Skip to content
Merged
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
1 change: 1 addition & 0 deletions src/sentry/auth/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ def _handle_membership(
if invite_helper.invite_approved:
rpc_om = invite_helper.accept_invite(user)
assert rpc_om
self._set_linked_flag(rpc_om)
return user, rpc_om

# It's possible the user has an _invite request_ that hasn't been approved yet,
Expand Down
2 changes: 2 additions & 0 deletions tests/sentry/auth/test_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ def test_associate_pending_invite(self) -> None:
)

assert assigned_member.id == member.id
assert getattr(assigned_member.flags, "sso:linked")
assert not getattr(assigned_member.flags, "sso:invalid")

def test_demo_user_can_be_added_new_user_when_demo_org(self) -> None:
# Force demo user behavior, and mark org as demo org
Expand Down
49 changes: 49 additions & 0 deletions tests/sentry/web/frontend/test_auth_organization_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,55 @@ def test_flow_as_authenticated_user_with_invite_joining(self) -> None:
assert not getattr(test_member.flags, "sso:invalid")
assert not getattr(test_member.flags, "member-limit:restricted")

def test_flow_as_anonymous_with_pending_invite(self) -> None:
"""New SSO user with a pending org invite should land once, with sso:linked."""
auth_provider = AuthProvider.objects.create(
organization_id=self.organization.id, provider="dummy"
)
invite = self.create_member(
email="invited@example.com",
organization=self.organization,
token="abcdef",
)

# Invite accept stores these before the user is bounced into SSO.
self.session["invite_token"] = invite.token
self.session["invite_member_id"] = invite.id
self.session["invite_organization_id"] = invite.organization_id
self.save_session()

resp = self.client.post(self.path, {"init": True})

assert resp.status_code == 200
assert PLACEHOLDER_TEMPLATE in resp.content.decode("utf-8")

path = reverse("sentry-auth-sso")

resp = self.client.post(path, {"email": "invited@example.com"})

self.assertTemplateUsed(resp, "sentry/auth-confirm-identity.html")
assert resp.status_code == 200

frontend_events = {"event_name": "Sign Up", "event_label": "dummy"}
marketing_query = urlencode({"frontend_events": json.dumps(frontend_events)})

resp = self.client.post(path, {"op": "newuser"}, follow=True)
assert resp.redirect_chain == [
(reverse("sentry-login") + f"?{marketing_query}", 302),
("/organizations/foo/issues/", 302),
]

auth_identity = AuthIdentity.objects.get(auth_provider=auth_provider)
user = auth_identity.user
assert user.email == "invited@example.com"

with assume_test_silo_mode(SiloMode.CELL):
member = OrganizationMember.objects.get(organization=self.organization, user_id=user.id)

assert member.id == invite.id
assert getattr(member.flags, "sso:linked")
assert not getattr(member.flags, "sso:invalid")

@override_settings(SENTRY_SINGLE_ORGANIZATION=True)
@with_feature({"organizations:create": False})
def test_basic_auth_flow_as_not_invited_user(self) -> None:
Expand Down
Loading