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
5 changes: 4 additions & 1 deletion src/sentry/replays/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from django.http import HttpRequest

from sentry.auth.principal import is_owned_by_acting_user
from sentry.auth.superuser import superuser_has_permission
from sentry.models.options.organization_option import OrganizationOption
from sentry.models.organizationmember import OrganizationMember
Expand Down Expand Up @@ -85,6 +86,8 @@ def granular_permissions_turned_off(organization: Organization) -> bool:
def get_org_member(organization: Organization, request: HttpRequest) -> OrganizationMember | None:
"""Get the OrganizationMember for the request user, or None if not a member."""
try:
return OrganizationMember.objects.get(organization=organization, user_id=request.user.id)
return OrganizationMember.objects.get(
is_owned_by_acting_user(request.user), organization=organization
)
except OrganizationMember.DoesNotExist:
return None
2 changes: 1 addition & 1 deletion tests/sentry/auth/test_principal.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ def _is_request_user_type_check(node: ast.AST) -> bool:


# Lower these as callers move off. Exact, so the baseline can't drift back up.
REQUEST_USER_ID_BASELINE = 134
REQUEST_USER_ID_BASELINE = 133
REQUEST_USER_TYPE_CHECK_BASELINE = 29
REQUEST_USER_ALLOWLIST_BASELINE = 22

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from rest_framework.response import Response

from sentry.models.apikey import ApiKey
from sentry.models.apitoken import ApiToken
from sentry.models.options.organization_option import OrganizationOption
from sentry.models.orgauthtoken import OrgAuthToken
Expand Down Expand Up @@ -445,3 +448,37 @@ def test_sentry_app_with_event_read_empty_allowlist_has_access(self) -> None:
)
# SentryApp with event:read bypasses member allowlist
assert response.status_code == 200

def _api_key_get_replays(self) -> Response:
with assume_test_silo_mode(SiloMode.CONTROL):
key = ApiKey.objects.create(
organization_id=self.organization.id, scope_list=["org:read", "event:read"]
)
url = f"/api/0/organizations/{self.organization.slug}/replays/"
return self.client.get(url, HTTP_AUTHORIZATION=self.create_basic_auth_header(key.key))

def test_api_key_does_not_get_a_pending_invites_access(self) -> None:
with self.feature("organizations:session-replay"):
self._enable_granular_permissions()
OrganizationMemberReplayAccess.objects.create(
organizationmember=self.member_with_access
)
# An org requiring 2FA turns non-compliant members back into pending invites,
# keeping their allowlist entry.
self.member_with_access.remove_user()
self.member_with_access.save()

response = self._api_key_get_replays()
assert response.status_code == 403

def test_api_key_with_several_pending_invites_denied(self) -> None:
with self.feature("organizations:session-replay"):
self._enable_granular_permissions()
OrganizationMemberReplayAccess.objects.create(
organizationmember=self.member_with_access
)
self.create_member(organization=self.organization, email="a@example.com")
self.create_member(organization=self.organization, email="b@example.com")

response = self._api_key_get_replays()
assert response.status_code == 403
Loading