
    Gj%/              
       f   S SK r S SKrS SKJrJr  S SKJrJr  S SKJ	r	J
r
  S SKJrJr  S SKJr  S SKJrJrJrJrJr  S SKJr  \ R0                  " \5      rS	\S
\S\S-  4S jrS	\S\S-  4S jrS	\S\S-  4S jrS\S-  S\S\\   4S jr  S(S\S-  S\S-  S\S-  S\S-  4S jjr!S\S-  S\S\\   4S jr"S	\S\S-  4S jr#S	\S\$\%\S-  4   4S jr&S\S\4S jr'S\S-  S\S\S\4S jr(S	\S\4S  jr)S\S-  S\%4S! jr*S"\S-  S#\S-  S\%4S$ jr+ S(S#\S%\\	   S-  S\4S& jjr,S	\S\4S' jr-g))    N)urljoinurlparse)RequestResponse)AnyUrlValidationError)OAuthRegistrationErrorOAuthTokenError)MCP_PROTOCOL_VERSION)OAuthClientInformationFullOAuthClientMetadataOAuthMetadata
OAuthTokenProtectedResourceMetadata)LATEST_PROTOCOL_VERSIONresponse
field_namereturnc                     U R                   R                  S5      nU(       d  gU S3n[        R                  " X25      nU(       a)  UR	                  S5      =(       d    UR	                  S5      $ g)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        W/Users/admin/workspace/tools/venv/lib/python3.13/site-packages/mcp/client/auth/utils.pyextract_field_from_www_authr!      s_     &&**+=>O 56GIIg/E{{1~/Q/    c                     [        U S5      $ )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                 J    U (       a  U R                   S:w  a  g[        U S5      $ )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                 V   / nU (       a  UR                  U 5        [        U5      nUR                   SUR                   3nUR                  (       a:  UR                  S:w  a*  [        USUR                   35      nUR                  U5        [        US5      nUR                  U5        U$ )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                     U b  U $ Ub(  UR                   b  SR                  UR                   5      $ Ub(  UR                   b  SR                  UR                   5      $ g)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                    U (       d(  [        U5      nUR                   SUR                   S3/$ / n[        U 5      nUR                   SUR                   3nUR                  (       a  UR                  S:w  a  SUR                  R	                  S5       3nUR                  [        XE5      5        SUR                  R	                  S5       3nUR                  [        XF5      5        UR                  R	                  S5       S3nUR                  [        XF5      5        U$ UR                  [        US5      5        UR                  [        US5      5        U$ )z
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      s0     *%==/V]]O3Z[\\Do&F--FMM?3H {{v{{c)>v{{?Q?QRU?V>WX
GH12 88J8J38O7PQ	GH01 {{))#.//PQ	GH01 	KK"KLM 	KK"EFGKr"   c                    #    U R                   S:X  a1   U R                  5       I Sh  vN n[        R                  " U5      nU$ g N! [         a     gf = f7f)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                    #    U R                   S:X  a3   U R                  5       I S h  vN n[        R                  " U5      nSU4$ U R                   S:  d  U R                   S:  a  gg N@! [         a     gf = f7f)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   A:A* A(A* #A:(A* *
A74A:6A77A:urlc                 ,    [        SU [        [        0S9$ )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                     U (       a'  U R                   (       a  [        U R                   5      nO[        US5      nUR                  SSSS9n[	        SX4SS0S9$ )	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      s^    
  4 J J3IIJ"=+>'22Dv\`2a6+n^pMqrrr"   c                 N  #    U R                   S;  a=  U R                  5       I Sh  vN   [        SU R                    SU R                   35      e U R                  5       I Sh  vN n[        R
                  " U5      nU$  NZ N! [         a  n[        SU 35      eSnAff = f7f)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%B)B%B $B%B  B%B 
B"BB""B%c                     U (       d  g [        U 5      nUR                  S:H  =(       a    UR                  S;  $ ! [         a     gf = f)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   /: 
AAoauth_metadataclient_metadata_urlc                 >    U(       d  gU (       d  gU R                   SL $ )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                     [        U SUS9$ )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                    #     U R                  5       I Sh  vN n[        R                  " U5      nU$  N! [         a  n[	        SU 35      eSnAff = f7f)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}   ;  sX      > ((#77@ )  > 8<==>s1   A6 46 A6 
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      s5    	 * # , 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"   