def create_access_token_response_dic(self): # See https://tools.ietf.org/html/rfc6749#section-4.3 token = create_token( self.user, self.client, self.params['scope'].split(' ')) id_token_dic = create_id_token( token=token, user=self.user, aud=self.client.client_id, nonce='self.code.nonce', at_hash=token.at_hash, request=self.request, scope=token.scope, ) token.id_token = id_token_dic token.save() return { 'access_token': token.access_token, 'refresh_token': token.refresh_token, 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'token_type': 'bearer', 'id_token': encode_id_token(id_token_dic, token.client), }
def _create_token(self, extra_scope=None): """ Generate a valid token. """ if extra_scope is None: extra_scope = [] scope = ['openid', 'email'] + extra_scope token = create_token( user=self.user, client=self.client, scope=scope) id_token_dic = create_id_token( token=token, user=self.user, aud=self.client.client_id, nonce=FAKE_NONCE, scope=scope, ) token.id_token = id_token_dic token.save() return token
def create_access_token_response_dic(self): # See https://tools.ietf.org/html/rfc6749#section-4.3 token = create_token(self.user, self.client, self.params['scope'].split(' ')) id_token_dic = create_id_token( token=token, user=self.user, aud=self.client.client_id, nonce='self.code.nonce', at_hash=token.at_hash, request=self.request, scope=token.scope, ) token.id_token = id_token_dic token.save() return { 'access_token': token.access_token, 'refresh_token': token.refresh_token, 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'token_type': 'bearer', 'id_token': encode_id_token(id_token_dic, token.client), }
def create_code_response_dic(self): token = create_token(user=self.code.user, client=self.code.client, scope=self.code.scope) if self.code.is_authentication: id_token_dic = create_id_token( user=self.code.user, aud=self.client.client_id, nonce=self.code.nonce, at_hash=token.at_hash, request=self.request, scope=self.params['scope'], ) else: id_token_dic = {} token.id_token = id_token_dic # Store the token. token.save() # We don't need to store the code anymore. self.code.delete() dic = { 'access_token': token.access_token, 'refresh_token': token.refresh_token, 'token_type': 'bearer', 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'id_token': encode_id_token(id_token_dic, token.client), } return dic
def create_refresh_response_dic(self): token = create_token(user=self.token.user, client=self.token.client, scope=self.token.scope) # If the Token has an id_token it's an Authentication request. if self.token.id_token: id_token_dic = create_id_token( user=self.token.user, aud=self.client.client_id, nonce=None, at_hash=token.at_hash, request=self.request, scope=self.params['scope'], ) else: id_token_dic = {} token.id_token = id_token_dic # Store the token. token.save() # Forget the old token. self.token.delete() dic = { 'access_token': token.access_token, 'refresh_token': token.refresh_token, 'token_type': 'bearer', 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'id_token': encode_id_token(id_token_dic, self.token.client), } return dic
def create_refresh_response_dic(self): token = create_token( user=self.token.user, client=self.token.client, scope=self.token.scope) # If the Token has an id_token it's an Authentication request. if self.token.id_token: id_token_dic = create_id_token( user=self.token.user, aud=self.client.client_id, nonce=None, at_hash=token.at_hash, request=self.request, scope=self.params['scope'], ) else: id_token_dic = {} token.id_token = id_token_dic # Store the token. token.save() # Forget the old token. self.token.delete() dic = { 'access_token': token.access_token, 'refresh_token': token.refresh_token, 'token_type': 'bearer', 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'id_token': encode_id_token(id_token_dic, self.token.client), } return dic
def create_refresh_response_dic(self): # See https://tools.ietf.org/html/rfc6749#section-6 scope_param = self.params['scope'] scope = (scope_param.split(' ') if scope_param else self.token.scope) unauthorized_scopes = set(scope) - set(self.token.scope) if unauthorized_scopes: raise TokenError('invalid_scope') token = create_token(user=None, client=self.token.client, scope=scope) id_token_dic = {} token.id_token = id_token_dic # Store the token. token.save() # Forget the old token. self.token.delete() dic = { 'access_token': token.access_token, 'refresh_token': token.refresh_token, 'token_type': 'bearer', 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'scope': self.token.client._scope, } return dic
def create_code_response_dic(self): token = create_token( user=self.code.user, client=self.code.client, scope=self.code.scope) if self.code.is_authentication: id_token_dic = create_id_token( user=self.code.user, aud=self.client.client_id, nonce=self.code.nonce, at_hash=token.at_hash, request=self.request, scope=self.params['scope'], ) else: id_token_dic = {} token.id_token = id_token_dic # Store the token. token.save() # We don't need to store the code anymore. self.code.delete() dic = { 'access_token': token.access_token, 'refresh_token': token.refresh_token, 'token_type': 'bearer', 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'id_token': encode_id_token(id_token_dic, token.client), } return dic
def test_redirects_when_aud_is_list(self): """Check with 'aud' containing a list of str.""" query_params = { 'post_logout_redirect_uri': self.LOGOUT_URL, } token = create_token(self.user, self.oidc_client, []) id_token_dic = create_id_token( token=token, user=self.user, aud=self.oidc_client.client_id) id_token_dic['aud'] = [id_token_dic['aud']] id_token = encode_id_token(id_token_dic, self.oidc_client) query_params['id_token_hint'] = id_token response = self.client.get(self.url, query_params) self.assertRedirects( response, self.LOGOUT_URL, fetch_redirect_response=False)
def create_client_credentials_response_dic(self): # See https://tools.ietf.org/html/rfc6749#section-4.4.3 token_scopes = self.validate_requested_scopes() token = create_token(user=None, client=self.client, scope=token_scopes) token.save() return { 'access_token': token.access_token, 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'token_type': 'bearer', 'scope': ' '.join(token.scope), }
def _create_token(self, extra_scope=[]): """ Generate a valid token. """ id_token_dic = create_id_token(self.user, self.client.client_id, FAKE_NONCE) token = create_token( user=self.user, client=self.client, id_token_dic=id_token_dic, scope=['openid', 'email'] + extra_scope) token.save() return token
def create_oidc_token(oidc_client, admin_user, request): scope = ['openid', 'email'] token = create_token(user=admin_user, client=oidc_client, scope=scope) id_token_dic = create_id_token(token=token, user=admin_user, aud=oidc_client.client_id, nonce='abcdefghijk', scope=scope, request=request) token.id_token = id_token_dic token.save() return token
def _create_token(self, user, client, request): scope = ['openid', 'email'] token = create_token(user=user, client=client, scope=scope) id_token_dic = create_id_token(token=token, user=user, aud=client.client_id, nonce='abcdefghijk', scope=scope, request=request) token.id_token = id_token_dic token.save() return token
def create_client_credentials_response_dic(self): # See https://tools.ietf.org/html/rfc6749#section-4.4.3 token = create_token( user=None, client=self.client, scope=self.client.scope) token.save() return { 'access_token': token.access_token, 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'token_type': 'bearer', 'scope': self.client._scope, }
def create_refresh_response_dic(self): # See https://tools.ietf.org/html/rfc6749#section-6 scope_param = self.params['scope'] scope = (scope_param.split(' ') if scope_param else self.token.scope) unauthorized_scopes = set(scope) - set(self.token.scope) if unauthorized_scopes: raise TokenError('invalid_scope') token = create_token(user=self.token.user, client=self.token.client, scope=scope, ae=self.token.ae, rid=self.token.rid) # If the Token has an id_token it's an Authentication request. if self.token.id_token: id_token_dic = create_id_token(user=self.token.user, aud=self.client.client_id, token=token, nonce=None, at_hash=token.at_hash, request=self.request, scope=token.scope, acr=self.token.id_token.get('acr'), amr=self.token.id_token.get('amr')) else: id_token_dic = {} token.id_token = id_token_dic # Store the token. token.save() # Forget the old token. self.token.delete() dic = { 'access_token': token.access_token, 'refresh_token': token.refresh_token, 'token_type': 'bearer', 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'id_token': encode_id_token(id_token_dic, self.token.client), } return dic
def create_refresh_response_dic(self): # See https://tools.ietf.org/html/rfc6749#section-6 scope_param = self.params['scope'] scope = (scope_param.split(' ') if scope_param else self.token.scope) unauthorized_scopes = set(scope) - set(self.token.scope) if unauthorized_scopes: raise TokenError('invalid_scope') token = create_token( user=self.token.user, client=self.token.client, scope=scope) # If the Token has an id_token it's an Authentication request. if self.token.id_token: id_token_dic = create_id_token( user=self.token.user, aud=self.client.client_id, token=token, nonce=None, at_hash=token.at_hash, request=self.request, scope=token.scope, ) else: id_token_dic = {} token.id_token = id_token_dic # Store the token. token.save() # Forget the old token. self.token.delete() dic = { 'access_token': token.access_token, 'refresh_token': token.refresh_token, 'token_type': 'bearer', 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'id_token': encode_id_token(id_token_dic, self.token.client), } return dic
def test_create_id_token(self): start_time = int(time.time()) login_timestamp = start_time - 1234 self.user.last_login = timestamp_to_datetime(login_timestamp) client = create_fake_client("code") token = create_token(self.user, client, []) id_token_data = create_id_token(token=token, user=self.user, aud='test-aud') iat = id_token_data['iat'] self.assertEqual(type(iat), int) self.assertGreaterEqual(iat, start_time) self.assertLessEqual(iat - start_time, 5) # Can't take more than 5 s self.assertEqual(id_token_data, { 'aud': 'test-aud', 'auth_time': login_timestamp, 'exp': iat + 600, 'iat': iat, 'iss': 'http://localhost:8000/openid', 'sub': str(self.user.id), })
def _create_token(self, extra_scope=[]): """ Generate a valid token. """ scope = ['openid', 'email'] + extra_scope id_token_dic = create_id_token( user=self.user, aud=self.client.client_id, nonce=FAKE_NONCE, scope=scope, ) token = create_token( user=self.user, client=self.client, id_token_dic=id_token_dic, scope=scope) token.save() return token
def test_redirects_when_aud_is_str(self): query_params = { 'post_logout_redirect_uri': self.LOGOUT_URL, } response = self.client.get(self.url, query_params) # With no id_token the OP MUST NOT redirect to the requested # redirect_uri. self.assertRedirects( response, settings.get('OIDC_LOGIN_URL'), fetch_redirect_response=False) token = create_token(self.user, self.oidc_client, []) id_token_dic = create_id_token( token=token, user=self.user, aud=self.oidc_client.client_id) id_token = encode_id_token(id_token_dic, self.oidc_client) query_params['id_token_hint'] = id_token response = self.client.get(self.url, query_params) self.assertRedirects( response, self.LOGOUT_URL, fetch_redirect_response=False)
def _create_token(self, extra_scope=None): """ Generate a valid token. """ if extra_scope is None: extra_scope = [] scope = ['openid', 'email'] + extra_scope token = create_token(user=self.user, client=self.client, scope=scope) id_token_dic = create_id_token( token=token, user=self.user, aud=self.client.client_id, nonce=FAKE_NONCE, scope=scope, ) token.id_token = id_token_dic token.save() return token
def create_code_response_dic(self): # See https://tools.ietf.org/html/rfc6749#section-4.1 token = create_token(user=self.code.user, client=self.code.client, scope=self.code.scope, ae=self.code.ae, rid=self.code.rid) if self.code.is_authentication: id_token_dic = create_id_token( user=self.code.user, aud=self.client.client_id, token=token, nonce=self.code.nonce, at_hash=token.at_hash, request=self.request, scope=token.scope, ) else: id_token_dic = {} token.id_token = id_token_dic # Store the token. token.save() # We don't need to store the code anymore. self.code.delete() dic = { 'access_token': token.access_token, 'refresh_token': token.refresh_token, 'token_type': 'bearer', 'expires_in': settings.get('OIDC_TOKEN_EXPIRE'), 'id_token': encode_id_token(id_token_dic, token.client), } return dic
def create_response_uri(self): uri = urlsplit(self.params['redirect_uri']) query_params = parse_qs(uri.query) query_fragment = parse_qs(uri.fragment) try: if self.grant_type in ['authorization_code', 'hybrid']: code = create_code( user=self.request.user, client=self.client, scope=self.params['scope'], nonce=self.params['nonce'], is_authentication=self.is_authentication, code_challenge=self.params['code_challenge'], code_challenge_method=self.params['code_challenge_method']) code.save() if self.grant_type == 'authorization_code': query_params['code'] = code.code query_params['state'] = self.params['state'] if self.params['state'] else '' elif self.grant_type in ['implicit', 'hybrid']: token = create_token( user=self.request.user, client=self.client, scope=self.params['scope']) # Check if response_type must include access_token in the response. if self.params['response_type'] in ['id_token token', 'token', 'code token', 'code id_token token']: query_fragment['access_token'] = token.access_token # We don't need id_token if it's an OAuth2 request. if self.is_authentication: kwargs = { 'user': self.request.user, 'aud': self.client.client_id, 'nonce': self.params['nonce'], 'request': self.request, 'scope': self.params['scope'], } # Include at_hash when access_token is being returned. if 'access_token' in query_fragment: kwargs['at_hash'] = token.at_hash id_token_dic = create_id_token(**kwargs) # Check if response_type must include id_token in the response. if self.params['response_type'] in ['id_token', 'id_token token', 'code id_token', 'code id_token token']: query_fragment['id_token'] = encode_id_token(id_token_dic, self.client) else: id_token_dic = {} # Store the token. token.id_token = id_token_dic token.save() # Code parameter must be present if it's Hybrid Flow. if self.grant_type == 'hybrid': query_fragment['code'] = code.code query_fragment['token_type'] = 'bearer' query_fragment['expires_in'] = settings.get('OIDC_TOKEN_EXPIRE') query_fragment['state'] = self.params['state'] if self.params['state'] else '' except Exception as error: logger.debug('[Authorize] Error when trying to create response uri: %s', error) raise AuthorizeError(self.params['redirect_uri'], 'server_error', self.grant_type) uri = uri._replace(query=urlencode(query_params, doseq=True)) uri = uri._replace(fragment=urlencode(query_fragment, doseq=True)) return urlunsplit(uri)
def create_response_uri(self): uri = urlsplit(self.params.redirect_uri) query_params = parse_qs(uri.query) query_fragment = parse_qs(uri.fragment) try: if self.grant_type == 'authorization_code': code = create_code( user=self.request.user, client=self.client, scope=self.params.scope, nonce=self.params.nonce, is_authentication=self.is_authentication, code_challenge=self.params.code_challenge, code_challenge_method=self.params.code_challenge_method) code.save() query_params['code'] = code.code query_params['state'] = self.params.state if self.params.state else '' elif self.grant_type == 'implicit': token = create_token( user=self.request.user, client=self.client, scope=self.params.scope) # Check if response_type is an OpenID request with value 'id_token token' # or it's an OAuth2 Implicit Flow request. if self.params.response_type in ['id_token token', 'token']: query_fragment['access_token'] = token.access_token # We don't need id_token if it's an OAuth2 request. if self.is_authentication: kwargs = { "user": self.request.user, "aud": self.client.client_id, "nonce": self.params.nonce, "request": self.request } # Include at_hash when access_token is being returned. if 'access_token' in query_fragment: kwargs['at_hash'] = token.at_hash id_token_dic = create_id_token(**kwargs) query_fragment['id_token'] = encode_id_token(id_token_dic, self.client) token.id_token = id_token_dic else: id_token_dic = {} # Store the token. token.id_token = id_token_dic token.save() query_fragment['token_type'] = 'bearer' # TODO: Create setting 'OIDC_TOKEN_EXPIRE'. query_fragment['expires_in'] = 60 * 10 query_fragment['state'] = self.params.state if self.params.state else '' except Exception as error: logger.debug('[Authorize] Error when trying to create response uri: %s', error) raise AuthorizeError( self.params.redirect_uri, 'server_error', self.grant_type) uri = uri._replace(query=urlencode(query_params, doseq=True)) uri = uri._replace(fragment=urlencode(query_fragment, doseq=True)) return urlunsplit(uri)
def create_response_uri(self): uri = urlsplit(self.params['redirect_uri']) query_params = parse_qs(uri.query) query_fragment = {} try: if self.grant_type in ['authorization_code', 'hybrid']: code = create_code( user=self.request.user, client=self.client, scope=self.params['scope'], nonce=self.params['nonce'], is_authentication=self.is_authentication, code_challenge=self.params['code_challenge'], code_challenge_method=self.params['code_challenge_method']) code.save() if self.grant_type == 'authorization_code': query_params['code'] = code.code query_params['state'] = self.params['state'] if self.params[ 'state'] else '' elif self.grant_type in ['implicit', 'hybrid']: token = create_token(user=self.request.user, client=self.client, scope=self.params['scope']) # Check if response_type must include access_token in the response. if (self.params['response_type'] in [ 'id_token token', 'token', 'code token', 'code id_token token' ]): query_fragment['access_token'] = token.access_token # We don't need id_token if it's an OAuth2 request. if self.is_authentication: kwargs = { 'token': token, 'user': self.request.user, 'aud': self.client.client_id, 'nonce': self.params['nonce'], 'request': self.request, 'scope': self.params['scope'], } # Include at_hash when access_token is being returned. if 'access_token' in query_fragment: kwargs['at_hash'] = token.at_hash id_token_dic = create_id_token(**kwargs) # Check if response_type must include id_token in the response. if self.params['response_type'] in [ 'id_token', 'id_token token', 'code id_token', 'code id_token token' ]: query_fragment['id_token'] = encode_id_token( id_token_dic, self.client) else: id_token_dic = {} # Store the token. token.id_token = id_token_dic token.save() # Code parameter must be present if it's Hybrid Flow. if self.grant_type == 'hybrid': query_fragment['code'] = code.code query_fragment['token_type'] = 'bearer' query_fragment['expires_in'] = settings.get( 'OIDC_TOKEN_EXPIRE') query_fragment['state'] = self.params['state'] if self.params[ 'state'] else '' if settings.get('OIDC_SESSION_MANAGEMENT_ENABLE'): # Generate client origin URI from the redirect_uri param. redirect_uri_parsed = urlsplit(self.params['redirect_uri']) client_origin = '{0}://{1}'.format(redirect_uri_parsed.scheme, redirect_uri_parsed.netloc) # Create random salt. salt = md5(uuid4().hex.encode()).hexdigest() # The generation of suitable Session State values is based # on a salted cryptographic hash of Client ID, origin URL, # and OP browser state. session_state = '{client_id} {origin} {browser_state} {salt}'.format( client_id=self.client.client_id, origin=client_origin, browser_state=get_browser_state_or_default(self.request), salt=salt) session_state = sha256( session_state.encode('utf-8')).hexdigest() session_state += '.' + salt if self.grant_type == 'authorization_code': query_params['session_state'] = session_state elif self.grant_type in ['implicit', 'hybrid']: query_fragment['session_state'] = session_state except Exception as error: logger.exception( '[Authorize] Error when trying to create response uri: %s', error) raise AuthorizeError(self.params['redirect_uri'], 'server_error', self.grant_type) uri = uri._replace(query=urlencode(query_params, doseq=True), fragment=uri.fragment + urlencode(query_fragment, doseq=True)) return urlunsplit(uri)
def create_response_uri(self): uri = urlsplit(self.params['redirect_uri']) query_params = parse_qs(uri.query) query_fragment = parse_qs(uri.fragment) try: if self.grant_type in ['authorization_code', 'hybrid']: code = create_code( user=self.request.user, client=self.client, scope=self.params['scope'], nonce=self.params['nonce'], is_authentication=self.is_authentication, code_challenge=self.params['code_challenge'], code_challenge_method=self.params['code_challenge_method']) code.save() if self.grant_type == 'authorization_code': query_params['code'] = code.code query_params['state'] = self.params['state'] if self.params['state'] else '' elif self.grant_type in ['implicit', 'hybrid']: token = create_token( user=self.request.user, client=self.client, scope=self.params['scope']) # Check if response_type must include access_token in the response. if self.params['response_type'] in ['id_token token', 'token', 'code token', 'code id_token token']: query_fragment['access_token'] = token.access_token # We don't need id_token if it's an OAuth2 request. if self.is_authentication: kwargs = { 'user': self.request.user, 'aud': self.client.client_id, 'nonce': self.params['nonce'], 'request': self.request, 'scope': self.params['scope'], } # Include at_hash when access_token is being returned. if 'access_token' in query_fragment: kwargs['at_hash'] = token.at_hash id_token_dic = create_id_token(**kwargs) # Check if response_type must include id_token in the response. if self.params['response_type'] in ['id_token', 'id_token token', 'code id_token', 'code id_token token']: query_fragment['id_token'] = encode_id_token(id_token_dic, self.client) else: id_token_dic = {} # Store the token. token.id_token = id_token_dic token.save() # Code parameter must be present if it's Hybrid Flow. if self.grant_type == 'hybrid': query_fragment['code'] = code.code query_fragment['token_type'] = 'bearer' query_fragment['expires_in'] = settings.get('OIDC_TOKEN_EXPIRE') query_fragment['state'] = self.params['state'] if self.params['state'] else '' if settings.get('OIDC_SESSION_MANAGEMENT_ENABLE'): # Generate client origin URI from the redirect_uri param. redirect_uri_parsed = urlsplit(self.params['redirect_uri']) client_origin = '{0}://{1}'.format(redirect_uri_parsed.scheme, redirect_uri_parsed.netloc) # Create random salt. salt = md5(uuid4().hex.encode()).hexdigest() # The generation of suitable Session State values is based # on a salted cryptographic hash of Client ID, origin URL, # and OP browser state. session_state = '{client_id} {origin} {browser_state} {salt}'.format( client_id=self.client.client_id, origin=client_origin, browser_state=self.request.COOKIES['op_browser_state'], salt=salt) session_state = sha256(session_state.encode('utf-8')).hexdigest() session_state += '.' + salt if self.grant_type == 'authorization_code': query_params['session_state'] = session_state elif self.grant_type in ['implicit', 'hybrid']: query_fragment['session_state'] = session_state except Exception as error: logger.debug('[Authorize] Error when trying to create response uri: %s', error) raise AuthorizeError(self.params['redirect_uri'], 'server_error', self.grant_type) uri = uri._replace(query=urlencode(query_params, doseq=True)) uri = uri._replace(fragment=urlencode(query_fragment, doseq=True)) return urlunsplit(uri)