o
    iQ                     @   s   d Z ddlZddlmZmZ ddlmZmZ ddlm	Z	 ddl
Z
ddlZddlmZmZ ddlmZmZmZmZ ddlmZmZ G d	d
 d
eZdedeegee f fddZG dd deZG dd deZG dd deZG dd deZdS )a  
OAuth client credential extensions for MCP.

Provides OAuth providers for machine-to-machine authentication flows:
- ClientCredentialsOAuthProvider: For client_credentials with client_id + client_secret
- PrivateKeyJWTOAuthProvider: For client_credentials with private_key_jwt authentication
  (typically using a pre-built JWT from workload identity federation)
- RFC7523OAuthClientProvider: For jwt-bearer grant (RFC 7523 Section 2.1)
    N)	AwaitableCallable)AnyLiteral)uuid4)	BaseModelField)OAuthClientProviderOAuthFlowErrorOAuthTokenErrorTokenStorage)OAuthClientInformationFullOAuthClientMetadatac                       sv   e Zd ZdZ		ddededededed	 d
edB ddf fddZdddZde	j
fddZde	j
fddZ  ZS )ClientCredentialsOAuthProvidera  OAuth provider for client_credentials grant with client_id + client_secret.

    This provider sets client_info directly, bypassing dynamic client registration.
    Use this when you already have client credentials (client_id and client_secret).

    Example:
        ```python
        provider = ClientCredentialsOAuthProvider(
            server_url="https://api.example.com",
            storage=my_token_storage,
            client_id="my-client-id",
            client_secret="my-client-secret",
        )
        ```
    client_secret_basicN
server_urlstorage	client_idclient_secrettoken_endpoint_auth_method)r   client_secret_postscopesreturnc                    sD   t ddg||d}t |||ddd td||dg||d| _dS )a  Initialize client_credentials OAuth provider.

        Args:
            server_url: The MCP server URL.
            storage: Token storage implementation.
            client_id: The OAuth client ID.
            client_secret: The OAuth client secret.
            token_endpoint_auth_method: Authentication method for token endpoint.
                Either "client_secret_basic" (default) or "client_secret_post".
            scopes: Optional space-separated list of scopes to request.
        Nclient_credentialsredirect_urisgrant_typesr   scope     r@)r   r   r   r   r   r   )r   super__init__r   _fixed_client_info)selfr   r   r   r   r   r   client_metadata	__class__ a/home/ubuntu/.local/lib/python3.10/site-packages/mcp/client/auth/extensions/client_credentials.pyr    )   s   z'ClientCredentialsOAuthProvider.__init__c                    ,   | j j I dH | j _| j| j _d| _dS z6Load stored tokens and set pre-configured client_info.NTcontextr   
get_tokenscurrent_tokensr!   client_info_initializedr"   r&   r&   r'   _initializeO      

z*ClientCredentialsOAuthProvider._initializec                       |   I dH S )z)Perform client_credentials authorization.N"_exchange_token_client_credentialsr0   r&   r&   r'   _perform_authorizationU      z5ClientCredentialsOAuthProvider._perform_authorizationc                    st   ddi}ddi}| j ||\}}| j | j jr!| j  |d< | j jjr-| j jj|d< |  }tj	d|||dS )	z:Build token exchange request for client_credentials grant.
grant_typer   Content-Type!application/x-www-form-urlencodedresourcer   POSTdataheaders)
r+   prepare_token_authshould_include_resource_paramprotocol_versionget_resource_urlr#   r   _get_token_endpointhttpxRequestr"   
token_datar?   	token_urlr&   r&   r'   r5   Y      
zAClientCredentialsOAuthProvider._exchange_token_client_credentials)r   Nr   N)__name__
__module____qualname____doc__strr   r   r    r1   rE   rF   r6   r5   __classcell__r&   r&   r$   r'   r      s,    
&r   tokenr   c                       dt dt f fdd}|S )a  Create an assertion provider that returns a static JWT token.

    Use this when you have a pre-built JWT (e.g., from workload identity federation)
    that doesn't need the audience parameter.

    Example:
        ```python
        provider = PrivateKeyJWTOAuthProvider(
            server_url="https://api.example.com",
            storage=my_token_storage,
            client_id="my-client-id",
            assertion_provider=static_assertion_provider(my_prebuilt_jwt),
        )
        ```

    Args:
        token: The pre-built JWT assertion string.

    Returns:
        An async callback suitable for use as an assertion_provider.
    audiencer   c                    s    S Nr&   )rT   rR   r&   r'   provider   s   z+static_assertion_provider.<locals>.providerrP   )rR   rW   r&   rV   r'   static_assertion_providern   s   rY   c                   @   s   e Zd ZU dZeddZeed< eddZeed< eddZ	eed< ed	d
dZ
eed< edddZeed< edddZeeef dB ed< deegee f fddZdS )SignedJWTParametersa  Parameters for creating SDK-signed JWT assertions.

    Use `create_assertion_provider()` to create an assertion provider callback
    for use with `PrivateKeyJWTOAuthProvider`.

    Example:
        ```python
        jwt_params = SignedJWTParameters(
            issuer="my-client-id",
            subject="my-client-id",
            signing_key=private_key_pem,
        )
        provider = PrivateKeyJWTOAuthProvider(
            server_url="https://api.example.com",
            storage=my_token_storage,
            client_id="my-client-id",
            assertion_provider=jwt_params.create_assertion_provider(),
        )
        ```
    z0Issuer for JWT assertions (typically client_id).)descriptionissuerz<Subject identifier for JWT assertions (typically client_id).subjectz)Private key for JWT signing (PEM format).signing_keyRS256%Algorithm for signing JWT assertions.defaultr[   signing_algorithm,  %Lifetime of generated JWT in seconds.lifetime_secondsNzAdditional claims.additional_claimsr   c                    rS   )zCreate an assertion provider callback for use with PrivateKeyJWTOAuthProvider.

        Returns:
            An async callback that takes the audience (authorization server issuer URL)
            and returns a signed JWT assertion.
        rT   r   c                    sV   t t } j j| | j |tt d} jr!| j t	j
| j jdS )Nisssubaudexpiatjti	algorithm)inttimer\   r]   rf   rP   r   rg   updatejwtencoder^   rc   )rT   nowclaimsr0   r&   r'   rW      s   z?SignedJWTParameters.create_assertion_provider.<locals>.providerrX   )r"   rW   r&   r0   r'   create_assertion_provider   s   z-SignedJWTParameters.create_assertion_provider)rL   rM   rN   rO   r   r\   rP   __annotations__r]   r^   rc   rf   rq   rg   dictr   r   r   rx   r&   r&   r&   r'   rZ      s   
   rZ   c                       s   e Zd ZdZ	ddedededeegee f dedB ddf fd	d
ZdddZ	de
jfddZdeeef ddfddZde
jfddZ  ZS )PrivateKeyJWTOAuthProvideraq  OAuth provider for client_credentials grant with private_key_jwt authentication.

    Uses RFC 7523 Section 2.2 for client authentication via JWT assertion.

    The JWT assertion's audience MUST be the authorization server's issuer identifier
    (per RFC 7523bis security updates). The `assertion_provider` callback receives
    this audience value and must return a JWT with that audience.

    **Option 1: Pre-built JWT via Workload Identity Federation**

    In production scenarios, the JWT assertion is typically obtained from a workload
    identity provider (e.g., GCP, AWS IAM, Azure AD):

        ```python
        async def get_workload_identity_token(audience: str) -> str:
            # Fetch JWT from your identity provider
            # The JWT's audience must match the provided audience parameter
            return await fetch_token_from_identity_provider(audience=audience)

        provider = PrivateKeyJWTOAuthProvider(
            server_url="https://api.example.com",
            storage=my_token_storage,
            client_id="my-client-id",
            assertion_provider=get_workload_identity_token,
        )
        ```

    **Option 2: Static pre-built JWT**

    If you have a static JWT that doesn't need the audience parameter:

        ```python
        provider = PrivateKeyJWTOAuthProvider(
            server_url="https://api.example.com",
            storage=my_token_storage,
            client_id="my-client-id",
            assertion_provider=static_assertion_provider(my_prebuilt_jwt),
        )
        ```

    **Option 3: SDK-signed JWT (for testing/simple setups)**

    For testing or simple deployments, use `SignedJWTParameters.create_assertion_provider()`:

        ```python
        jwt_params = SignedJWTParameters(
            issuer="my-client-id",
            subject="my-client-id",
            signing_key=private_key_pem,
        )
        provider = PrivateKeyJWTOAuthProvider(
            server_url="https://api.example.com",
            storage=my_token_storage,
            client_id="my-client-id",
            assertion_provider=jwt_params.create_assertion_provider(),
        )
        ```
    Nr   r   r   assertion_providerr   r   c                    sH   t ddgd|d}t |||ddd || _td|dgd|d| _dS )a  Initialize private_key_jwt OAuth provider.

        Args:
            server_url: The MCP server URL.
            storage: Token storage implementation.
            client_id: The OAuth client ID.
            assertion_provider: Async callback that takes the audience (authorization
                server's issuer identifier) and returns a JWT assertion. Use
                `SignedJWTParameters.create_assertion_provider()` for SDK-signed JWTs,
                `static_assertion_provider()` for pre-built JWTs, or provide your own
                callback for workload identity federation.
            scopes: Optional space-separated list of scopes to request.
        Nr   private_key_jwtr   r   )r   r   r   r   r   )r   r   r    _assertion_providerr   r!   )r"   r   r   r   r|   r   r#   r$   r&   r'   r       s   z#PrivateKeyJWTOAuthProvider.__init__c                    r(   r)   r*   r0   r&   r&   r'   r1   %  r2   z&PrivateKeyJWTOAuthProvider._initializec                    r3   )z>Perform client_credentials authorization with private_key_jwt.Nr4   r0   r&   r&   r'   r6   +  r7   z1PrivateKeyJWTOAuthProvider._perform_authorizationrH   c                   sD   | j js	tdt| j jj}| |I dH }||d< d|d< dS )IAdd JWT assertion for client authentication to token endpoint parameters./Missing OAuth metadata for private_key_jwt flowNclient_assertion6urn:ietf:params:oauth:client-assertion-type:jwt-bearerclient_assertion_type)r+   oauth_metadatar
   rP   r\   r~   )r"   rH   rT   	assertionr&   r&   r'   _add_client_authentication_jwt/  s   z9PrivateKeyJWTOAuthProvider._add_client_authentication_jwtc                    st   ddi}ddi}| j |dI dH  | j| jjr!| j |d< | jjjr-| jjj|d< |  }tj	d	|||d
S )zOBuild token exchange request for client_credentials grant with private_key_jwt.r8   r   r9   r:   rH   Nr;   r   r<   r=   )
r   r+   rA   rB   rC   r#   r   rD   rE   rF   rG   r&   r&   r'   r5   =  rJ   z=PrivateKeyJWTOAuthProvider._exchange_token_client_credentialsrU   rK   )rL   rM   rN   rO   rP   r   r   r   r    r1   rE   rF   r6   rz   r   r   r5   rQ   r&   r&   r$   r'   r{      s(    A
'r{   c                   @   s   e Zd ZU dZedddZedB ed< edddZedB ed< edddZ	edB ed	< edd
dZ
edB ed< edddZeeef dB ed< edddZedB ed< edddZedB ed< edddZeed< ddedB defddZdS )JWTParameterszJWT parameters.NzeJWT assertion for JWT authentication. Will be used instead of generating a new assertion if provided.ra   r   zIssuer for JWT assertions.r\   z&Subject identifier for JWT assertions.r]   zAudience for JWT assertions.rT   z%Additional claims for JWT assertions.rw   r_   r`   jwt_signing_algorithmzPrivate key for JWT signing.jwt_signing_keyrd   re   jwt_lifetime_secondswith_audience_fallbackr   c                 C   s   | j d ur
| j }|S | jstd| jstd| jstd| jr%| jn|}|s-tdtt }| j| j||| j |t	t
 d}|| jpJi  tj|| j| jpUdd}|S )Nz(Missing signing key for JWT bearer grantz#Missing issuer for JWT bearer grantz$Missing subject for JWT bearer grantz%Missing audience for JWT bearer grantrh   r_   ro   )r   r   r
   r\   r]   rT   rq   rr   r   rP   r   rs   rw   rt   ru   r   )r"   r   r   rT   rv   rw   r&   r&   r'   to_assertionc  s6   
zJWTParameters.to_assertionrU   )rL   rM   rN   rO   r   r   rP   ry   r\   r]   rT   rw   rz   r   r   r   r   rq   r   r&   r&   r&   r'   r   R  s   
  r   c                       s   e Zd ZdZ				ddedededeeged f dB deg ee	eedB f  f dB d	e
d
edB ddf fddZdddededeeef dB dejf fddZdejf fddZdeeef fddZdejfddZ  ZS )RFC7523OAuthClientProvidera  OAuth client provider for RFC 7523 jwt-bearer grant.

    .. deprecated::
        Use :class:`ClientCredentialsOAuthProvider` for client_credentials with
        client_id + client_secret, or :class:`PrivateKeyJWTOAuthProvider` for
        client_credentials with private_key_jwt authentication instead.

    This provider supports the jwt-bearer authorization grant (RFC 7523 Section 2.1)
    where the JWT itself is the authorization grant.
    Nr   r   r#   r   redirect_handlercallback_handlertimeoutjwt_parametersr   c           	         s8   dd l }|jdtdd t |||||| || _d S )Nr   zsRFC7523OAuthClientProvider is deprecated. Use ClientCredentialsOAuthProvider or PrivateKeyJWTOAuthProvider instead.   )
stacklevel)warningswarnDeprecationWarningr   r    r   )	r"   r   r#   r   r   r   r   r   r   r$   r&   r'   r      s   

z#RFC7523OAuthClientProvider.__init__r   	auth_codecode_verifierrH   c                   s<   |pi }| j jjdkr| j|d t j|||dI dH S )z9Build token exchange request for authorization_code flow.r}   r   N)r+   r#   r   r   r   "_exchange_token_authorization_code)r"   r   r   rH   r$   r&   r'   r     s
   z=RFC7523OAuthClientProvider._exchange_token_authorization_codec                    s2   d| j jjv r|  I dH }|S t  I dH S )zPerform the authorization flow.+urn:ietf:params:oauth:grant-type:jwt-bearerN)r+   r#   r   _exchange_token_jwt_bearerr   r6   )r"   token_requestr$   r&   r'   r6     s
   z1RFC7523OAuthClientProvider._perform_authorizationc                C   s\   | j std| jjstdt| jjj}| j j|d}||d< d|d< | j |d< dS )	r   z/Missing JWT parameters for private_key_jwt flowr   r   r   r   r   rT   N)r   r   r+   r   rP   r\   r   rC   )r"   rH   r\   r   r&   r&   r'   r     s   z9RFC7523OAuthClientProvider._add_client_authentication_jwtc                    s   | j js	td| jstd| j jstdt| j jj}| jj|d}d|d}| j 	| j j
r:| j  |d< | j jjrF| j jj|d< |  }tjd	||d
didS )z2Build token exchange request for JWT bearer grant.zMissing client infozMissing JWT parameterszMissing OAuth metadatar   r   )r8   r   r;   r   r<   r9   r:   r=   )r+   r.   r
   r   r   r   rP   r\   r   rA   rB   rC   r#   r   rD   rE   rF   )r"   r\   r   rH   rI   r&   r&   r'   r     s(   
z5RFC7523OAuthClientProvider._exchange_token_jwt_bearer)NNr   N)rL   rM   rN   rO   rP   r   r   r   r   tuplefloatr   r    rz   r   rE   rF   r   r6   r   r   rQ   r&   r&   r$   r'   r     sH    		r   )rO   rr   collections.abcr   r   typingr   r   uuidr   rE   rt   pydanticr   r   mcp.client.authr	   r
   r   r   mcp.shared.authr   r   r   rP   rY   rZ   r{   r   r   r&   r&   r&   r'   <module>   s"    
 V7 4