Skip to content

Commit

Permalink
fix(oauth): Show error if user has no org (#80141)
Browse files Browse the repository at this point in the history
This flow is org scoped oauth so the user entering this flow must be a
member of at least one organization. Before this would break the UI but
now we show a proper error.

<img width="580" alt="Screenshot 2024-11-01 at 11 23 14 AM"
src="https://github.com/user-attachments/assets/572f2e99-4aff-4f48-906a-062f49917ccf">
  • Loading branch information
sentaur-athena authored Nov 11, 2024
1 parent 482dbd6 commit deedb74
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 3 deletions.
8 changes: 8 additions & 0 deletions src/sentry/web/frontend/oauth_authorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,14 @@ def get(self, request: HttpRequest, **kwargs) -> HttpResponseBase:

if application.requires_org_level_access:
organization_options = user_service.get_organizations(user_id=request.user.id)
if not organization_options:
return self.respond(
"sentry/oauth-error.html",
{
"error": "This authorization flow is only available for users who are members of an organization."
},
status=400,
)
else:
# If application is not org level we should not show organizations to choose from at all
organization_options = []
Expand Down
22 changes: 19 additions & 3 deletions tests/sentry/web/frontend/test_oauth_authorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,15 +356,31 @@ def path(self):

def setUp(self):
super().setUp()
self.owner = self.create_user(email="admin@test.com")
self.create_member(user=self.owner, organization=self.organization, role="owner")
self.application = ApiApplication.objects.create(
owner=self.user,
redirect_uris="https://example.com",
requires_org_level_access=True,
scopes=["org:read", "project:read"],
)

def test_no_orgs(self):
# If the user has no organizations, this oauth flow should not be possible
user = self.create_user(email="user1@test.com")
self.login_as(user)
resp = self.client.get(
f"{self.path}?response_type=code&client_id={self.application.client_id}&scope=org%3write&state=foo"
)
assert resp.status_code == 400
self.assertTemplateUsed("sentry/oauth-error.html")
assert (
resp.context["error"]
== "This authorization flow is only available for users who are members of an organization."
)

def test_rich_params(self):
self.login_as(self.user)
self.login_as(self.owner)

# Putting scope in the query string to show that this will be overridden by the scopes that are stored on the application model
resp = self.client.get(
Expand All @@ -379,7 +395,7 @@ def test_rich_params(self):
self.path, {"op": "approve", "selected_organization_id": self.organization.id}
)

grant = ApiGrant.objects.get(user=self.user)
grant = ApiGrant.objects.get(user=self.owner)
assert grant.redirect_uri == self.application.get_default_redirect_uri()
assert grant.application == self.application
assert grant.get_scopes() == ["org:read", "project:read"]
Expand All @@ -394,4 +410,4 @@ def test_rich_params(self):
f"state=foo&code={grant.code}"
)

assert not ApiToken.objects.filter(user=self.user).exists()
assert not ApiToken.objects.filter(user=self.owner).exists()

0 comments on commit deedb74

Please sign in to comment.