o
    iT                     @   s  d 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mZmZmZmZmZmZmZmZmZ ddlZddlZddlmZ ddlmZ ddlmZ ddlmZ dd	lm Z  dd
l!m"Z" ej#dk rxddl	m$Z$ ddl%m&Z& nddl'm$Z$ ddl	m&Z& e(e)Z*edZ+e&dZ,G dd deZ-G dd de.Z/G dd de.Z0G dd deZ1G dd dej2Z3G dd de.Z4de$e,e+f de$e,e+f fddZ5G d d! d!Z6dS )"zSSO login base dependency.    N)TracebackType)AnyClassVarDictListLiteralOptionalType	TypedDictTypeVarUnionoverload)WebApplicationClient)HTTPException)Request)RedirectResponse)get_pkce_challenge_pair)generate_random_state)   
   )Callable)	ParamSpecTPc                   @   s*   e Zd ZU dZeed< eed< eed< dS )DiscoveryDocumentzDiscovery document.authorization_endpointtoken_endpointuserinfo_endpointN)__name__
__module____qualname____doc__str__annotations__ r$   r$   K/home/app/Keep/.python/lib/python3.10/site-packages/fastapi_sso/sso/base.pyr   $   s
   
 r   c                   @      e Zd ZdZdS )UnsetStateWarningz$Warning about unset state parameter.Nr   r   r    r!   r$   r$   r$   r%   r'   ,       r'   c                   @   r&   )ReusedOauthClientWarningz+Warning about reused oauth client instance.Nr(   r$   r$   r$   r%   r*   0   r)   r*   c                   @   r&   )SSOLoginErrorzRaised when any login-related error ocurrs.

    Such as when user is not verified or if there was an attempt for fake login.
    Nr(   r$   r$   r$   r%   r+   4   r)   r+   c                   @   s   e Zd ZU dZdZee ed< dZee	j
 ed< dZee ed< dZee ed< dZee ed< dZee ed< dZee ed	< dS )
OpenIDzOClass (schema) to represent information got from sso provider in a common form.Nidemail
first_name	last_namedisplay_namepictureprovider)r   r   r    r!   r-   r   r"   r#   r.   pydanticZEmailStrr/   r0   r1   r2   r3   r$   r$   r$   r%   r,   ;   s   
 r,   c                   @   r&   )SecurityWarningz&Raised when insecure usage is detectedNr(   r$   r$   r$   r%   r5   G   r)   r5   funcreturnc                    s"   dt jdt jdtf fdd}|S )Nargskwargsr7   c                     sH   | r	t | d ts | i |S | d jstjdtdd  | i |S )Nr   zPlease make sure you are using SSO provider in an async context (using 'async with provider:'). See https://github.com/tomasvotava/fastapi-sso/issues/186 for more information.   )category
stacklevel)
isinstanceSSOBase	_in_stackwarningswarnr5   )r8   r9   r6   r$   r%   wrapperL   s   
z'requires_async_context.<locals>.wrapper)r   r8   r9   r   )r6   rC   r$   rB   r%   requires_async_contextK   s   rD   c                   @   s<  e Zd ZU dZeZeed< eZeed< eZ	eed< eZ
eeejef  ed< g Zeee  ed< dZeeeeef   ed< d	Zeed
< d	Zeed< dZeed< 						dOdededeeejef  dededeee  fddZedee fddZeedefddZeedee fddZ eedee fddZ!eedee fddZ"dPde#dee$j% de&fdd Z'de(fd!d"Z)edee fd#d$Z*edee fd%d&Z+edee fd'd(Z,dddd)deeejef  d*eeeef  d+ee defd,d-Z-dddd)dee d*eeeef  d+ee de.fd.d/Z/e0dddd0d1d2e1d*eeeef  d3eeeef  dee d4e2d0 dee& fd5d6Z3e0dddd7d2e1d*eeeef  d3eeeef  dee d4e2d	 deeeef  fd8d6Z3edddd0d1d2e1d*eeeef  d3eeeef  dee d4ee2d0 e2d	 f deee& eeeef  f fd9d6Z3dQd:d;Z4dQd<d=Z5d>ee6e7  d?ee7 d@ee8 ddfdAdBZ9d>ee6e7  d?ee7 d@ee8 ddfdCdDZ:edefdEdFZ;e0ddddd0dGdHed2e1d*eeeef  deeeef  dee dIee d4e2d0 dee& fdJdKZ<e0dddddLdHed2e1d*eeeef  deeeef  dee dIee d4e2d	 deeeef  fdMdKZ<eddddd0dGdHed2e1d*eeeef  deeeef  dee dIee d4ee2d0 e2d	 f deee& eeeef  f fdNdKZ<dS )Rr>   z!Base class for all SSO providers.r3   	client_idclient_secretredirect_uriscopeNadditional_headersF	uses_pkcerequires_state`   _pkce_challenge_lengthallow_insecure_http	use_statec                 C   s   || _ || _|| _|| _t | _d| _d| _d| _	| jr*t
d| jj dtjd< |r2tdt |p6| j| _d| _d| _d| _d| _d| _d| _dS )z)Base class (mixin) for all SSO providers.FNz-Initializing %s with allow_insecure_http=True1ZOAUTHLIB_INSECURE_TRANSPORTzArgument 'use_state' of SSOBase's constructor is deprecated and will be removed in future releases. Use 'state' argument of individual methods instead.ZS256)rE   rF   rG   rN   asyncioLock_login_lockr?   _oauth_client_generated_stateloggerdebug	__class__r   osenvironr@   rA   DeprecationWarningrH   _scope_refresh_token	_id_token_state_pkce_code_challenge_pkce_code_verifier_pkce_challenge_method)selfrE   rF   rG   rN   rO   rH   r$   r$   r%   __init__i   s.   



zSSOBase.__init__r7   c                 C   s   | j du rtdt | j S )ag  Retrieves the state as it was returned from the server.

        Warning:
            This will emit a warning if the state is unset, implying either that
            the server didn't return a state or `verify_and_process` hasn't been
            called yet.

        Returns:
            Optional[str]: The state parameter returned from the server.
        Nz'state' parameter is unset. This means the server either didn't return state (was this expected?) or 'verify_and_process' hasn't been called yet.)r_   r@   rA   r'   rc   r$   r$   r%   state   s   
zSSOBase.statec                 C   s8   | j tkrtd| j d| jdu rt| j | _| jS )a  Retrieves the OAuth Client to aid in generating requests and parsing responses.

        Raises:
            NotImplementedError: If the provider is not supported or `client_id` is not set.

        Returns:
            WebApplicationClient: OAuth client instance.
        	Provider  not supportedN)rE   NotImplementedNotImplementedErrorr3   rT   r   re   r$   r$   r%   oauth_client   s
   

zSSOBase.oauth_clientc                 C   s   | j jS )zRetrieves the access token from token endpoint.

        Returns:
            Optional[str]: The access token if available.
        )rk   access_tokenre   r$   r$   r%   rl      s   zSSOBase.access_tokenc                 C   s   | j p| jjS )zRetrieves the refresh token if returned from provider.

        Returns:
            Optional[str]: The refresh token if available.
        )r]   rk   refresh_tokenre   r$   r$   r%   rm      s   zSSOBase.refresh_tokenc                 C   s   | j S )zRetrieves the id token if returned from provider.

        Returns:
            Optional[str]: The id token if available.
        )r^   re   r$   r$   r%   id_token   s   zSSOBase.id_tokenresponsesessionc                       t d| j d)a  Converts a response from the provider's user info endpoint to an OpenID object.

        Args:
            response (dict): The response from the user info endpoint.
            session (Optional[httpx.AsyncClient]): The HTTPX AsyncClient session.

        Raises:
            NotImplementedError: If the provider is not supported.

        Returns:
            OpenID: The user information in a standardized format.
        rg   rh   rj   r3   )rc   ro   rp   r$   r$   r%   openid_from_response   s   zSSOBase.openid_from_responsec                    rq   )a  Retrieves the discovery document containing useful URLs.

        Raises:
            NotImplementedError: If the provider is not supported.

        Returns:
            DiscoveryDocument: A dictionary containing important endpoints like authorization, token and userinfo.
        rg   rh   rr   re   r$   r$   r%   get_discovery_document   s   	zSSOBase.get_discovery_documentc                       |   I dH }|dS )z8Return `authorization_endpoint` from discovery document.Nr   rt   getrc   Z	discoveryr$   r$   r%   r         
zSSOBase.authorization_endpointc                    ru   )z0Return `token_endpoint` from discovery document.Nr   rv   rx   r$   r$   r%   r      ry   zSSOBase.token_endpointc                    ru   )z3Return `userinfo_endpoint` from discovery document.Nr   rv   rx   r$   r$   r%   r      ry   zSSOBase.userinfo_endpointrG   paramsrf   r{   rf   c                   s   |pi }|p	| j }|du rtd| jr't| j| jfs't| jj	d | j
r>|s>| jdu r;t| jj	d | j}| jj| jI dH f||| j| j| jd|}|S )a  Generates and returns the prepared login URL.

        Args:
            redirect_uri (Optional[str]): Overrides the `redirect_uri` specified on this instance.
            params (Optional[Dict[str, Any]]): Additional query parameters to add to the login request.
            state (Optional[str]): The state parameter for the OAuth 2.0 authorization request.

        Raises:
            ValueError: If `redirect_uri` is not provided either at construction or request time.

        Returns:
            str: The prepared login URL.
        NzEredirect_uri must be provided, either at construction or request timez| uses PKCE and no code was generated yet. Use SSO class as a context manager to get rid of this warning and possible errors.z requires state in the request but none was provided nor generated automatically. Use SSO as a context manager. The login process will most probably fail.)rG   rf   rH   Zcode_challengeZcode_challenge_method)rG   
ValueErrorrJ   allra   r`   r@   rA   rX   r   rK   rU   rk   Zprepare_request_urir   r\   rb   )rc   rG   r{   rf   request_urir$   r$   r%   get_login_url   s6   



	zSSOBase.get_login_urlc                   sN   | j r	|s	| j}| j|||dI dH }t|d}| jr%|dt| j |S )a  Constructs and returns a redirect response to the login page of OAuth SSO provider.

        Args:
            redirect_uri (Optional[str]): Overrides the `redirect_uri` specified on this instance.
            params (Optional[Dict[str, Any]]): Additional query parameters to add to the login request.
            state (Optional[str]): The state parameter for the OAuth 2.0 authorization request.

        Returns:
            RedirectResponse: A Starlette response directing to the login page of the OAuth SSO provider.
        rz   Ni/  pkce_code_verifier)rK   rU   r   r   rJ   
set_cookier"   ra   )rc   rG   r{   rf   Z	login_uriro   r$   r$   r%   get_login_redirect/  s   

zSSOBase.get_login_redirectT)r{   headersrG   convert_responserequestr   r   c                      d S Nr$   rc   r   r{   r   rG   r   r$   r$   r%   verify_and_processH     	zSSOBase.verify_and_process)r{   r   rG   c                   r   r   r$   r   r$   r$   r%   r   S  r   c             	      s   |pi }|j d}|du rtd|j|j|j  tdd|j d| _d}| jr:|j	d}|du r:t
d | j|||||||d	I dH S )
at  Processes the login given a FastAPI (Starlette) Request object. This should be used for the /callback path.

        Args:
            request (Request): FastAPI or Starlette request object.
            params (Optional[Dict[str, Any]]): Additional query parameters to pass to the provider.
            headers (Optional[Dict[str, Any]]): Additional headers to pass to the provider.
            redirect_uri (Optional[str]): Overrides the `redirect_uri` specified on this instance.
            convert_response (bool): If True, userinfo response is converted to OpenID object.

        Raises:
            SSOLoginError: If the 'code' parameter is not found in the callback request.

        Returns:
            Optional[OpenID]: User information as OpenID instance (if convert_response == True)
            Optional[Dict[str, Any]]: The original JSON response from the API.
        codeNz9Callback request:
	URI: %s
	Headers: %s
	Query params: %si  z2'code' parameter was not found in callback requestrf   r   zaPKCE code verifier was not found in the request Cookie. This will probably lead to a login error.r{   rI   rG   r   r   )Zquery_paramsrw   rV   rW   urlr   r+   r_   rJ   cookiesr@   rA   process_login)rc   r   r{   r   rG   r   r   r   r$   r$   r%   r   ^  s8   
c                 C   sR   t jdtdd d | _d | _d | _d | _| jrt | _	| j
r't| j\| _| _| S )NzSSO Providers are supposed to be used in async context, please change 'with provider' to 'async with provider'. See https://github.com/tomasvotava/fastapi-sso/issues/186 for more information.r:   )r<   )r@   rA   r[   rT   r]   r^   r_   rK   r   rU   rJ   r   rM   ra   r`   re   r$   r$   r%   	__enter__  s   zSSOBase.__enter__c                    sZ   | j  I d H  d| _d | _d | _d | _d | _| jrt | _	| j
r+t| j\| _| _| S )NT)rS   acquirer?   rT   r]   r^   r_   rK   r   rU   rJ   r   rM   ra   r`   re   r$   r$   r%   
__aenter__  s   zSSOBase.__aenter__	_exc_type_exc_val_exc_tbc                    s   d| _ | j  d S )NF)r?   rS   releaserc   r   r   r   r$   r$   r%   	__aexit__  s   zSSOBase.__aexit__c                 C   s   d S r   r$   r   r$   r$   r%   __exit__  s   zSSOBase.__exit__c                 C   s   i S r   r$   re   r$   r$   r%   _extra_query_params  s   zSSOBase._extra_query_paramsr   r   r   c                   r   r   r$   rc   r   r   r{   rI   rG   r   r   r$   r$   r%   r        zSSOBase.process_login)r{   rI   rG   r   c                   r   r   r$   r   r$   r$   r%   r     r   c             	      s
  | j durd| _ d| _d| _tdt |pi }|| j |p"i }|| jp)i  |j	}| j
s?|jdkr?t|dd}	nt|}	|j d|j |j }
|rX|d|i | jj| jI dH f|	|ph| jph|
|d|\}}}|du rxdS || t| j| j}t 4 I dH k}|j||||d	I dH }| }|d
| _|d| _| jt| | j| jI dH \}}}|| |j | ||I dH }| }|r| !||I dH W  d  I dH  S |W  d  I dH  S 1 I dH sw   Y  dS )a  Processes login from the callback endpoint to verify the user and request user info endpoint.
        It's a lower-level method, typically, you should use `verify_and_process` instead.

        Args:
            code (str): The authorization code.
            request (Request): FastAPI or Starlette request object.
            params (Optional[Dict[str, Any]]): Additional query parameters to pass to the provider.
            additional_headers (Optional[Dict[str, Any]]): Additional headers to be added to all requests.
            redirect_uri (Optional[str]): Overrides the `redirect_uri` specified on this instance.
            pkce_code_verifier (Optional[str]): A PKCE code verifier sent to the server to verify the login request.
            convert_response (bool): If True, userinfo response is converted to OpenID object.

        Raises:
            ReusedOauthClientWarning: If the SSO object is reused, which is not safe and caused security issues.

        Returns:
            Optional[OpenID]: User information in OpenID format if the login was successful (convert_response == True).
            Optional[Dict[str, Any]]: Original userinfo API endpoint response.
        NzReusing the SSO object is not safe and caused a security issue in previous versions.To make sure you don't see this warning, please use the SSO object as a context manager.httpszhttp://zhttps://z://Zcode_verifier)Zauthorization_responseZredirect_urlr   )r   contentauthrm   rn   )"rT   r]   r^   r@   rA   r*   updater   rI   r   rN   schemer"   replacenetlocpathrk   Zprepare_token_requestr   rG   httpxZ	BasicAuthrE   rF   AsyncClientpostjsonrw   Zparse_request_body_responsedumpsZ	add_tokenr   r   rs   )rc   r   r   r{   rI   rG   r   r   r   Zcurrent_urlcurrent_pathZ	token_urlr   bodyr   rp   ro   r   uri_r$   r$   r%   r     sb   



0)NFFNr   )r7   r>   )=r   r   r    r!   ri   r3   r"   r#   rE   rF   rG   r   r   r4   Z
AnyHttpUrlrH   r   r   rI   r   r   rJ   boolrK   rM   intrd   propertyrf   rD   r   rk   rl   rm   rn   dictr   r   r,   rs   r   rt   r   r   r   r   r   r   r   r   r   r   r   r   r	   BaseExceptionr   r   r   r   r   r$   r$   r$   r%   r>   [   s  
 

(
2



5


	

	
	
	
r>   )7r!   rQ   r   loggingrY   sysr@   typesr   typingr   r   r   r   r   r   r	   r
   r   r   r   r   r4   Zoauthlib.oauth2r   Zstarlette.exceptionsr   Zstarlette.requestsr   Zstarlette.responsesr   Zfastapi_sso.pkcer   Zfastapi_sso.stater   version_infor   Ztyping_extensionsr   collections.abc	getLoggerr   rV   r   r   r   UserWarningr'   r*   r+   Z	BaseModelr,   r5   rD   r>   r$   r$   r$   r%   <module>   sB    4

"