Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.

Commit 24784ce

Browse files
fix: Restrict deactivated enterprise user access (#910)
1 parent db88c2d commit 24784ce

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

graphql_api/tests/test_owner.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,27 @@ def test_fetch_owner_on_unauthenticated_enteprise_guest_access(self):
785785
assert e.message == UnauthorizedGuestAccess.message
786786
assert e.extensions["code"] == UnauthorizedGuestAccess.code
787787

788+
@override_settings(IS_ENTERPRISE=True, GUEST_ACCESS=False)
789+
def test_fetch_owner_on_unauthenticated_enteprise_guest_access_not_activated(self):
790+
user = OwnerFactory(username="sample-user")
791+
owner = OwnerFactory(username="sample-owner", plan_activated_users=[123, 456])
792+
user.organizations = [owner.ownerid]
793+
user.save()
794+
owner.save()
795+
query = """{
796+
owner(username: "%s") {
797+
isCurrentUserActivated
798+
}
799+
}
800+
""" % (owner.username)
801+
802+
try:
803+
self.gql_request(query, owner=user)
804+
805+
except GraphQLError as e:
806+
assert e.message == UnauthorizedGuestAccess.message
807+
assert e.extensions["code"] == UnauthorizedGuestAccess.code
808+
788809
def test_fetch_current_user_is_okta_authenticated(self):
789810
account = AccountFactory()
790811
owner = OwnerFactory(username="sample-owner", service="github", account=account)
@@ -843,7 +864,7 @@ def test_fetch_current_user_is_not_okta_authenticated_no_account(self):
843864

844865
@patch("shared.rate_limits.determine_entity_redis_key")
845866
@patch("shared.rate_limits.determine_if_entity_is_rate_limited")
846-
@override_settings(IS_ENTERPRISE=True, GUEST_ACCESS=False)
867+
@override_settings(IS_ENTERPRISE=True, GUEST_ACCESS=True)
847868
def test_fetch_is_github_rate_limited(
848869
self, mock_determine_rate_limit, mock_determine_redis_key
849870
):

graphql_api/types/query/query.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional
1+
from typing import Any, Optional
22

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

2222

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

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

4141

4242
@query_bindable.field("owner")
43-
def resolve_owner(_, info, username):
43+
async def resolve_owner(
44+
_: Any, info: GraphQLResolveInfo, username: str
45+
) -> Optional[Owner]:
4446
configure_sentry_scope(query_name(info))
4547

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

53-
return get_owner(service, username)
55+
target = await get_owner(service, username)
56+
if user.ownerid not in target.plan_activated_users:
57+
raise UnauthorizedGuestAccess()
58+
59+
return await get_owner(service, username)
5460

5561

5662
@query_bindable.field("config")
57-
def resolve_config(_, info):
63+
def resolve_config(_: Any, info: GraphQLResolveInfo) -> object:
5864
configure_sentry_scope(query_name(info))
5965

6066
# we have to return something here just to allow access to the child resolvers

0 commit comments

Comments
 (0)