def determine_access(self, request: Request, organization): from sentry.api.base import logger if request.user and request.user.is_authenticated and request.auth: request.access = access.from_request( request, organization, scopes=request.auth.get_scopes()) elif request.auth: request.access = access.from_auth(request.auth, organization) else: request.access = access.from_request(request, organization) extra = { "organization_id": organization.id, "user_id": request.user.id } if auth.is_user_signed_request(request): # if the user comes from a signed request # we let them pass if sso is enabled logger.info( "access.signed-sso-passthrough", extra=extra, ) elif request.user.is_authenticated: # session auth needs to confirm various permissions if self.needs_sso(request, organization): logger.info( "access.must-sso", extra=extra, ) raise SsoRequired(organization) if self.is_not_2fa_compliant(request, organization): logger.info( "access.not-2fa-compliant", extra=extra, ) if request.user.is_superuser and organization.id != Superuser.org_id: raise SuperuserRequired() raise TwoFactorRequired() if self.is_member_disabled_from_limit(request, organization): logger.info( "access.member-disabled-from-limit", extra=extra, ) raise MemberDisabledOverLimit(organization)
def dispatch(self, request: Request, *args, **kwargs) -> Response: """ Identical to rest framework's dispatch except we add the ability to convert arguments (for common URL params). """ with sentry_sdk.start_span(op="base.dispatch.setup", description=type(self).__name__): self.args = args self.kwargs = kwargs request = self.initialize_request(request, *args, **kwargs) self.load_json_body(request) self.request = request self.headers = self.default_response_headers # deprecate? # Tags that will ultimately flow into the metrics backend at the end of # the request (happens via middleware/stats.py). request._metric_tags = {} start_time = time.time() origin = request.META.get("HTTP_ORIGIN", "null") # A "null" value should be treated as no Origin for us. # See RFC6454 for more information on this behavior. if origin == "null": origin = None try: with sentry_sdk.start_span(op="base.dispatch.request", description=type(self).__name__): if origin: if request.auth: allowed_origins = request.auth.get_allowed_origins() else: allowed_origins = None if not is_valid_origin(origin, allowed=allowed_origins): response = Response(f"Invalid origin: {origin}", status=400) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response self.initial(request, *args, **kwargs) # Get the appropriate handler method if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) (args, kwargs) = self.convert_args(request, *args, **kwargs) self.args = args self.kwargs = kwargs else: handler = self.http_method_not_allowed if getattr(request, "access", None) is None: # setup default access request.access = access.from_request(request) with sentry_sdk.start_span( op="base.dispatch.execute", description=f"{type(self).__name__}.{handler.__name__}", ): response = handler(request, *args, **kwargs) except Exception as exc: response = self.handle_exception(request, exc) if origin: self.add_cors_headers(request, response) self.response = self.finalize_response(request, response, *args, **kwargs) if settings.SENTRY_API_RESPONSE_DELAY: duration = time.time() - start_time if duration < (settings.SENTRY_API_RESPONSE_DELAY / 1000.0): with sentry_sdk.start_span( op="base.dispatch.sleep", description=type(self).__name__, ) as span: span.set_data("SENTRY_API_RESPONSE_DELAY", settings.SENTRY_API_RESPONSE_DELAY) time.sleep(settings.SENTRY_API_RESPONSE_DELAY / 1000.0 - duration) return self.response