Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Restrict deactivated enterprise user access #910

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion graphql_api/tests/test_owner.py
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,27 @@ def test_fetch_owner_on_unauthenticated_enteprise_guest_access(self):
assert e.message == UnauthorizedGuestAccess.message
assert e.extensions["code"] == UnauthorizedGuestAccess.code

@override_settings(IS_ENTERPRISE=True, GUEST_ACCESS=False)
def test_fetch_owner_on_unauthenticated_enteprise_guest_access_not_activated(self):
user = OwnerFactory(username="sample-user")
owner = OwnerFactory(username="sample-owner", plan_activated_users=[123, 456])
user.organizations = [owner.ownerid]
user.save()
owner.save()
query = """{
owner(username: "%s") {
isCurrentUserActivated
}
}
""" % (owner.username)

try:
self.gql_request(query, owner=user)

except GraphQLError as e:
assert e.message == UnauthorizedGuestAccess.message
assert e.extensions["code"] == UnauthorizedGuestAccess.code

def test_fetch_current_user_is_okta_authenticated(self):
account = AccountFactory()
owner = OwnerFactory(username="sample-owner", service="github", account=account)
Expand Down Expand Up @@ -843,7 +864,7 @@ def test_fetch_current_user_is_not_okta_authenticated_no_account(self):

@patch("shared.rate_limits.determine_entity_redis_key")
@patch("shared.rate_limits.determine_if_entity_is_rate_limited")
@override_settings(IS_ENTERPRISE=True, GUEST_ACCESS=False)
@override_settings(IS_ENTERPRISE=True, GUEST_ACCESS=True)
def test_fetch_is_github_rate_limited(
self, mock_determine_rate_limit, mock_determine_redis_key
):
Expand Down
18 changes: 12 additions & 6 deletions graphql_api/types/query/query.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import Any, Optional

from ariadne import ObjectType
from django.conf import settings
Expand All @@ -20,7 +20,7 @@ def query_name(info: GraphQLResolveInfo) -> Optional[str]:
return info.operation.name.value


def configure_sentry_scope(query_name: str):
def configure_sentry_scope(query_name: Optional[str]) -> None:
# this sets the Sentry transaction name to the GraphQL query name which
# should make it easier to search/filter transactions
# we're configuring this here since it's the main entrypoint into GraphQL resolvers
Expand All @@ -33,14 +33,16 @@ def configure_sentry_scope(query_name: str):

@query_bindable.field("me")
@sync_to_async
def resolve_me(_, info) -> Optional[Owner]:
def resolve_me(_: Any, info: GraphQLResolveInfo) -> Optional[Owner]:
configure_sentry_scope(query_name(info))
# will be `None` for anonymous users or users w/ no linked owners
return info.context["request"].current_owner


@query_bindable.field("owner")
def resolve_owner(_, info, username):
async def resolve_owner(
_: Any, info: GraphQLResolveInfo, username: str
) -> Optional[Owner]:
configure_sentry_scope(query_name(info))

service = info.context["service"]
Expand All @@ -50,11 +52,15 @@ def resolve_owner(_, info, username):
if not user or not user.is_authenticated:
raise UnauthorizedGuestAccess()

return get_owner(service, username)
target = await get_owner(service, username)
if user.ownerid not in target.plan_activated_users:
raise UnauthorizedGuestAccess()
suejung-sentry marked this conversation as resolved.
Show resolved Hide resolved

return await get_owner(service, username)


@query_bindable.field("config")
def resolve_config(_, info):
def resolve_config(_: Any, info: GraphQLResolveInfo) -> object:
configure_sentry_scope(query_name(info))

# we have to return something here just to allow access to the child resolvers
Expand Down
Loading