o
    RDiܡ                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	m
Z
 d dlmZmZ d dlmZ d dlZd dlmZ d dlmZmZ d dlmZmZ d dlmZ d d	lmZmZ d d
lmZ d dlm Z m!Z! d dl"m#Z# d dl$m%Z% d dl&m'Z( d dl)m*Z*m+Z+ d dl,m-Z- d dl.m/Z/ d dl0m1Z1m2Z2 d dl3m4Z4 ddl5m6Z6 ddl7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z= ddl>m?Z? ddlm@Z@ ddl2mAZA eBdZCe8jDe8jEfe8jFfe8jGfe8jDe8jFe8jGe8jEfdZHe: ZIe9 ZJe< ZKe; ZLe= ZMe ZNG dd de4ZOdS )    N)OrderedDict)datetime	timedelta)unquote_plus)settings)authenticateget_user_model)check_passwordidentify_hasher)ObjectDoesNotExist)routertransaction)HttpRequest)
dateformattimezone)constant_time_compare)
make_aware)gettext_lazy)jwsjwt)JWException)
JWTExpired)errorsutils)RequestValidator   )FatalClientError)AbstractApplicationget_access_token_modelget_application_modelget_grant_modelget_id_token_modelget_refresh_token_model)get_scopes_backend)oauth2_settings)get_timezoneoauth2_provider)authorization_codepasswordclient_credentialsrefresh_tokenc                       sZ  e Zd Zi ddddddddddddd	dddd
dddddddddddddddddddddZdd Zdd Zdd Zdd Zdd Zd d! Z	 fd"d#Z
d$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; Zd<d= Zd>d? Zd@dA ZdBdC ZdDdE ZdFdG ZdHdI ZdJdK ZdLdM ZdNdO Z dPdQ Z!dRdS Z"ddUdVZ#ddWdXZ$dYdZ Z%d[d\ Z&d]d^ Z'd_d` Z(dadb Z)dcdd Z*e+dedf Z,dgdh Z-didj Z.dkdl Z/dmdn Z0dodp Z1dqdr Z2dsdt Z3dudv Z4dwdx Z5dydz Z6d{d| Z7d}d~ Z8dd Z9dd Z:dd Z;dd Z<dd Z=  Z>S )OAuth2Validatorsubopenidnameprofilefamily_name
given_namemiddle_namenicknamepreferred_usernamepicturewebsitegender	birthdatezoneinfolocale
updated_atemailemail_verifiedaddressphone)r>   phone_numberphone_number_verifiedc                 C   sJ   |j dd}|sdS |dd}t|dkrdS |\}}|dkr#dS |S )zx
        Return authentication string if request contains basic auth credentials,
        otherwise return None
        HTTP_AUTHORIZATIONN r      Basic)headersgetsplitlen)selfrequestauthrH   	auth_typeauth_string rO   Z/var/www/Datamplify/venv/lib/python3.10/site-packages/oauth2_provider/oauth2_validators.py_extract_basic_authb   s   z#OAuth2Validator._extract_basic_authc                 C   s2   z
t | t||W S  ty   t|| Y S w )zy
        Checks whether the provided client secret is valid.

        Supports both hashed and unhashed secrets.
        )r
   r	   
ValueErrorr   )rJ   provided_secretstored_secretrO   rO   rP   _check_secretu   s   zOAuth2Validator._check_secretc              	   C   sF  |  |}|s	dS z
|jptjpd}W n ty   d}Y nw zt|}W n ttj	fy9   t
d| Y dS w z||}W n tyR   t
d|| Y dS w ztt|dd\}}W n tyo   t
d Y dS w | ||du rt
d	|  dS |jj|krt
d
|  dS | ||jjst
d|  dS dS )z
        Authenticates with HTTP Basic Auth.

        Note: as stated in rfc:`2.3.1`, client_id and client_secret must be encoded with
        "application/x-www-form-urlencoded" encoding algorithm.
        Futf-8z0Failed basic auth: %r can't be decoded as base64z7Failed basic auth: %r can't be decoded as unicode by %r:r   z+Failed basic auth, Invalid base64 encoding.Nz0Failed basic auth: Application %s does not existz%Failed basic auth: wrong client id %sz)Failed basic auth: wrong client secret %sT)rQ   encodingr   DEFAULT_CHARSETAttributeErrorbase64	b64decode	TypeErrorbinasciiErrorlogdebugdecodeUnicodeDecodeErrormapr   rH   rR   _load_applicationclient	client_idrU   client_secret)rJ   rK   rN   rX   b64_decodedauth_string_decodedrg   rh   rO   rO   rP   _authenticate_basic_auth   sH   

z(OAuth2Validator._authenticate_basic_authc                 C   sx   z|j }t|ddpd}W n
 ty   Y dS w | ||du r)td|  dS | ||jjs:td|  dS dS )aA  
        Try to authenticate the client using client_id and client_secret
        parameters included in body.

        Remember that this method is NOT RECOMMENDED and SHOULD be limited to
        clients unable to directly utilize the HTTP Basic authentication scheme.
        See rfc:`2.3.1` for more details.
        rh    FNz0Failed body auth: Application %s does not existsz(Failed body auth: wrong client secret %sT)	rg   getattrrZ   re   r`   ra   rU   rf   rh   )rJ   rK   rg   rh   rO   rO   rP   _authenticate_request_body   s   
z*OAuth2Validator._authenticate_request_bodyc                 C   sv   t |ds	J dz|jptjj|d|_|j|s%td|  W dS |jW S  tjy:   td|  Y dS w )z
        If request.client was not set, load application instance for given
        client_id and store it in request.client
        rf   z,"request" instance has no "client" attribute)rg   z6Failed body authentication: Application %r is disabledNz9Failed body authentication: Application %r does not exist)	hasattrrf   ApplicationobjectsrG   	is_usabler`   ra   DoesNotExistrJ   rg   rK   rO   rO   rP   re      s   z!OAuth2Validator._load_applicationc                 C   sz   |d u rt ddtdfg}n)| rt ddtdfg}n||s.t ddtdfg}n
td t dg}||_|S )N)errorinvalid_tokenerror_descriptionzThe access token is invalid.zThe access token has expired.)ru   insufficient_scopez9The access token is valid but does not have enough scope.z5OAuth2 access token is invalid for an unknown reason.)r   _
is_expiredallow_scopesr`   warningoauth2_error)rJ   rK   access_tokenscopesru   rO   rO   rP   _set_oauth2_error_on_request   s2   




z,OAuth2Validator._set_oauth2_error_on_requestc                    s~   |  |rdS z|jr|jrW dS W n ty    td Y nw | |j| |jr2|jjt	j
kS t j|g|R i |S )ah  
        Determine if the client has to be authenticated

        This method is called only for grant types that supports client authentication:
            * Authorization code grant
            * Resource owner password grant
            * Refresh token grant

        If the request contains authorization headers, always authenticate the client
        no matter the grant type.

        If the request does not contain authorization headers, proceed with authentication
        only if the client is of type `Confidential`.

        If something goes wrong, call oauthlib implementation of the method.
        Tz*Client ID or client secret not provided...)rQ   rg   rh   rZ   r`   ra   re   rf   client_typer   CLIENT_CONFIDENTIALsuperclient_authentication_required)rJ   rK   argskwargs	__class__rO   rP   r      s   

z.OAuth2Validator.client_authentication_requiredc                 O   s   |  |}|s| |}|S )a  
        Check if client exists and is authenticating itself as in rfc:`3.2.1`

        First we try to authenticate with HTTP Basic Auth, and that is the PREFERRED
        authentication method.
        Whether this fails we support including the client credentials in the request-body,
        but this method is NOT RECOMMENDED and SHOULD be limited to clients unable to
        directly utilize the HTTP Basic authentication scheme.
        See rfc:`2.3.1` for more details
        )rk   rn   )rJ   rK   r   r   authenticatedrO   rO   rP   authenticate_client  s   

z#OAuth2Validator.authenticate_clientc                 O   s"   |  ||dur|jjtjkS dS )z
        If we are here, the client did not authenticate itself as in rfc:`3.2.1` and we can
        proceed only if the client exists and is not of type "Confidential".
        NF)re   rf   r   r   r   rJ   rg   rK   r   r   rO   rO   rP   authenticate_client_id/  s   z&OAuth2Validator.authenticate_client_idc                 O   s   t jj||d}||S )zc
        Ensure the redirect_uri is listed in the Application instance redirect_uris field
        codeapplication)Grantrq   rG   redirect_uri_allowed)rJ   rg   r   redirect_urirf   r   r   grantrO   rO   rP   confirm_redirect_uri8  s   
z$OAuth2Validator.confirm_redirect_uric                 O   s>   zt jj||jd}|  W dS  t jy   tj|dw )z
        Remove the temporary grant used to swap the authorization token.

        :raises: InvalidGrantError if the grant does not exist.
        r   )rK   N)r   rq   rG   rf   deleters   r   InvalidGrantError)rJ   rg   r   rK   r   r   r   rO   rO   rP   invalidate_authorization_code?  s   z-OAuth2Validator.invalidate_authorization_codec                 O   s   |  ||duS )z{
        Ensure an Application exists with given client_id.
        If it exists, it's assigned to request.client.
        N)re   r   rO   rO   rP   validate_client_idK  s   z"OAuth2Validator.validate_client_idc                 O   s   |j jS N)rf   default_redirect_urir   rO   rO   rP   get_default_redirect_uriR  s   z(OAuth2Validator.get_default_redirect_uric                 C   s$   t jjdi t j|d i\}}|S )a6  
        An optional layer to define where to store the profile in `UserModel` or a separate model.
        For example `UserOAuth`, where `user = models.OneToOneField(UserModel)` .

        The function is called after checking that username is in the content.

        Returns an UserModel instance;
        usernameNrO   )	UserModelrq   get_or_createUSERNAME_FIELD)rJ   contentuserry   rO   rO   rP   get_or_create_user_from_contentU  s    	z/OAuth2Validator.get_or_create_user_from_contentc                 C   s  d}|rdd |i}n#|r/|d d}|d d}t|d | }dd |di}ztj|d	|i|d
}	W n tjjyM   t	
d| Y dS w |	jtjjkrbt	
d |	j|	j dS z|	 }
W n tyw   t	
d Y dS w d|
v r|
d du rd|
v r| |
}nd}t ttjd }d|
v rt|
d }||kr|}n|}|
dd}tjrt|ttjd}tj j!||d||dd\}}|S dS dS )a  Use external introspection endpoint to "crack open" the token.
        :param introspection_url: introspection endpoint URL
        :param introspection_token: Bearer token
        :param introspection_credentials: Basic Auth credentials (id,secret)
        :return: :class:`models.AccessToken`

        Some RFC 7662 implementations (including this one) use a Bearer token while others use Basic
        Auth. Depending on the external AS's implementation, provide either the introspection_token
        or the introspection_credentials.

        If the resulting access_token identifies a username (e.g. Authorization Code grant), add
        that user to the UserModel. Also cache the access_token up until its expiry time or a
        configured maximum time.

        NAuthorizationz	Bearer {}r   rV   r      :zBasic {}token)datarF   z0Introspection: Failed POST to %r in token lookupzfIntrospection: Failed to get a valid response from authentication server. Status code: {}, Reason: {}.z/Introspection: Failed to parse response as jsonactiveTr   secondsexpscoperl   )r   )r   r   r   expires)r   defaults)"formatencoder[   	b64encoderb   requestspost
exceptionsRequestExceptionr`   	exceptionstatus_codehttprf   OKreasonjsonrR   r   r   nowr   r$   %RESOURCE_SERVER_TOKEN_CACHING_SECONDSutcfromtimestamprG   r   USE_TZr   r%   #AUTHENTICATION_SERVER_EXP_TIME_ZONEAccessTokenrq   update_or_create)rJ   r   introspection_urlintrospection_tokenintrospection_credentialsrF   rg   rh   
basic_authresponser   r   max_caching_timer   r   r~   _createdrO   rO   rP   %_get_token_from_authentication_servera  sl   



z5OAuth2Validator._get_token_from_authentication_serverc                 C   s   |sdS t j}t j}t j}| |}|r||s'|r'|s|r'| ||||}|rA||rA|j|_|j	|_	t
|j|_||_dS | ||| dS )zX
        When users try to access resources, check that provided token is valid
        FT)r$   !RESOURCE_SERVER_INTROSPECTION_URLRESOURCE_SERVER_AUTH_TOKEN)RESOURCE_SERVER_INTROSPECTION_CREDENTIALS_load_access_tokenis_validr   r   rf   r   listr   r~   r   )rJ   r   r   rK   r   r   r   r~   rO   rO   rP   validate_bearer_token  s&   
z%OAuth2Validator.validate_bearer_tokenc                 C   s.   t |d }tjddj|d S )NrV   r   r   )token_checksum)	hashlibsha256r   	hexdigestr   rq   select_relatedfilterfirst)rJ   r   r   rO   rO   rP   r     s   z"OAuth2Validator._load_access_tokenc                 O   st   z.t jj||d}| s,|jd|_|j|_|jr|j|_|j	r)t
|j	|_	W dS W dS  t jy9   Y dS w )Nr   rC   TF)r   rq   rG   rz   r   rH   r   r   nonceclaimsr   loadsrs   )rJ   rg   r   rf   rK   r   r   r   rO   rO   rP   validate_code  s   zOAuth2Validator.validate_codec                 O   s   |t v sJ |jjt |  S )zk
        Validate both grant_type is a valid string and grant_type is allowed for current workflow
        )GRANT_TYPE_MAPPINGrf   allows_grant_type)rJ   rg   
grant_typerf   rK   r   r   rO   rO   rP   validate_grant_type  s   z#OAuth2Validator.validate_grant_typec                 O   s   |dkr
| tjS |dkr| tjS |dkr| tjS |dkr(| tjS |dkr2| tjS |dkr<| tjS |dkrF| tjS dS )	z
        We currently do not support the Authorization Endpoint Response Types registry as in
        rfc:`8.4`, so validate the response_type only if it matches "code" or "token"
        r   r   id_tokenzid_token tokenzcode id_tokenz
code tokenzcode id_token tokenF)r   r   GRANT_AUTHORIZATION_CODEGRANT_IMPLICITGRANT_OPENID_HYBRID)rJ   rg   response_typerf   rK   r   r   rO   rO   rP   validate_response_type  s   z&OAuth2Validator.validate_response_typec                 O   s"   t  j||d}t|t|S )zZ
        Ensure required scopes are permitted (as specified in the settings file)
        r   rK   )r#   get_available_scopessetissubset)rJ   rg   r   rf   rK   r   r   available_scopesrO   rO   rP   validate_scopes
  s   zOAuth2Validator.validate_scopesc                 O   s   t  j|j|d}|S )Nr   )r#   get_default_scopesrf   )rJ   rg   rK   r   r   default_scopesrO   rO   rP   r     s   z"OAuth2Validator.get_default_scopesc                 O      |j |S r   )rf   r   )rJ   rg   r   rK   r   r   rO   rO   rP   validate_redirect_uri  s   z%OAuth2Validator.validate_redirect_uric                 C   s   t tjr
t|S tjS )z
        Enables or disables PKCE verification.

        Uses the setting PKCE_REQUIRED, which can be either a bool or a callable that
        receives the client id and returns a bool.
        )callabler$   PKCE_REQUIREDrt   rO   rO   rP   is_pkce_required  s   

z OAuth2Validator.is_pkce_requiredc                 C      t jj||jd}|jpd S Nr   )r   rq   rG   rf   code_challengerJ   r   rK   r   rO   rO   rP   get_code_challenge#     
z"OAuth2Validator.get_code_challengec                 C   r   r   )r   rq   rG   rf   code_challenge_methodr   rO   rO   rP   get_code_challenge_method'  r   z)OAuth2Validator.get_code_challenge_methodc                 O   s   |  || d S r   )_create_authorization_code)rJ   rg   r   rK   r   r   rO   rO   rP   save_authorization_code+  s   z'OAuth2Validator.save_authorization_codec                 C   s.   t jj|djddd }|rt|S g S )Nr   r   Tflat)r   rq   r   values_listr   r   scope_to_list)rJ   rg   r   r   rK   r   rO   rO   rP   get_authorization_code_scopes.  s   
z-OAuth2Validator.get_authorization_code_scopesc                 C   s   t jS )z;
        Checks if rotate refresh token is enabled
        )r$   ROTATE_REFRESH_TOKENrJ   rK   rO   rO   rP   rotate_refresh_token4  s   z$OAuth2Validator.rotate_refresh_tokenc                 O   sP   t jttd | j||g|R i |W  d   S 1 s!w   Y  dS )z
        Save access and refresh token.

        Override _save_bearer_token and not this function when adding custom logic
        for the storing of these token. This allows the transaction logic to be
        separate from the token handling.
        usingN)r   atomicr   db_for_writer   _save_bearer_token)rJ   r   rK   r   r   rO   rO   rP   save_bearer_token:  s   	$z!OAuth2Validator.save_bearer_tokenc           
   	   O   s  d|vrt dt t|dtjd }|jdkrd|_|dd}|rt	|dd}| 
|s_t|tr_|jr_tj j|jjd	}|j|_|d |_||_|d
 |_|j|_|  dS t|trtj j|jd	}||_tjj|d }	z|  W n tjtjfy   Y n
w t|dd nd}	|	s| j||||d}| |||| dS |	j|d
< tjj|	d j|d< |	j|d< dS | ||| dS )z
        Save access and refresh token.

        If refresh token is issued, remove or reuse old refresh token as in rfc:`6`.

        @see: https://rfc-editor.org/rfc/rfc6749.html#section-6
        r   z+Failed to renew access token: missing scope
expires_inr   r)   Nr*   refresh_token_instance)pkr~   )source_refresh_token)r~   ) r   r   r   r   rG   r$   ACCESS_TOKEN_EXPIRE_SECONDSr   r   rm   r  
isinstanceRefreshTokenr~   r   rq   select_for_updater  r   r   r   rf   r   saver  r   r   revokers   setattr_create_access_token_create_refresh_token)
rJ   r   rK   r   r   r   refresh_token_coder  r~   previous_access_tokenrO   rO   rP   r
  F  sx   	






z"OAuth2Validator._save_bearer_tokenNc              	   C   s@   | dd }|r| |}tjj|j|d ||d ||j|dS )Nr   r   r~   )r   r   r   r   r   r   r  )rG   _load_id_tokenr   rq   creater   rf   )rJ   r   rK   r   r  r   rO   rO   rP   r    s   
z$OAuth2Validator._create_access_tokenc                 C   sh   |st  ttjd }tjj|j|j	|d ||j
d|j|jp"d|jp&d|jp*dt|jp0i d
S )Nr   r   rC   rl   )
r   r   r   r   r   r   r   r   r   r   )r   r   r   r$   !AUTHORIZATION_CODE_EXPIRE_SECONDSr   rq   r  rf   r   r   joinr   r   r   r   r   dumpsr   )rJ   rK   r   r   rO   rO   rP   r     s   
z*OAuth2Validator._create_authorization_codec                 C   s.   |r|j }nt }tjj|j||j||dS )N)r   r   r   r~   token_family)r   uuiduuid4r  rq   r  r   rf   )rJ   rK   r  r~   previous_refresh_tokenr   rO   rO   rP   r    s   z%OAuth2Validator._create_refresh_tokenc              
      s   |dvrd}t td}||t  z jj|d  W dS  tyC    fdd| D D ]}ttdd |jj	|d q/Y dS w )z
        Revoke an access or refresh token.

        :param token: The token string.
        :param token_type_hint: access_token or refresh_token.
        :param request: The HTTP Request (oauthlib.common.Request)
        )r~   r*   Nr   c                    s   g | ]}| kr|qS rO   rO   ).0_t
token_typerO   rP   
<listcomp>  s    z0OAuth2Validator.revoke_token.<locals>.<listcomp>c                 S   s   |   S r   )r  )trO   rO   rP   <lambda>  s    z.OAuth2Validator.revoke_token.<locals>.<lambda>)
r   r  rG   rq   r  r   valuesr   rd   r   )rJ   r   token_type_hintrK   r   r   token_types
other_typerO   r'  rP   revoke_token  s   zOAuth2Validator.revoke_tokenc           	      O   s`   t  }|j|_|j|_t||jt|j |j	|_
t|||d}|dur.|jr.||_dS dS )zS
        Check username and password correspond to a valid and active User
        )r   r(   NTF)r   uripathhttp_methodmethodrm   updatedictdecoded_bodyrF   METAr   	is_activer   )	rJ   r   r(   rf   rK   r   r   http_requesturO   rO   rP   validate_user  s   zOAuth2Validator.validate_userc                 O   sB   |j }|jsz
tjj|jdjW S  tjy   g  Y S w |jjS )N)source_refresh_token_id)	r  access_token_idr   rq   rG   r  r   rs   r~   )rJ   r*   rK   r   r   rtrO   rO   rP   get_original_scopes  s   z#OAuth2Validator.get_original_scopesc           	      O   s   t jj|dd }|sdS |jdur=|jt tt	j
d kr=t	jr;|jr;t jj|jd}| D ]}|  q4dS |j|_|j|_||_|j|kS )z
        Check refresh_token exists and refers to the right client.
        Also attach User instance to the request object
        r$  r~   FNr   )r   )r  rq   r   r   r   revokedr   r   r   r$   "REFRESH_TOKEN_GRACE_PERIOD_SECONDSREFRESH_TOKEN_REUSE_PROTECTIONr   allr  r   r   r*   r  r   )	rJ   r*   rf   rK   r   r   r?  rt_token_family
related_rtrO   rO   rP   validate_refresh_token  s   


z&OAuth2Validator.validate_refresh_tokenc                 O   s0   |j pd|j}tjj|j||||jd}|S )NrC   )r   r   r   jtir   )r   r  r   IDTokenrq   r  r   rf   )rJ   rH  rK   r   r   r   r   r   rO   rO   rP   _save_id_token(  s   zOAuth2Validator._save_id_tokenc                 C   s   t t| jjdkS )Nr   )rI   inspect	signatureget_additional_claims
parameters)clsrO   rO   rP   *_get_additional_claims_is_request_agnostic4  s   z:OAuth2Validator._get_additional_claims_is_request_agnosticc                 C      |  |||S r   )get_id_token)rJ   r   token_handlerrK   rO   rO   rP   get_jwt_bearer_token8     z$OAuth2Validator.get_jwt_bearer_tokenc                 C   sP   |   rddd i}ndt|jji}|   r|  }n| |}|| |S )Nr,   c                 S   s   t | jjS r   )strr   r  )rrO   rO   rP   r+  =  s    z0OAuth2Validator.get_claim_dict.<locals>.<lambda>)rP  rV  r   r  rM  r5  )rJ   rK   r   addrO   rO   rP   get_claim_dict;  s   


zOAuth2Validator.get_claim_dictc                 C   s(   dg}|   r|t| | 7 }|S )Nr,   )rP  r   rY  keys)rJ   rK   r   rO   rO   rP   get_discovery_claimsJ  s   z$OAuth2Validator.get_discovery_claimsc                 C   sT   |  |}i }| D ]\}}| jr| j||jv r't|r#||n|||< q|S r   )rY  itemsoidc_claim_scoperG   r   r   )rJ   r   rS  rK   r   r   kvrO   rO   rP   get_oidc_claimsP  s   
zOAuth2Validator.get_oidc_claimsc              
   C   sn   |  |||}t ttjd }|jdi | |tt	
|dtt	
|jjdtt d ||fS )a4  
        Get the claims to put in the ID Token.

        These claims are in addition to the claims automatically added by
        ``oauthlib`` - aud, iat, nonce, at_hash, c_hash.

        This function adds in iss, exp and auth_time, plus any claims added from
        calling ``get_oidc_claims()``
        r   U)issr   	auth_timerH  NrO   )r`  r   r   r   r$   ID_TOKEN_EXPIRE_SECONDSr5  get_oidc_issuer_endpointintr   r   r   
last_loginrV  r!  r"  )rJ   r   rS  rK   r   expiration_timerO   rO   rP   get_id_token_dictionary[  s   

	z'OAuth2Validator.get_id_token_dictionaryc                 C   s
   t |S r   )r$   oidc_issuerr  rO   rO   rP   re  t  s   
z(OAuth2Validator.get_oidc_issuer_endpointc           	      C   s   |  |||\}}|jd	i | d|vr|jr|j|d< d|jjd}|jjtjkr3|jj |d< t	j
tj|tdtj|tdd}||jj tjttd | |d ||}W d    n1 shw   Y  ||_||_| S )
Nr   JWT)typalgkid)default)headerr   r  rH  rO   )ri  r5  r   rf   	algorithmr   RS256_ALGORITHMjwk_key
thumbprintr   rk  r   r  rV  make_signed_tokenr   r  r   r	  rI  rJ  r~   r   	serialize)	rJ   r   r   rS  rK   r   rh  rp  	jwt_tokenrO   rO   rP   finalize_id_tokenw  s(   
z!OAuth2Validator.finalize_id_tokenc                 C   rQ  r   )validate_id_token)rJ   r   r   rK   rO   rO   rP   validate_jwt_bearer_token  rU  z)OAuth2Validator.validate_jwt_bearer_tokenc                 C   sH   |sdS |  |}|sdS ||sdS |j|_|j|_||_||_dS )z[
        When users try to access resources, check that provided id_token is valid
        FT)r  r{   r   rf   r   r   r~   )rJ   r   r   rK   r   rO   rO   rP   ry    s   

z!OAuth2Validator.validate_id_tokenc              
   C   s^   |  |}|s	d S ztj||d}t|j}tjj|d dW S  t	t
tjfy.   Y d S w )N)keyr   rH  )rH  )_get_key_for_tokenr   rk  r   r   r   rI  rq   rG   r   r   rs   )rJ   r   r{  rw  r   rO   rO   rP   r    s   
zOAuth2Validator._load_id_tokenc                 C   sP   t  }|| t|jd d}d|vrdS | |d }|r&|jS dS )z
        Peek at the unvalidated token to discover who it was issued for
        and then use that to load that application and its key.
        payloadrV   audN)	r   JWSdeserializer   r   rq   rb   _get_client_by_audiencers  )rJ   r   unverified_tokenr   r   rO   rO   rP   r|    s   
z"OAuth2Validator._get_key_for_tokenc                 C   s"   t |tr|g}tjj|d S )z
        Load a client by the aud claim in a JWT.
        aud may be multi-valued, if your provider makes it so.
        This function is separate to allow further customization.
        )client_id__in)r  rV  rp   rq   r   r   )rJ   audiencerO   rO   rP   r    s   
z'OAuth2Validator._get_client_by_audiencec                 C   s   dS )NTrO   )rJ   id_token_hintr   r   rK   rO   rO   rP   validate_user_match  s   z#OAuth2Validator.validate_user_matchc                 C   s(   t jj|djddd }|r|S dS )aj  Extracts nonce from saved authorization code.
        If present in the Authentication Request, Authorization
        Servers MUST include a nonce Claim in the ID Token with the
        Claim Value being the nonce value sent in the Authentication
        Request. Authorization Servers SHOULD perform no other
        processing on nonce values used. The nonce value is a
        case-sensitive string.
        Only code param should be sufficient to retrieve grant code from
        any storage you are using. However, `client_id` and `redirect_uri`
        have been validated and can be used also.
        :param client_id: Unicode client identifier
        :param code: Unicode authorization code grant
        :param redirect_uri: Unicode absolute URI
        :return: Unicode nonce
        Method is used by:
            - Authorization Token Grant Dispatcher
        r   r   Tr   N)r   rq   r   r   r   )rJ   rg   r   r   rK   r   rO   rO   rP   get_authorization_code_nonce  s   z,OAuth2Validator.get_authorization_code_noncec                 C   s   |  |jd|S )zw
        Generates and saves a new JWT for this request, and returns it as the
        current user's claims.

        N)r`  r~   r  rO   rO   rP   get_userinfo_claims  s   z#OAuth2Validator.get_userinfo_claimsc                 C   s   i S r   rO   r  rO   rO   rP   rM    s   z%OAuth2Validator.get_additional_claimsc                 O   r   )aV  Indicate if the given origin is allowed to access the token endpoint
        via Cross-Origin Resource Sharing (CORS).  CORS is used by browser-based
        clients, such as Single-Page Applications, to perform the Authorization
        Code Grant.

        Verifies if request's origin is within Application's allowed origins list.
        )rf   origin_allowed)rJ   rg   originrK   r   r   rO   rO   rP   is_origin_allowed  s   z!OAuth2Validator.is_origin_allowedr   )?__name__
__module____qualname__r]  rQ   rU   rk   rn   re   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r
  r  r   r  r0  r<  r@  rG  rJ  classmethodrP  rT  rY  r[  r`  ri  re  rx  rz  ry  r  r|  r  r  r  r  rM  r  __classcell__rO   rO   r   rP   r+   E   s    	
. !	T 
g


r+   )Pr[   r^   r   http.clientr   rK  r   loggingr!  collectionsr   r   r   urllib.parser   r   django.confr   django.contrib.authr   r   django.contrib.auth.hashersr	   r
   django.core.exceptionsr   	django.dbr   r   django.httpr   django.utilsr   r   django.utils.cryptor   django.utils.timezoner   django.utils.translationr   ry   jwcryptor   r   jwcrypto.commonr   jwcrypto.jwtr   oauthlib.oauth2.rfc6749r   r   oauthlib.openidr   r   r   modelsr   r   r   r    r!   r"   r   r#   r$   r%   	getLoggerr`   r   r   GRANT_PASSWORDGRANT_CLIENT_CREDENTIALSr   rp   r   rI  r   r  r   r+   rO   rO   rO   rP   <module>   sf     
