
    [ǻik                        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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mZmZ ddlZddlZddlmZmZmZ ddlmZ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*m+Z+m,Z,m-Z-m.Z. dd
l/m0Z0 ddl1m2Z2m3Z3m4Z4m5Z5m6Z6 ddl7m8Z8m9Z9m:Z:  ejv                  e<      Z= G d de      Z> G d de      Z?e G d d             Z@ G d dej                        ZBy)z|
OAuth2 Authentication implementation for HTTPX.

Implements authorization code flow with PKCE and automatic token refresh.
    N)AsyncGenerator	AwaitableCallable)	dataclassfield)AnyProtocol)quote	urlencodeurljoinurlparse)	BaseModelFieldValidationError)OAuthFlowErrorOAuthTokenError)8build_oauth_authorization_server_metadata_discovery_urls0build_protected_resource_metadata_discovery_urls$create_client_info_from_metadata_url"create_client_registration_requestcreate_oauth_metadata_requestextract_field_from_www_auth'extract_resource_metadata_from_www_authextract_scope_from_www_authget_client_metadata_scopeshandle_auth_metadata_response"handle_protected_resource_responsehandle_registration_responsehandle_token_response_scopesis_valid_client_metadata_urlshould_use_client_metadata_url)MCP_PROTOCOL_VERSION)OAuthClientInformationFullOAuthClientMetadataOAuthMetadata
OAuthTokenProtectedResourceMetadata)calculate_token_expirycheck_resource_allowedresource_url_from_server_urlc                   d    e Zd ZU dZ eddd      Zeed<    eddd      Zeed<   e	d
d       Z
y	)PKCEParametersz.PKCE (Proof Key for Code Exchange) parameters..+      )
min_length
max_lengthcode_verifiercode_challengec                    dj                  d t        d      D              }t        j                  |j	                               j                         }t        j                  |      j                         j                  d      } | ||      S )zGenerate new PKCE parameters. c              3      K   | ];  }t        j                  t        j                  t        j                  z   d z          = yw)z-._~N)secretschoicestringascii_lettersdigits).0_s     T/opt/lhia/marcimex/agent/venv/lib/python3.12/site-packages/mcp/client/auth/oauth2.py	<genexpr>z*PKCEParameters.generate.<locals>.<genexpr>B   s/     rbcv/C/Cfmm/SV\/\ ]rs   AAr.   =)r1   r2   )
joinrangehashlibsha256encodedigestbase64urlsafe_b64encodedecoderstrip)clsr1   rE   r2   s       r=   generatezPKCEParameters.generate?   sp     rglmpgqrr 4 4 67>>@11&9@@BII#N~NN    N)returnr,   )__name__
__module____qualname____doc__r   r1   str__annotations__r2   classmethodrK    rL   r=   r,   r,   9   s?    8srcBM3BsCNCCO OrL   r,   c                   T    e Zd ZdZdedz  fdZdeddfdZdedz  fdZdeddfd	Z	y)
TokenStoragez+Protocol for token storage implementations.rM   Nc                    K   yw)zGet stored tokens.NrU   selfs    r=   
get_tokenszTokenStorage.get_tokensK   	        tokensc                    K   yw)zStore tokens.NrU   )rZ   r^   s     r=   
set_tokenszTokenStorage.set_tokensO   r\   r]   c                    K   yw)zGet stored client information.NrU   rY   s    r=   get_client_infozTokenStorage.get_client_infoS   r\   r]   client_infoc                    K   yw)zStore client information.NrU   )rZ   rc   s     r=   set_client_infozTokenStorage.set_client_infoW   r\   r]   )
rN   rO   rP   rQ   r&   r[   r`   r#   rb   re   rU   rL   r=   rW   rW   H   sP    5*t"3 z d 'AD'H 1K PT rL   rW   c                   (   e Zd ZU dZeed<   eed<   eed<   eege	d   f   dz  ed<   eg e	e
eedz  f      f   dz  ed<   dZeed	<   dZedz  ed
<   dZedz  ed<   dZedz  ed<   dZedz  ed<   dZedz  ed<   dZedz  ed<   dZedz  ed<   dZedz  ed<    eej6                        Zej6                  ed<   dedefdZdeddfdZdefdZ defdZ!d dZ"defdZ#d!dedz  defdZ$	 d!de%eef   de%eef   dz  de
e%eef   e%eef   f   fdZ&y)"OAuthContextzOAuth flow context.
server_urlclient_metadatastorageNredirect_handlercallback_handler     r@timeoutclient_metadata_urlprotected_resource_metadataoauth_metadataauth_server_urlprotocol_versionrc   current_tokenstoken_expiry_time)default_factorylockrM   c                 N    t        |      }|j                   d|j                   S )z,Extract base URL by removing path component.z://)r   schemenetloc)rZ   rh   parseds      r=   get_authorization_base_urlz'OAuthContext.get_authorization_base_urlx   s%    *%--FMM?33rL   tokenc                 8    t        |j                        | _        y)z4Update token expiry time using shared util function.N)r(   
expires_inru   )rZ   r}   s     r=   update_token_expiryz OAuthContext.update_token_expiry}   s    !78H8H!IrL   c                     t        | j                  xrH | j                  j                  xr0 | j                   xs! t	        j                         | j                  k        S )z Check if current token is valid.)boolrt   access_tokenru   timerY   s    r=   is_token_validzOAuthContext.is_token_valid   sU     V##00V+++Ttyy{d>T>T/T
 	
rL   c                 x    t        | j                  xr$ | j                  j                  xr | j                        S )z Check if token can be refreshed.)r   rt   refresh_tokenrc   rY   s    r=   can_refresh_tokenzOAuthContext.can_refresh_token   s0    D''bD,?,?,M,MbRVRbRbccrL   c                      d| _         d| _        y)zClear current tokens.N)rt   ru   rY   s    r=   clear_tokenszOAuthContext.clear_tokens   s    "!%rL   c                     t        | j                        }| j                  rD| j                  j                  r.t	        | j                  j                        }t        ||      r|}|S )zGet resource URL for RFC 8707.

        Uses PRM resource if it's a valid parent, otherwise uses canonical server URL.
        )requested_resourceconfigured_resource)r*   rh   rp   resourcerR   r)   )rZ   r   prm_resources      r=   get_resource_urlzOAuthContext.get_resource_url   sV    
 0@ ++0P0P0Y0Yt??HHIL%Wcd'rL   c                 ,    | j                   y|sy|dk\  S )zDetermine if the resource parameter should be included in OAuth requests.

        Returns True if:
        - Protected resource metadata is available, OR
        - MCP-Protocol-Version header is 2025-06-18 or later
        TFz
2025-06-18)rp   )rZ   rs   s     r=   should_include_resource_paramz*OAuthContext.should_include_resource_param   s(     ++7    <//rL   dataheadersc                    |i }| j                   s||fS | j                   j                  }|dk(  r| j                   j                  r| j                   j                  rt	        | j                   j                  d      }t	        | j                   j                  d      }| d| }t        j                  |j                               j                         }d| |d<   |j                         D 	ci c]  \  }}	|dk7  s||	 }}}	||fS |dk(  r/| j                   j                  r| j                   j                  |d<   ||fS c c}	}w )	zPrepare authentication for token requests.

        Args:
            data: The form data to send
            headers: Optional headers dict to update

        Returns:
            Tuple of (updated_data, updated_headers)
        client_secret_basicr4   )safe:zBasic Authorizationclient_secretclient_secret_post)
rc   token_endpoint_auth_method	client_idr   r
   rF   	b64encoderD   rH   items)
rZ   r   r   auth_method
encoded_idencoded_secretcredentialsencoded_credentialskvs
             r=   prepare_token_authzOAuthContext.prepare_token_auth   sD    ?G= &&AA//D4D4D4N4NSWScScSqSqt//99CJ"4#3#3#A#AKN'L.)9:K"("2"2;3E3E3G"H"O"O"Q)/0C/D'EGO$%)ZZ\JTQQ/5IAqDJDJ W} 00T5E5E5S5S$($4$4$B$BD! W} Ks   1E?ErM   NN)'rN   rO   rP   rQ   rR   rS   r$   rW   r   r   tuplern   floatro   rp   r'   rq   r%   rr   rs   rc   r#   rt   r&   ru   r   anyioLockrw   r|   r   r   r   r   r   r   r   dictr   rU   rL   r=   rg   rg   \   s   O((uio56==r9U3d
?-C#DDELLGU&*t* EI!:T!AH+/NMD(/"&OS4Z&#'cDj' 6:K+d29 )-NJ%,&*ut|* UZZ8D%**84S 4S 4
J J J
 
d4 d&
# 0cDj 0TX 0( FJ"cN"-1#s(^d-B"	tCH~tCH~-	."rL   rg   c                   <   e Zd ZdZdZ	 	 	 	 ddedededeege	d   f   dz  deg e	e
eedz  f      f   dz  d	ed
edz  fdZdej                  defdZdej"                  fdZde
eef   fdZdefdZi ddededeeef   dz  dej"                  fdZdej                  ddfdZdej"                  fdZdej                  defdZd dZdej"                  ddfdZdej                  ddfdZdej"                  deej"                  ej                  f   fdZy)!OAuthClientProviderzw
    OAuth2 authentication for httpx.
    Handles OAuth flow with automatic client registration and token storage.
    TNrh   ri   rj   rk   rl   rn   ro   c           	      v    |t        |      st        d|       t        |||||||      | _        d| _        y)al  Initialize OAuth2 authentication.

        Args:
            server_url: The MCP server URL.
            client_metadata: OAuth client metadata for registration.
            storage: Token storage implementation.
            redirect_handler: Handler for authorization redirects.
            callback_handler: Handler for authorization callbacks.
            timeout: Timeout for the OAuth flow.
            client_metadata_url: URL-based client ID. When provided and the server
                advertises client_id_metadata_document_supported=true, this URL will be
                used as the client_id instead of performing dynamic client registration.
                Must be a valid HTTPS URL with a non-root pathname.

        Raises:
            ValueError: If client_metadata_url is provided but not a valid HTTPS URL
                with a non-root pathname.
        NzMclient_metadata_url must be a valid HTTPS URL with a non-root pathname, got: )rh   ri   rj   rk   rl   rn   ro   F)r    
ValueErrorrg   context_initialized)rZ   rh   ri   rj   rk   rl   rn   ro   s           r=   __init__zOAuthClientProvider.__init__   sY    : *3OPc3d_`s_tu  $!+-- 3
 "rL   responserM   c                 2  K   |j                   dk(  rs	 |j                          d{   }t        j                  |      }|| j                  _        |j                  r't        |j                  d         | j                  _        y|j                   dk(  r.t        j                  d|j                  j                   d	       yt        d
|j                          7 # t        $ r/ t        j                  d|j                  j                          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
           Nr   Tz'Invalid protected resource metadata at Fi  z)Protected resource metadata not found at z, trying next URLz,Protected Resource Metadata request failed: )status_codeareadr'   model_validate_jsonr   rp   authorization_serversrR   rr   r   loggerwarningrequesturldebugr   rZ   r   contentmetadatas       r=   #_handle_protected_resource_responsez7OAuthClientProvider._handle_protected_resource_response  s      3& ( 004HHQ;C81136x7U7UVW7X3YDLL0 !!S(LLDXEUEUEYEYDZZklm !>x?S?S>TU # 1 # !HIYIYI]I]H^_`s:   DC CAC ADC 5DDDDc                    K   | j                          d{   \  }}| j                  ||       d{   }|S 7 #7 w)zPerform the authorization flow.N)!_perform_authorization_code_grant"_exchange_token_authorization_code)rZ   	auth_coder1   token_requests       r=   _perform_authorizationz*OAuthClientProvider._perform_authorization.  sB     )-)O)O)Q#Q 	="EEiQ^__ $R_s   >:><>>c                   K   | j                   j                  j                  t        d      | j                   j                  st        d      | j                   j
                  st        d      | j                   j                  rJ| j                   j                  j                  r*t        | j                   j                  j                        }n;| j                   j                  | j                   j                        }t        |d      }| j                   j                  st        d      t        j                         }t        j                   d      }d| j                   j                  j"                  t        | j                   j                  j                  d	         ||j$                  d
d}| j                   j'                  | j                   j(                        r| j                   j+                         |d<   | j                   j                  j,                  r#| j                   j                  j,                  |d<   | dt/        |       }| j                   j	                  |       d{    | j                   j                          d{   \  }}|t        j0                  ||      st        d| d|       |st        d      ||j2                  fS 7 m7 Mw)z5Perform the authorization redirect and get auth code.N6No redirect URIs provided for authorization code grantz9No redirect handler provided for authorization code grantz9No callback handler provided for authorization code grantz
/authorizez*No client info available for authorization    coder   S256)response_typer   redirect_uristater2   code_challenge_methodr   scope?zState parameter mismatch: z != zNo authorization code received)r   ri   redirect_urisr   rk   rl   rq   authorization_endpointrR   r|   rh   r   rc   r,   rK   r6   token_urlsafer   r2   r   rs   r   r   r   compare_digestr1   )	rZ   auth_endpointauth_base_urlpkce_paramsr   auth_paramsauthorization_urlr   returned_states	            r=   r   z5OAuthClientProvider._perform_authorization_code_grant4  sO    <<''55= !YZZ||,, !\]]||,, !\]]<<&&4<<+F+F+]+] ; ; R RSM LLCCDLLD[D[\M#M<@M||'' !MNN %--/%%b) $11;; < < J J1 MN)88%+
 <<55dll6S6ST&*ll&C&C&EK
#<<''--#'<<#?#?#E#EK ,oQy/E.FGll++,=>>> +/,,*G*G*I$I!	>!)?)?PU)V #=n=MTRWQX!YZZ !ABB +3333 	? %Js%   I+K-K.!KKAKKc                 >   | j                   j                  rK| j                   j                  j                  r+t        | j                   j                  j                        }|S | j                   j	                  | j                   j
                        }t        |d      }|S )N/token)r   rq   token_endpointrR   r|   rh   r   )rZ   	token_urlr   s      r=   _get_token_endpointz'OAuthClientProvider._get_token_endpointi  su    <<&&4<<+F+F+U+UDLL77FFGI  !LLCCDLLD[D[\Mx8IrL   )
token_datar   r1   r   c                  K   | j                   j                  j                  t        d      | j                   j                  st        d      | j                         }|xs i }|j                  d|t        | j                   j                  j                  d         | j                   j                  j                  |d       | j                   j                  | j                   j                        r| j                   j                         |d<   ddi}| j                   j                  ||      \  }}t        j                  d	|||
      S w)z9Build token exchange request for authorization_code flow.r   zMissing client infoauthorization_coder   )
grant_typer   r   r   r1   r   Content-Type!application/x-www-form-urlencodedPOSTr   r   )r   ri   r   r   rc   r   updaterR   r   r   rs   r   r   httpxRequest)rZ   r   r1   r   r   r   s         r=   r   z6OAuthClientProvider._exchange_token_authorization_codeq  s     <<''55= !YZZ||'' !677,,.	%2
2! #DLL$@$@$N$Nq$Q R!\\55??!.	
 <<55dll6S6ST%)\\%B%B%DJz" "#FG"ll==j'R
G}}VYZQQs   E
Ec                   K   |j                   dk7  rD|j                          d{   }|j                  d      }t        d|j                    d|       t	        |       d{   }|| j
                  _        | j
                  j                  |       | j
                  j                  j                  |       d{    y7 7 `7 	w)zHandle token exchange response.r   Nzutf-8zToken exchange failed (z): )
r   r   rH   r   r   r   rt   r   rj   r`   )rZ   r   body	body_texttoken_responses        r=   _handle_token_responsez*OAuthClientProvider._handle_token_response  s     3&!))DG,I!$;H<P<P;QQTU^T_"`aa  <HEE '5#((8ll""--n=== *
 F
 	>s4   #C	C>C	$C%AC	=C>C	C	C	c                   K   | j                   j                  r | j                   j                  j                  st        d      | j                   j                  r | j                   j                  j
                  st        d      | j                   j                  rJ| j                   j                  j                  r*t        | j                   j                  j                        }n;| j                   j                  | j                   j                        }t        |d      }d| j                   j                  j                  | j                   j                  j
                  d}| j                   j                  | j                   j                        r| j                   j                         |d<   ddi}| j                   j                  ||      \  }}t!        j"                  d	|||
      S w)zBuild token refresh request.zNo refresh token availablezNo client info availabler   r   )r   r   r   r   r   r   r   r   )r   rt   r   r   rc   r   rq   r   rR   r|   rh   r   r   rs   r   r   r   r   )rZ   r   r   refresh_datar   s        r=   _refresh_tokenz"OAuthClientProvider._refresh_token  sc    ||**$,,2M2M2[2[!">??||''t||/G/G/Q/Q!"<==<<&&4<<+F+F+U+UDLL77FFGI LLCCDLLD[D[\Mx8I *!\\88FF11;;(
 <<55dll6S6ST'+||'D'D'FL$ "#FG $ ? ?g Vg}}VY\7SSs   G(G*c                 6  K   |j                   dk7  r=t        j                  d|j                           | j                  j	                          y	 |j                          d{   }t        j                  |      }|| j                  _        | j                  j                  |       | j                  j                  j                  |       d{    y7 s7 # t        $ r2 t        j                  d       | j                  j	                          Y yw xY ww)z:Handle token refresh response. Returns True if successful.r   zToken refresh failed: FNTzInvalid refresh response)r   r   r   r   r   r   r&   r   rt   r   rj   r`   r   	exception)rZ   r   r   r   s       r=   _handle_refresh_responsez,OAuthClientProvider._handle_refresh_response  s     3&NN3H4H4H3IJKLL%%'	$NN,,G';;GDN*8DLL'LL,,^<,,&&11.AAA -
 B  	78LL%%'	sO   ADC #C$A-C CC DC C 8DDDDc                   K   | j                   j                  j                          d{   | j                   _        | j                   j                  j	                          d{   | j                   _        d| _        y7 V7 w)z#Load stored tokens and client info.NT)r   rj   r[   rt   rb   rc   r   rY   s    r=   _initializezOAuthClientProvider._initialize  s\     ,0LL,@,@,K,K,M&M#)-)=)=)M)M)O#O   'N#Os!   (BB:B%B&BBr   c                     | j                   j                  rR| j                   j                  j                  r1d| j                   j                  j                   |j                  d<   yyy)z<Add authorization header to request if we have valid tokens.zBearer r   N)r   rt   r   r   )rZ   r   s     r=   _add_auth_headerz$OAuthClientProvider._add_auth_header  sP    <<&&4<<+F+F+S+S189T9T9a9a8b/cGOOO, ,T&rL   c                    K   |j                          d {   }t        j                  |      }|| j                  _        y 7 +wr   )r   r%   r   r   rq   r   s       r=   _handle_oauth_metadata_responsez3OAuthClientProvider._handle_oauth_metadata_response  s6      (( 44W=&.# )s   AA,Ac                  K   | j                   j                  4 d{    | j                  s| j                          d{    |j                  j                  t              | j                   _        | j                   j                         sW| j                   j                         r=| j                          d{   }|}| j                  |       d{   sd| _        | j                   j                         r| j                  |       |}|j                  dk(  r	 t        |      }t        || j                   j                         }|D ]  }t#        |      }|}	t%        |	       d{   }
|
rT|
| j                   _        t)        |
j*                        dkD  sJ t-        |
j*                  d         | j                   _         nt0        j3                  d|         t5        | j                   j.                  | j                   j                         }|D ][  }t#        |      }|}t7        |       d{   \  }}|s n1|r|r|| j                   _         nt0        j3                  d|        ] t;        t=        |      | j                   j&                  | j                   j8                        | j                   j>                  _         | j                   jB                  stE        | j                   j8                  | j                   jF                        rt0        j3                  d| j                   jF                          tI        | j                   jF                  | j                   j>                  jJ                        }|| j                   _!        | j                   jL                  jO                  |       d{    ntQ        | j                   j8                  | j                   j>                  | j                   jS                  | j                   j                               }|}tU        |       d{   }|| j                   _!        | j                   jL                  jO                  |       d{    | jW                          d{   }| jY                  |       d{    | j                  |       | n|j                  d
k(  rt_        |d      }|dk(  rw	 t;        t=        |      | j                   j&                        | j                   j>                  _         | jW                          d{   }| jY                  |       d{    | j                  |       | ddd      d{    y7 m7 L7 7 7 "7 Y7 7 a7 &7 7 # tZ        $ r t0        j]                  d	        w xY w7 7 p# tZ        $ r t0        j]                  d	        w xY w7 o# 1 d{  7  sw Y   yxY ww)zHTTPX auth flow integration.NFi  r   z.Protected resource metadata discovery failed: z!OAuth metadata discovery failed: z"Using URL-based client ID (CIMD): )r   zOAuth flow errori  errorinsufficient_scope)0r   rw   r   r   r   getr"   rs   r   r   r   r   r   r   r   r   rh   r   r   rp   lenr   rR   rr   r   r   r   r   rq   r   r   ri   r   rc   r!   ro   r   r   rj   re   r   r|   r   r   r   	Exceptionr   r   )rZ   r   refresh_requestrefresh_responser   www_auth_resource_metadata_urlprm_discovery_urlsr   discovery_requestdiscovery_responseprmasm_discovery_urlsoauth_metadata_requestoauth_metadata_responseokasmclient_informationregistration_requestregistration_responser   r  s                        r=   async_auth_flowz#OAuthClientProvider.async_auth_flow  s/    <<$$ D	 D	$$&&((( -4OO,?,?@T,UDLL)<<..0T\\5S5S5U(,(;(;(="=)8#8 !::;KLLL(-D%||**,%%g.$}H##s*S5\]e5f2 *Z68O8O*&  2 a,I#,N)3D-D*$FGY$ZZGJDLLD !$C$=$= > B B <?s?X?XYZ?[;\DLL8!"LL+YZ]Y^)_`#a& *b44dll6M6M*&
  2 T1Ns1S.8N2N/(EF](^"^C!!#:=DLL7!"LL+LSE)RST :T3H=@@33:DLL006  <<339 LL779Y9Y #LL+MdllNnNnMo)pq1U $ @ @.2ll.J.J.X.X2. 8JDLL4"&,,"6"6"F"FGY"ZZZ 4V $ ; ; $ < < $ G GH_H_ `40
 ;O4N17STi7j1j.7IDLL4"&,,"6"6"F"FGY"ZZZ 261L1L1N+N%NN55nEEE %%g.%%,3HgF 00=W7A4<<CkCk>44:
 6:5P5P5R/R)R"99.III %%g.ID	 D	 D	( #> M2 [. #_8 [ 2kZ ,OE  $$%78( 0SI$ (();<}D	 D	 D	 D	sS  XV
X W6VA9W6;V<W6VAW6&AV*4V5CV* VFV*VA:V*>V?=V*<V"=V*V%V*0V(1V*57W6-AWWWWW#W69XW4XW6W6W6V*V*V*V*"V*%V*(V** W

W6WW W11W64X6X<W?=XX)NNrm   Nr   ) rN   rO   rP   rQ   requires_response_bodyrR   r$   rW   r   r   r   r   r   r   Responser   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r  rU   rL   r=   r   r      s   
 " EISW*.+"+" -+" 	+"
 #C5)D/#9:TA+" #2ysC$J1G'H#HIDP+" +" !4Z+"Z%.. UY @emm 34sCx 34jS  Z\RR-0RAEc3hRVAVR	R>>U^^ > >Temm T<u~~ $ *!d d$ d
/enn /QU /
FU]] F~emm]b]k]kNk?l FrL   r   )CrQ   rF   rB   loggingr6   r8   r   collections.abcr   r   r   dataclassesr   r   typingr   r	   urllib.parser
   r   r   r   r   r   pydanticr   r   r   mcp.client.auth.exceptionsr   r   mcp.client.auth.utilsr   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   mcp.client.streamable_httpr"   mcp.shared.authr#   r$   r%   r&   r'   mcp.shared.auth_utilsr(   r)   r*   	getLoggerrN   r   r,   rW   rg   Authr   rU   rL   r=   <module>r'     s          ? ? (   < <   6 6 F    " <   
		8	$OY O8 ( y y yxO%** OrL   