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(' ')) create_id_token_hook = settings.import_hook('OIDC_IDTOKEN_CREATE_HOOK') id_token_dic = create_id_token_hook( 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': self._encode_id_token(id_token_dic, token.client), }
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. create_id_token_hook = settings.import_hook('OIDC_IDTOKEN_CREATE_HOOK') if self.token.id_token: id_token_dic = create_id_token_hook( 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': self._encode_id_token(id_token_dic, self.token.client), } return dic
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) create_id_token_hook = settings.import_hook('OIDC_IDTOKEN_CREATE_HOOK') if self.code.is_authentication: id_token_dic = create_id_token_hook( 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': self._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 = {} 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 create_id_token_hook = settings.import_hook( 'OIDC_IDTOKEN_CREATE_HOOK') id_token_dic = create_id_token_hook(**kwargs) encode_id_token = settings.import_hook( 'OIDC_IDTOKEN_ENCODE_HOOK') # 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 _encode_id_token(self, *args): return settings.import_hook('OIDC_IDTOKEN_ENCODE_HOOK')(*args)