1818from sentry .auth .services .access .service import access_service
1919from sentry .auth .services .auth import AuthenticatedToken , RpcAuthState , RpcMemberSsoState
2020from sentry .auth .staff import is_active_staff
21- from sentry .auth .superuser import get_superuser_scopes , is_active_superuser
21+ from sentry .auth .superuser import (
22+ Superuser ,
23+ get_superuser_access_expiry ,
24+ get_superuser_scopes ,
25+ is_active_superuser ,
26+ resolve_superuser_access ,
27+ )
2228from sentry .auth .system import is_system_auth
2329from sentry .constants import ObjectStatus
2430from sentry .data_secrecy .logic import should_allow_superuser_access
2834from sentry .models .organizationmemberteam import OrganizationMemberTeam
2935from sentry .models .project import Project
3036from sentry .models .team import Team , TeamStatus
31- from sentry .organizations .services .organization import RpcTeamMember , RpcUserOrganizationContext
37+ from sentry .organizations .services .organization import (
38+ RpcTeamMember ,
39+ RpcUserOrganizationContext ,
40+ organization_service ,
41+ )
3242from sentry .organizations .services .organization .serial import summarize_member
3343from sentry .roles import organization_roles
3444from sentry .roles .manager import OrganizationRole , TeamRole
3545from sentry .seer .agent_token import is_agent_auth
3646from sentry .sentry_apps .models .sentry_app import SentryApp
47+ from sentry .types .request import _HttpRequestWithUser
48+ from sentry .types .superuser import SuperuserAccess
3749from sentry .users .models .user import User
3850from sentry .users .services .user import RpcUser
51+ from sentry .users .services .user .service import user_service
3952from sentry .utils import metrics
53+ from sentry .viewer_context import set_viewer_context_superuser
4054
4155__all__ = (
4256 "from_user" ,
@@ -992,6 +1006,28 @@ def __init__(self) -> None:
9921006 )
9931007
9941008
1009+ def _propagate_superuser_access (
1010+ request : _HttpRequestWithUser ,
1011+ org_context : RpcUserOrganizationContext ,
1012+ su : Superuser | None ,
1013+ ) -> None :
1014+ # Members use their normal callback permissions and user flags; adding this
1015+ # claim would instead force read-only access and a five-minute VC lifetime.
1016+ if org_context .member is not None :
1017+ return
1018+ if request .auth is not None or su is None or not su .is_active :
1019+ return
1020+ if su .requires_org_auth (org_context .organization ):
1021+ return
1022+ expires_at = get_superuser_access_expiry (su , org_context .organization .id )
1023+ if expires_at is not None :
1024+ set_viewer_context_superuser (
1025+ user_id = request .user .id ,
1026+ organization_id = org_context .organization .id ,
1027+ superuser = SuperuserAccess (expires_at = expires_at ),
1028+ )
1029+
1030+
9951031def from_request_org_and_scopes (
9961032 * ,
9971033 request : HttpRequest ,
@@ -1002,6 +1038,10 @@ def from_request_org_and_scopes(
10021038 Note that `scopes` is usually None because request.auth is not set at `get_authorization_header`
10031039 when the request is made from the frontend using cookies
10041040 """
1041+ if isinstance (request .auth , AuthenticatedToken ) and request .auth .superuser is not None :
1042+ if rpc_user_org_context is None :
1043+ return DEFAULT
1044+ return from_superuser_access (request .auth , rpc_user_org_context )
10051045 if is_agent_auth (request .auth ):
10061046 if rpc_user_org_context is None :
10071047 return DEFAULT
@@ -1027,11 +1067,12 @@ def from_request_org_and_scopes(
10271067
10281068 if is_active_superuser (request ):
10291069 su = getattr (request , "superuser" , None )
1030- if (
1031- su
1032- and su .requires_org_auth (rpc_user_org_context .organization )
1033- and rpc_user_org_context .member is None
1034- ):
1070+ if su is None and request .auth is None :
1071+ su = Superuser (request )
1072+ requires_org_auth = su is not None and su .requires_org_auth (
1073+ rpc_user_org_context .organization
1074+ )
1075+ if requires_org_auth and rpc_user_org_context .member is None :
10351076 setattr (request , "_superuser_needs_org_auth" , rpc_user_org_context .organization .slug )
10361077
10371078 member = rpc_user_org_context .member
@@ -1043,12 +1084,14 @@ def from_request_org_and_scopes(
10431084 org_member = member ,
10441085 )
10451086
1046- superuser_scopes = get_superuser_scopes (auth_state , request . user , rpc_user_org_context )
1087+ superuser_scopes = get_superuser_scopes (auth_state , rpc_user_org_context )
10471088 if scopes :
10481089 superuser_scopes = superuser_scopes .union (set (scopes ))
10491090 if member and member .scopes :
10501091 superuser_scopes = superuser_scopes .union (set (member .scopes ))
10511092
1093+ _propagate_superuser_access (request , rpc_user_org_context , su )
1094+
10521095 return ApiBackedOrganizationGlobalAccess (
10531096 rpc_user_organization_context = rpc_user_org_context ,
10541097 auth_state = auth_state ,
@@ -1114,7 +1157,9 @@ def from_user_and_rpc_user_org_context(
11141157def from_request (
11151158 request : Request , organization : Organization | None = None , scopes : Iterable [str ] | None = None
11161159) -> Access :
1117- if is_agent_auth (request .auth ):
1160+ if isinstance (request .auth , AuthenticatedToken ) and (
1161+ is_agent_auth (request .auth ) or request .auth .superuser is not None
1162+ ):
11181163 if organization is None :
11191164 return DEFAULT
11201165 return from_auth (request .auth , organization )
@@ -1154,7 +1199,7 @@ def from_request(
11541199 )
11551200 sso_state = auth_state .sso_state
11561201
1157- superuser_scopes = get_superuser_scopes (auth_state , request . user , organization )
1202+ superuser_scopes = get_superuser_scopes (auth_state , organization )
11581203 if scopes :
11591204 superuser_scopes = superuser_scopes .union (set (scopes ))
11601205 if member and (member_scopes := member .get_scopes ()):
@@ -1285,6 +1330,11 @@ def from_rpc_member(
12851330
12861331
12871332def from_auth (auth : AuthenticatedToken , organization : Organization ) -> Access :
1333+ if isinstance (auth , AuthenticatedToken ) and auth .superuser is not None :
1334+ context = organization_service .get_organization_by_id (
1335+ id = organization .id , user_id = auth .user_id
1336+ )
1337+ return from_superuser_access (auth , context ) if context is not None else DEFAULT
12881338 if is_system_auth (auth ):
12891339 return SystemAccess ()
12901340 if is_agent_auth (auth ):
@@ -1312,6 +1362,8 @@ def from_auth(auth: AuthenticatedToken, organization: Organization) -> Access:
13121362def from_rpc_auth (
13131363 auth : AuthenticatedToken , rpc_user_org_context : RpcUserOrganizationContext
13141364) -> Access :
1365+ if isinstance (auth , AuthenticatedToken ) and auth .superuser is not None :
1366+ return from_superuser_access (auth , rpc_user_org_context )
13151367 if is_system_auth (auth ):
13161368 return SystemAccess ()
13171369 if is_agent_auth (auth ):
@@ -1356,4 +1408,30 @@ def from_agent_auth(
13561408 return from_rpc_member (rpc_user_org_context , scopes = auth .get_scopes ())
13571409
13581410
1411+ def from_superuser_access (
1412+ auth : AuthenticatedToken , rpc_user_org_context : RpcUserOrganizationContext
1413+ ) -> Access :
1414+ if (
1415+ auth .superuser is None
1416+ or auth .organization_id != rpc_user_org_context .organization .id
1417+ or auth .user_id != rpc_user_org_context .user_id
1418+ ):
1419+ return DEFAULT
1420+ users = user_service .get_many (filter = {"user_ids" : [auth .user_id ]})
1421+ user = users [0 ] if users else None
1422+ if user is None :
1423+ return DEFAULT
1424+ delegated = resolve_superuser_access (auth .superuser , user , rpc_user_org_context )
1425+ if delegated is None :
1426+ return DEFAULT
1427+ scopes , _ = delegated
1428+ return ApiBackedOrganizationGlobalAccess (
1429+ rpc_user_organization_context = rpc_user_org_context ,
1430+ auth_state = RpcAuthState (
1431+ sso_state = RpcMemberSsoState (is_valid = True , is_required = False ), permissions = []
1432+ ),
1433+ scopes = scopes & set (auth .get_scopes ()),
1434+ )
1435+
1436+
13591437DEFAULT = NoAccess ()
0 commit comments