def save_bearer_token(self, token, request, *args, **kwargs): if 'scope' not in token: raise FatalClientError( 'Failed to renew access token: missing scope') if request.grant_type == 'client_credentials': request.user = None # TODO: check out a more reliable way to communicate expire time to oauthlib token['expires_in'] = oauth2_settings.ACCESS_TOKEN_EXPIRE_SECONDS refresh_token_code = token.get('refresh_token', None) if not refresh_token_code: return if self.rotate_refresh_token(request): refresh_token = RefreshToken( user=request.user, token=refresh_token_code, application=request.client, expires=datetime.now() + timedelta( seconds=oauth2_settings.REFRESH_TOKEN_EXPIRE_SECONDS), scope=token['scope'], ) refresh_token.save() token[ 'refresh_token_expires_in'] = oauth2_settings.REFRESH_TOKEN_EXPIRE_SECONDS
def validate_authorization_request(self, request): require_approval = request.GET.get( "approval_prompt", oauth2_settings.REQUEST_APPROVAL_PROMPT) if require_approval != 'force' and request.GET.get( 'scope') != 'profile': raise FatalClientError( 'Combnination of require_approval and scope values not allowed.' ) return super().validate_authorization_request(request)
def _create_access_token(self, expires, request, token, source_refresh_token=None): if not getattr(request, 'organizers', None) and not getattr(source_refresh_token, 'access_token', None) and token["scope"] != 'profile': raise FatalClientError('No organizers selected.') if token['scope'] != 'profile': if hasattr(request, 'organizers'): orgs = list(request.organizers.all()) else: orgs = list(source_refresh_token.access_token.organizers.all()) access_token = super()._create_access_token(expires, request, token, source_refresh_token=None) if token['scope'] != 'profile': access_token.organizers.add(*orgs) return access_token
def save_authorization_code(self, client_id, code, request, *args, **kwargs): if not getattr(request, 'organizers', None) and request.scopes != ['profile']: raise FatalClientError('No organizers selected.') expires = timezone.now() + timedelta( seconds=oauth2_settings.AUTHORIZATION_CODE_EXPIRE_SECONDS) g = Grant(application=request.client, user=request.user, code=code["code"], expires=expires, redirect_uri=request.redirect_uri, scope=" ".join(request.scopes)) g.save() if request.scopes != ['profile']: g.organizers.add(*request.organizers.all())
def verify_access_token(key): try: token = AccessToken.objects.get(token=key) if not token.is_valid(): raise OAuthToolkitError('AccessToken is not valid.') if token.is_expired(): raise OAuthToolkitError('AccessToken has expired.') except AccessToken.DoesNotExist: raise FatalClientError("AccessToken not found at all.") return token
def verify_access_token(request, key): try: token = None if request: token = get_token_object_from_session(request.session) if not token or token.key != key: token = AccessToken.objects.get(token=key) if not token.is_valid(): raise OAuthToolkitError('AccessToken is not valid.') if token.is_expired(): raise OAuthToolkitError('AccessToken has expired.') except AccessToken.DoesNotExist: raise FatalClientError("AccessToken not found at all.") except BaseException: return None return token
def validate_authorization_request(self, request): """ A wrapper method that calls validate_authorization_request on `server_class` instance. :param request: The current django.http.HttpRequest object """ try: uri, http_method, body, headers = self._extract_params(request) headers["tatl.scopes"] = request.user.get_all_permissions( ) if request.user else [] scopes, credentials = self.server.validate_authorization_request( uri, http_method=http_method, body=body, headers=headers) return scopes, credentials except oauth2.FatalClientError as error: raise FatalClientError(error=error) except oauth2.OAuth2Error as error: raise OAuthToolkitError(error=error)
def test_error_response_without_redirect(self): """Test that errors are rendered without a 'url' context variable.""" base_error = FakeOAuthLibError(status_code=405) error = FatalClientError(error=base_error) response = self.view.error_response(error) self.assertNotIn('url', response.context_data)
def save_bearer_token(self, token, request, *args, **kwargs): """ Save access and refresh token, If refresh token is issued, remove or reuse old refresh token as in rfc:`6` @see: https://tools.ietf.org/html/draft-ietf-oauth-v2-31#page-43 """ if "scope" not in token: raise FatalClientError( "Failed to renew access token: missing scope") expires = timezone.now() + timedelta( seconds=oauth2_settings.ACCESS_TOKEN_EXPIRE_SECONDS) if request.grant_type == "client_credentials": request.user = None # This comes from OAuthLib: # https://github.com/idan/oauthlib/blob/1.0.3/oauthlib/oauth2/rfc6749/tokens.py#L267 # Its value is either a new random code; or if we are reusing # refresh tokens, then it is the same value that the request passed in # (stored in `request.refresh_token`) refresh_token_code = token.get("refresh_token", None) if refresh_token_code: # an instance of `RefreshToken` that matches the old refresh code. # Set on the request in `validate_refresh_token` refresh_token_instance = getattr(request, "refresh_token_instance", None) # If we are to reuse tokens, and we can: do so if not self.rotate_refresh_token(request) and \ isinstance(refresh_token_instance, RefreshToken) and \ refresh_token_instance.access_token: access_token = AccessToken.objects.select_for_update().get( pk=refresh_token_instance.access_token.pk) auth_cache = caches['auth'] auth_cache.delete(access_token.token) access_token.user = request.user access_token.scope = ' '.join(request.user.scopes) access_token.expires = expires access_token.token = token["access_token"] access_token.application = request.client access_token.save() cached_auth = { 'uid': access_token.user.id, 'scopes': access_token.user.scopes, 'token': access_token.token, 'reused': 'true', } auth_cache.set(access_token.token, cached_auth, oauth2_settings.ACCESS_TOKEN_EXPIRE_SECONDS) # else create fresh with access & refresh tokens else: # revoke existing tokens if possible to allow reuse of grant if isinstance(refresh_token_instance, RefreshToken): try: auth_cache = caches['auth'] refresh_token_key = 'auth:access_token:{access_token}:refresh_token'.format( access_token=refresh_token_instance.access_token. token) access_token_key = 'auth:access_token:{access_token}'.format( access_token=refresh_token_instance.access_token. token) auth_cache.delete_many( [access_token_key, refresh_token_key]) refresh_token_instance.revoke() except (AccessToken.DoesNotExist, RefreshToken.DoesNotExist): pass else: setattr(request, "refresh_token_instance", None) # If the refresh token has already been used to create an # access token (ie it's within the grace period), return that # access token # TODO rewrite to celery access_token = self._create_access_token( expires, request, token, ) refresh_token = RefreshToken(user=request.user, token=refresh_token_code, application=request.client, access_token=access_token) refresh_token.save() auth_cache = caches['auth'] key = 'auth:access_token:{access_token}:refresh_token'.format( access_token=access_token.token) auth_cache.set(key, access_token.token, oauth2_settings.REFRESH_TOKEN_EXPIRE_SECONDS) # No refresh token should be created, just access token else: self._create_access_token(expires, request, token) # TODO: check out a more reliable way to communicate expire time to oauthlib token["expires_in"] = oauth2_settings.ACCESS_TOKEN_EXPIRE_SECONDS