
    [ǻi%/              
       D   d dl Z d dlZd dlmZmZ d dlmZ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mZmZmZ d dlmZ  e j0                  e      Zd	ed
ededz  fdZd	ededz  fdZd	ededz  fdZdedz  dedee   fdZ 	 d(dedz  dedz  dedz  dedz  fdZ!dedz  dedee   fdZ"d	ededz  fdZ#d	ede$e%edz  f   fdZ&dedefdZ'dedz  dededefdZ(d	edefd Z)dedz  de%fd!Z*d"edz  d#edz  de%fd$Z+	 d(d#ed%ee	   dz  defd&Z,d	edefd'Z-y))    N)urljoinurlparse)RequestResponse)AnyUrlValidationError)OAuthRegistrationErrorOAuthTokenError)MCP_PROTOCOL_VERSION)OAuthClientInformationFullOAuthClientMetadataOAuthMetadata
OAuthTokenProtectedResourceMetadata)LATEST_PROTOCOL_VERSIONresponse
field_namereturnc                     | j                   j                  d      }|sy| d}t        j                  ||      }|r$|j	                  d      xs |j	                  d      S y)z
    Extract field from WWW-Authenticate header.

    Returns:
        Field value if found in WWW-Authenticate header, None otherwise
    zWWW-AuthenticateNz=(?:"([^"]+)"|([^\s,]+))      )headersgetresearchgroup)r   r   www_auth_headerpatternmatchs        S/opt/lhia/marcimex/agent/venv/lib/python3.12/site-packages/mcp/client/auth/utils.pyextract_field_from_www_authr!      sa     &&**+=>O 56GIIg/E{{1~/Q/    c                     t        | d      S )z
    Extract scope parameter from WWW-Authenticate header as per RFC6750.

    Returns:
        Scope string if found in WWW-Authenticate header, None otherwise
    scope)r!   r   s    r    extract_scope_from_www_authr&   ,   s     'x99r"   c                 >    | r| j                   dk7  ryt        | d      S )z
    Extract protected resource metadata URL from WWW-Authenticate header as per RFC9728.

    Returns:
        Resource metadata URL if found in WWW-Authenticate header, None otherwise
    i  Nresource_metadata)status_coder!   r%   s    r    'extract_resource_metadata_from_www_authr*   6   s%     x++s2&x1DEEr"   www_auth_url
server_urlc                 @   g }| r|j                  |        t        |      }|j                   d|j                   }|j                  r9|j                  dk7  r*t        |d|j                         }|j                  |       t        |d      }|j                  |       |S )a;  
    Build ordered list of URLs to try for protected resource metadata discovery.

    Per SEP-985, the client MUST:
    1. Try resource_metadata from WWW-Authenticate header (if present)
    2. Fall back to path-based well-known URI: /.well-known/oauth-protected-resource/{path}
    3. Fall back to root-based well-known URI: /.well-known/oauth-protected-resource

    Args:
        www_auth_url: optional resource_metadata url extracted from the WWW-Authenticate header
        server_url: server url

    Returns:
        Ordered list of URLs to try for discovery
    :///z%/.well-known/oauth-protected-resource)appendr   schemenetlocpathr   )r+   r,   urlsparsedbase_urlpath_based_urlroot_based_urls          r    0build_protected_resource_metadata_discovery_urlsr9   C   s      D L! j!F--FMM?3H {{v{{c) -RSYS^S^R_+`aN# X'NONKKKr"   www_authenticate_scopeprotected_resource_metadataauthorization_server_metadatac                     | | S |'|j                   dj                  |j                         S |'|j                   dj                  |j                         S y)zLSelect scopes as outlined in the 'Scope Selection Strategy' in the MCP spec.N )scopes_supportedjoin)r:   r;   r<   s      r    get_client_metadata_scopesrA   i   se     )%%	$	05P5a5a5mxx3DDEE	&	27T7e7e7qxx5FFGG r"   auth_server_urlc                    | s(t        |      }|j                   d|j                   dgS g }t        |       }|j                   d|j                   }|j                  r|j                  dk7  rd|j                  j	                  d       }|j                  t        ||             d|j                  j	                  d       }|j                  t        ||             |j                  j	                  d       d}|j                  t        ||             |S |j                  t        |d             |j                  t        |d             |S )a  
    Generate ordered list of (url, type) tuples for discovery attempts.

    Args:
        auth_server_url: URL for the OAuth Authorization Metadata URL if found, otherwise None
        server_url: URL for the MCP server, used as a fallback if auth_server_url is None
    r.   z'/.well-known/oauth-authorization-serverr/   z!/.well-known/openid-configuration)r   r1   r2   r3   rstripr0   r   )rB   r,   r5   r4   r6   
oauth_path	oidc_paths          r    8build_oauth_authorization_server_metadata_discovery_urlsrG      s6     *%==/V]]O3Z[\\Do&F--FMM?3H {{v{{c)>v{{?Q?QRU?V>WX
GHj12 88J8J38O7PQ	GHi01 {{))#.//PQ	GHi01 	KK"KLM 	KK"EFGKr"   c                    K   | j                   dk(  r0	 | j                          d{   }t        j                  |      }|S y7 # t        $ r Y yw xY ww)z
    Handle protected resource metadata discovery response.

    Per SEP-985, supports fallback when discovery fails at one URL.

    Returns:
        True if metadata was successfully discovered, False if we should try next URL
       N)r)   areadr   model_validate_jsonr   )r   contentmetadatas      r    "handle_protected_resource_responserN      s\      s"	$NN,,G0DDWMHO  -  		s8   AA AA AA 	AAAAc                    K   | j                   dk(  r2	 | j                          d {   }t        j                  |      }d|fS | j                   dk  s| j                   dk\  ryy7 =# t        $ r Y yw xY ww)NrI   T)TNi  i  )FN)r)   rJ   r   rK   r   )r   rL   asms      r    handle_auth_metadata_responserQ      s}     s"	$NN,,G33G<C9 
			#x';';s'B -  		s8   A5A& A$A& !A5$A& &	A2/A51A22A5urlc                 2    t        d| t        t        i      S )NGET)r   )r   r   r   )rR   s    r    create_oauth_metadata_requestrU      s    5#(<>U'VWWr"   auth_server_metadataclient_metadataauth_base_urlc                     | r"| j                   rt        | j                         }nt        |d      }|j                  ddd      }t	        d||ddi      S )	z9Build registration request or skip if already registered.z	/registerTjson)by_aliasmodeexclude_nonePOSTzContent-Typezapplication/json)rZ   r   )registration_endpointstrr   
model_dumpr   )rV   rW   rX   registration_urlregistration_datas        r    "create_client_registration_requestrd      sa    
  4 J J3IIJ"=+>'22Dv\`2a6+2Cn^pMqrrr"   c                 F  K   | j                   dvr=| j                          d{    t        d| j                    d| j                         	 | j                          d{   }t	        j
                  |      }|S 7 Y7 # t        $ r}t        d|       d}~ww xY ww)zHandle registration response.)rI      NzRegistration failed: r>   zInvalid registration response: )r)   rJ   r	   textr   rK   r   )r   rL   client_infoes       r    handle_registration_responserj      s     :-nn$'<X=Q=Q<RRST\TaTaSb%cddL ((0DDWM 	 )
  L$'Fqc%JKKLsE   "B!A>)B!B "B #B =B! B 	BBBB!c                 |    | sy	 t        |       }|j                  dk(  xr |j                  dvS # t        $ r Y yw xY w)zValidate that a URL is suitable for use as a client_id (CIMD).

    The URL must be HTTPS with a non-root pathname.

    Args:
        url: The URL to validate

    Returns:
        True if the URL is a valid HTTPS URL with a non-root pathname
    Fhttps) r/   )r   r1   r3   	Exception)rR   r5   s     r    is_valid_client_metadata_urlro      sG     #}}'HFKKy,HH s   )/ 	;;oauth_metadataclient_metadata_urlc                 *    |sy| sy| j                   du S )a  Determine if URL-based client ID (CIMD) should be used instead of DCR.

    URL-based client IDs should be used when:
    1. The server advertises client_id_metadata_document_supported=true
    2. The client has a valid client_metadata_url configured

    Args:
        oauth_metadata: OAuth authorization server metadata
        client_metadata_url: URL-based client ID (already validated)

    Returns:
        True if CIMD should be used, False if DCR should be used
    FT)%client_id_metadata_document_supported)rp   rq   s     r    should_use_client_metadata_urlrt   
  s!    " ??4GGr"   redirect_urisc                     t        | d|      S )a  Create client information using a URL-based client ID (CIMD).

    When using URL-based client IDs, the URL itself becomes the client_id
    and no client_secret is used (token_endpoint_auth_method="none").

    Args:
        client_metadata_url: The URL to use as the client_id
        redirect_uris: The redirect URIs from the client metadata (passed through for
            compatibility with OAuthClientInformationFull which inherits from OAuthClientMetadata)

    Returns:
        OAuthClientInformationFull with the URL as client_id
    none)	client_idtoken_endpoint_auth_methodru   )r   )rq   ru   s     r    $create_client_info_from_metadata_urlrz   $  s      &%#)# r"   c                    K   	 | j                          d{   }t        j                  |      }|S 7 # t        $ r}t	        d|       d}~ww xY ww)av  Parse and validate token response with optional scope validation.

    Parses token response JSON. Callers should check response.status_code before calling.

    Args:
        response: HTTP response from token endpoint (status already checked by caller)

    Returns:
        Validated OAuthToken model

    Raises:
        OAuthTokenError: If response JSON is invalid
    NzInvalid token response: )rJ   r   rK   r   r
   )r   rL   token_responseri   s       r    handle_token_response_scopesr}   ;  sY      > ((#77@ )  > 8<==>s0   A5 35 A5 	AAAA)N).loggingr   urllib.parser   r   httpxr   r   pydanticr   r   mcp.client.authr	   r
   mcp.client.streamable_httpr   mcp.shared.authr   r   r   r   r   	mcp.typesr   	getLogger__name__loggerr`   r!   r&   r*   listr9   rA   rG   rN   tupleboolrQ   rU   rd   rj   ro   rt   rz   r}    r"   r    <module>r      s7    	 * # , C ;  .			8	$(  d
 ,:( :sTz :
Fh 
F3: 
F#3: #[^ #cghkcl #R ;?$J!:T!A $14#7 	4Z	0)cTXj )fi )nrsvnw )X%2
( 
uT=[_K_E_?` 
Xs Xw Xs'$.sATsehssL L>X L cDj T (H!D(HtH 
H6 DH-1&\D-@.>>>r"   