
    {hY                        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Zddlm	Z	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 ddlZddlZddlmZ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$m%Z% ddl&m'Z'  ejP                  e)      Z* G d de+      Z, G d de,      Z- G d de,      Z. G d de      Z/ G d de      Z0e G d d             Z1 G d dejd                        Z3y)z|
OAuth2 Authentication implementation for HTTPX.

Implements authorization code flow with PKCE and automatic token refresh.
    N)AsyncGenerator	AwaitableCallable)	dataclassfield)Protocol)	urlencodeurljoinurlparse)	BaseModelFieldValidationError)MCP_PROTOCOL_VERSION)OAuthClientInformationFullOAuthClientMetadataOAuthMetadata
OAuthTokenProtectedResourceMetadata)check_resource_allowedresource_url_from_server_url)LATEST_PROTOCOL_VERSIONc                       e Zd ZdZy)OAuthFlowErrorz%Base exception for OAuth flow errors.N__name__
__module____qualname____doc__     P/var/www/html/hubwallet-dev/venv/lib/python3.12/site-packages/mcp/client/auth.pyr   r   %   s    /r    r   c                       e Zd ZdZy)OAuthTokenErrorz"Raised when token operations fail.Nr   r   r    r!   r#   r#   )   s    ,r    r#   c                       e Zd ZdZy)OAuthRegistrationErrorz&Raised when client registration fails.Nr   r   r    r!   r%   r%   -   s    0r    r%   c                   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     r!   	<genexpr>z*PKCEParameters.generate.<locals>.<genexpr>:   s/     rbcv/C/Cfmm/SV\/\ ]rs   AAr)   =)r,   r-   )
joinrangehashlibsha256encodedigestbase64urlsafe_b64encodedecoderstrip)clsr,   r?   r-   s       r!   generatezPKCEParameters.generate7   sp     rglmpgqrr 4 4 67>>@11&9@@BII#N~NNr    N)returnr'   )r   r   r   r   r   r,   str__annotations__r-   classmethodrE   r   r    r!   r'   r'   1   s?    8srcBM3BsCNCCO Or    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.rF   Nc                    K   yw)zGet stored tokens.Nr   selfs    r!   
get_tokenszTokenStorage.get_tokensC   	        tokensc                    K   yw)zStore tokens.Nr   )rN   rR   s     r!   
set_tokenszTokenStorage.set_tokensG   rP   rQ   c                    K   yw)zGet stored client information.Nr   rM   s    r!   get_client_infozTokenStorage.get_client_infoK   rP   rQ   client_infoc                    K   yw)zStore client information.Nr   )rN   rW   s     r!   set_client_infozTokenStorage.set_client_infoO   rP   rQ   )
r   r   r   r   r   rO   rT   r   rV   rY   r   r    r!   rK   rK   @   sP    5*t"3 z d 'AD'H 1K PT r    rK   c                      e Zd ZU dZeed<   eed<   eed<   eege	d   f   ed<   eg e	e
eedz  f      f   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<    eej4                        Zej4                  ed<   dZedz  ed<   dZedz  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%y) OAuthContextzOAuth flow context.
server_urlclient_metadatastorageNredirect_handlercallback_handler     r@timeoutprotected_resource_metadataoauth_metadataauth_server_urlprotocol_versionrW   current_tokenstoken_expiry_time)default_factorylockdiscovery_base_urldiscovery_pathnamerF   c                 N    t        |      }|j                   d|j                   S )z,Extract base URL by removing path component.://)r   schemenetloc)rN   r\   parseds      r!   get_authorization_base_urlz'OAuthContext.get_authorization_base_urls   s%    *%--FMM?33r    tokenc                 x    |j                   r't        j                         |j                   z   | _        yd| _        y)zUpdate token expiry time.N)
expires_intimerh   )rN   rs   s     r!   update_token_expiryz OAuthContext.update_token_expiryx   s,    %)YY[53C3C%CD"%)D"r    c                     t        | j                  xrH | j                  j                  xr0 | j                   xs! t	        j                         | j                  k        S )z Check if current token is valid.)boolrg   access_tokenrh   rv   rM   s    r!   is_token_validzOAuthContext.is_token_valid   sU     V##00V+++Ttyy{d>T>T/T
 	
r    c                 x    t        | j                  xr$ | j                  j                  xr | j                        S )z Check if token can be refreshed.)ry   rg   refresh_tokenrW   rM   s    r!   can_refresh_tokenzOAuthContext.can_refresh_token   s0    D''bD,?,?,M,MbRVRbRbccr    c                      d| _         d| _        y)zClear current tokens.N)rg   rh   rM   s    r!   clear_tokenszOAuthContext.clear_tokens   s    "!%r    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   r\   rc   resourcerG   r   )rN   r   prm_resources      r!   get_resource_urlzOAuthContext.get_resource_url   sV    
 0@ ++0P0P0Y0Yt??HHIL%Wcd'r    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)rc   )rN   rf   s     r!   should_include_resource_paramz*OAuthContext.should_include_resource_param   s(     ++7    <//r    rF   N)N)&r   r   r   r   rG   rH   r   rK   r   r   tuplerb   floatrc   r   rd   r   re   rf   rW   r   rg   r   rh   r   anyioLockrj   rk   rl   rr   rw   ry   r{   r~   r   r   r   r   r    r!   r[   r[   T   sm   O((uio566r9U3d
?-C#DDEEGU EI!:T!AH+/NMD(/"&OS4Z&#'cDj' 6:K+d29 )-NJ%,&*ut|* UZZ8D%**8 &*d
)%)d
)4S 4S 4
* * *
 
d4 d&
# 0cDj 0TX 0r    r[   c                      e Zd ZdZdZ	 d"dedededeege	d   f   deg e	e
eedz  f      f   d	efd
Zdej                  dedz  fdZdej                  dej                   fdZdej                  ddfdZdee   fdZdej                   dz  fdZdej                  ddfdZde
eef   fdZdede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dej                   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.
    Tr\   r]   r^   r_   Nr`   rb   c                 >    t        ||||||      | _        d| _        y)z!Initialize OAuth2 authentication.)r\   r]   r^   r_   r`   rb   FN)r[   context_initialized)rN   r\   r]   r^   r_   r`   rb   s          r!   __init__zOAuthClientProvider.__init__   s,     $!+--
 "r    init_responserF   c                     |r|j                   dk7  ry|j                  j                  d      }|syd}t        j                  ||      }|r$|j                  d      xs |j                  d      S y)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
          NzWWW-Authenticatez)resource_metadata=(?:"([^"]+)"|([^\s,]+))      )status_codeheadersgetresearchgroup)rN   r   www_auth_headerpatternmatchs        r!   (_extract_resource_metadata_from_www_authz<OAuthClientProvider._extract_resource_metadata_from_www_auth   sl      9 9S @'//334FG ?		'?3;;q>3U[[^3r    c                    K   | j                  |      }|s;| j                  j                  | j                  j                        }t	        |d      }t        j                  d|t        t        i      S w)Nz%/.well-known/oauth-protected-resourceGETr   )	r   r   rr   r\   r
   httpxRequestr   r   )rN   r   urlauth_base_urls       r!   _discover_protected_resourcez0OAuthClientProvider._discover_protected_resource   s^     ;;MJ LLCCDLLD[D[\M-)PQC}}UC2FH_1`aas   A1A3responsec                 4  K   |j                   dk(  rt	 |j                          d{   }t        j                  |      }|| j                  _        |j                  r(t        |j                  d         | j                  _        yyy7 `# t        $ r Y yw xY ww)zHandle discovery response.   Nr   )
r   areadr   model_validate_jsonr   rc   authorization_serversrG   re   r   rN   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 2 '0
 # s9   BB	 BAB	 BB	 		BBBBc                    g }| j                   j                  xs | j                   j                  }t        |      }|j                   d|j
                   }|j                  rH|j                  dk7  r9d|j                  j                  d       }|j                  t        ||             |j                  t        |d             |j                  rH|j                  dk7  r9d|j                  j                  d       }|j                  t        ||             |j                  d       d}|j                  |       |S )zCGenerate ordered list of (url, type) tuples for discovery attempts.rn   /z'/.well-known/oauth-authorization-serverz!/.well-known/openid-configuration)
r   re   r\   r   ro   rp   pathrC   appendr
   )rN   urlsre   rq   base_url
oauth_path	oidc_pathoidc_fallbacks           r!   _get_discovery_urlsz'OAuthClientProvider._get_discovery_urls   s   ,,66Q$,,:Q:Q/*mm_C7 ;;6;;#-B6;;CUCUVYCZB[\JKK*56 	GH&OPQ ;;6;;#-;FKK<N<Ns<S;TUIKK)45 +11#677XYM"r    c                   K   | j                   j                  ry| j                   j                  rJ| j                   j                  j                  r*t	        | j                   j                  j                        }n;| j                   j                  | j                   j                        }t        |d      }| j                   j                  j                  ddd      }t        j                  d||ddi	      S w)
z9Build registration request or skip if already registered.Nz	/registerTjson)by_aliasmodeexclude_nonePOSTContent-Typezapplication/json)r   r   )r   rW   rd   registration_endpointrG   rr   r\   r
   r]   
model_dumpr   r   )rN   registration_urlr   registration_datas       r!   _register_clientz$OAuthClientProvider._register_client  s     <<##<<&&4<<+F+F+\+\"4<<#>#>#T#TU LLCCDLLD[D[\M&}kB LL88CCTX^mqCr}}$+<~WiFj
 	
s   C6C8c                   K   |j                   dvr=|j                          d{    t        d|j                    d|j                         	 |j                          d{   }t	        j
                  |      }|| j                  _        | j                  j                  j                  |       d{    y7 7 Z7 	# t        $ r}t        d|       d}~ww xY ww)zHandle registration response.)r      NzRegistration failed:  zInvalid registration response: )r   r   r%   textr   r   r   rW   r^   rY   r   )rN   r   r   rW   es        r!   _handle_registration_responsez1OAuthClientProvider._handle_registration_response*  s     z1.."""(+@AUAU@VVWX`XeXeWf)ghh	P$NN,,G4HHQK'2DLL$,,&&66{CCC # - D 	P(+J1#)NOO	PsX   "C B;)C C "B=#AC 5B?6C :C =C ?C 	C
CCC c                   K   | 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.z
/authorizez*No client info available for authorization    coder   S256)response_type	client_idredirect_uristater-   code_challenge_methodr   scope?NzState parameter mismatch: z != zNo authorization code received)r   rd   authorization_endpointrG   rr   r\   r
   rW   r   r'   rE   r1   token_urlsafer   r]   redirect_urisr-   r   rf   r   r   r	   r_   r`   compare_digestr,   )	rN   auth_endpointr   pkce_paramsr   auth_paramsauthorization_url	auth_codereturned_states	            r!   _perform_authorizationz*OAuthClientProvider._perform_authorization8  s    <<&&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%   G>I2 I.!I2"I0#AI20I2r   r,   c                 v  K   | j                   j                  st        d      | j                   j                  rJ| j                   j                  j                  r*t        | j                   j                  j                        }n;| j                   j                  | j                   j                        }t        |d      }d|t        | j                   j                  j                  d         | j                   j                  j                  |d}| j                   j                  | j                   j                        r| j                   j                         |d<   | j                   j                  j                  r#| j                   j                  j                  |d<   t!        j"                  d||d	d
i      S w)zBuild token exchange request.zMissing client info/tokenauthorization_coder   )
grant_typer   r   r   r,   r   client_secretr   r   !application/x-www-form-urlencodeddatar   )r   rW   r   rd   token_endpointrG   rr   r\   r
   r]   r   r   r   rf   r   r   r   r   )rN   r   r,   	token_urlr   
token_datas         r!   _exchange_tokenz#OAuthClientProvider._exchange_tokenf  sF    ||'' !677<<&&4<<+F+F+U+UDLL77FFGI LLCCDLLD[D[\Mx8I / < < J J1 MN11;;*

 <<55dll6S6ST%)\\%B%B%DJz"<<##11*.,,*B*B*P*PJ'}}IJIl8m
 	
s   F7F9c                   K   |j                   dk7  rt        d|j                          	 |j                          d{   }t        j                  |      }|j
                  r| j                  j                  j
                  rot        | j                  j                  j
                  j                               }t        |j
                  j                               }||z
  }|rt        d|       || j                  _
        | j                  j                  |       | j                  j                  j                  |       d{    y7 7 # t        $ r}t        d|       d}~ww xY ww)zHandle token exchange response.r   zToken exchange failed: Nz$Server granted unauthorized scopes: zInvalid token response: )r   r#   r   r   r   r   r   r]   setsplitrg   rw   r^   rT   r   )rN   r   r   token_responserequested_scopesreturned_scopesunauthorized_scopesr   s           r!   _handle_token_responsez*OAuthClientProvider._handle_token_response  s=    3&!$;H<P<P;Q"RSS	B$NN,,G';;GDN ##(D(D(J(J#&t||'C'C'I'I'O'O'Q#R "%n&:&:&@&@&B"C&58H&H#&),PQdPe*fgg*8DLL'LL,,^<,,&&11.AAA - B 	B!$<QC"@AA	BsK   (E1E EDE EE E1E E 	E.E))E..E1c                   K   | j                   j                  r | j                   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      }d| j                   j                  j                  | j                   j                  j                  d}| j                   j                  | j                   j                        r| j                   j                         |d<   | j                   j                  j                  r#| j                   j                  j                  |d<   t!        j"                  d||d	d
i      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   )r   rg   r}   r#   rW   rd   r   rG   rr   r\   r
   r   r   rf   r   r   r   r   )rN   r   r   refresh_datas       r!   _refresh_tokenz"OAuthClientProvider._refresh_token  sa    ||**$,,2M2M2[2[!">??||''!"<==<<&&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$<<##11,0LL,D,D,R,RL)}}IL>Kn:o
 	
s   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   loggerwarningr   r   r   r   r   rg   rw   r^   rT   r   	exception)rN   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   r^   rO   rg   rV   rW   r   rM   s    r!   _initializezOAuthClientProvider._initialize  s\     ,0LL,@,@,K,K,M&M#)-)=)=)M)M)O#O   'N#Os!   (BB:B%B&BBrequestc                     | 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 AuthorizationN)r   rg   rz   r   )rN   r  s     r!   _add_auth_headerz$OAuthClientProvider._add_auth_header  sP    <<&&4<<+F+F+S+S189T9T9a9a8b/cGOOO, ,T&r    r   c                 F    t        j                  d|t        t        i      S )Nr   r   )r   r   r   r   )rN   r   s     r!   _create_oauth_metadata_requestz2OAuthClientProvider._create_oauth_metadata_request  s    }}UC2FH_1`aar    c                 P  K   |j                          d {   }t        j                  |      }|| j                  _        | j                  j
                  j                  B|j                  5dj                  |j                        | j                  j
                  _        y y y 7 w)Nr   )	r   r   r   r   rd   r]   r   scopes_supportedr:   r   s       r!   _handle_oauth_metadata_responsez3OAuthClientProvider._handle_oauth_metadata_response  s      (( 44W=&.#<<''--5(:S:S:_14(:S:S1TDLL((. ;`5	 )s   B&B$BB&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;	 | j                  |       d{   }|}| j                  |       d{    | j!                         }|D ]c  }| j#                  |      }	|	}
|
j                  dk(  r	 | j%                  |
       d{     n"|
j                  dk  s|
j                  dk\  sc n | j)                          d{   }|r|}| j+                  |       d{    | j-                          d{   \  }}| j/                  ||       d{   }|}| j1                  |       d{    ddd      d{    | j                  |       | y7 j7 I7 7 7 Y7 >7 # t&        $ r Y 8w xY w7 7 7 7 s7 W# t2        $ r t4        j7                  d        w xY w7 l# 1 d{  7  sw Y   |xY ww)zHTTPX auth flow integration.NFr   r   i  i  zOAuth flow error)r   rj   r   r  r   r   r   rf   r{   r~   r   r  r  r   r   r   r   r
  r  r   r   r   r   r   r   	Exceptionr   r  )rN   r  refresh_requestrefresh_responser   discovery_requestdiscovery_responsediscovery_urlsr   oauth_metadata_requestoauth_metadata_responseregistration_requestregistration_responser   r,   token_requestr   s                    r!   async_auth_flowz#OAuthClientProvider.async_auth_flow  s    <<$$ <	 <	$$&&((( -4OO,?,?@T,UDLL)<<..0T\\5S5S5U(,(;(;(="=)8#8 !::;KLLL(-D%||**,%%g.$}H##s*% /3.O.OPX.Y(Y%/@)@&BBCUVVV &*%=%=%?N- "151T1TUX1Y.8N2N/2>>#E)&*&J&JKb&c c c % 5@@3FJaJmJmqtJt!" 261F1F1H+H(+6J0J-"@@AVWWW 6:5P5P5R/R,I} +/*>*>y-*X$XM+8%8N55nEEEs<	 <	~ 	g&A<	( #> M )ZV !d#2 ) () ,I X 0S %YE  $$%78u<	 <	 <	 <	sB  K/JK/ KJ
A9K;J<KJAK&J5:J;J5J>J5J,J-J1 J5J5(J+)J5J-	J5 J/!J5=J1>J5J3J5 K/+K,K/
KKKJ5J5J	J($J5'J((J5-J5/J51J53J55 KKK/K, K#!K,(K/)ra   r   )#r   r   r   r   requires_response_bodyrG   r   rK   r   r   r   r   r   r   Responser   r   r   r   listr   r   r   r   r   r   r   ry   r  r  r  r
  r  r   r  r   r    r!   r   r      s   
 " "" -" 	"
 #C5)D/#9:" #2ysC$J1G'H#HI" "(enn Y\_cYc 0	b 	bSXS`S` 	b
%.. 
UY 
T#Y 6
(< 
"PENN Pt P,4eCHo ,4\
s 
3 
5== 
<BU^^ B B.
emm 
>u~~ $ *!d d$ d
b# b%-- bUenn UQU UBU]] B~emm]b]k]kNk?l Br    r   )4r   r@   r<   loggingr   r1   r3   rv   collections.abcr   r   r   dataclassesr   r   typingr   urllib.parser	   r
   r   r   r   pydanticr   r   r   mcp.client.streamable_httpr   mcp.shared.authr   r   r   r   r   mcp.shared.auth_utilsr   r   	mcp.typesr   	getLoggerr   r   r  r   r#   r%   r'   rK   r[   Authr   r   r    r!   <module>r*     s       	    ? ? (  5 5   6 6 ;  W -			8	$0Y 0-n -1^ 1OY O8 ( [0 [0 [0|t%** tr    