Xj%/ DddlZddlZddlmZmZddlmZmZddlm Z m Z ddl m Z m Z ddlmZddlmZmZmZmZmZddlmZej0eZd ed ed edzfd Zd ed edzfd Zd ed edzfdZdedzded eefdZ d(dedzdedzdedzd edzfdZ!dedzded eefdZ"d ed edzfdZ#d ed e$e%edzffdZ&ded efdZ'dedzdeded efdZ(d ed efd Z)dedzd e%fd!Z*d"edzd#edzd e%fd$Z+ d(d#ed%ee dzd efd&Z,d ed efd'Z-y))N)urljoinurlparse)RequestResponse)AnyUrlValidationError)OAuthRegistrationErrorOAuthTokenError)MCP_PROTOCOL_VERSION)OAuthClientInformationFullOAuthClientMetadata OAuthMetadata OAuthTokenProtectedResourceMetadata)LATEST_PROTOCOL_VERSIONresponse field_namereturnc|jjd}|sy|d}tj||}|r$|j dxs|j dSy)z Extract field from WWW-Authenticate header. Returns: Field value if found in WWW-Authenticate header, None otherwise zWWW-AuthenticateNz=(?:"([^"]+)"|([^\s,]+)))headersgetresearchgroup)rrwww_auth_headerpatternmatchs i/mnt/ssd/data/Dropbox/adrian/vault-secondbrain/venv/lib/python3.12/site-packages/mcp/client/auth/utils.pyextract_field_from_www_authr!sa&&**+=>O 56G IIg /E {{1~/Q/ ct|dS)z Extract scope parameter from WWW-Authenticate header as per RFC6750. Returns: Scope string if found in WWW-Authenticate header, None otherwise scope)r!rs r extract_scope_from_www_authr&,s 'x 99r"c>|r|jdk7ryt|dS)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 iNresource_metadata) status_coder!r%s r 'extract_resource_metadata_from_www_authr*6s% x++s2 &x1D EEr" www_auth_url server_urlc@g}|r|j|t|}|jd|j}|jr9|jdk7r*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)appendrschemenetlocpathr)r+r,urlsparsedbase_urlpath_based_urlroot_based_urls r 0build_protected_resource_metadata_discovery_urlsr9Cs D L!j !F--FMM?3H{{v{{c) -RSYS^S^R_+`a N#X'NONKK Kr"www_authenticate_scopeprotected_resource_metadataauthorization_server_metadatac||S|'|jdj|jS|'|jdj|jSy)zLSelect scopes as outlined in the 'Scope Selection Strategy' in the MCP spec.N )scopes_supportedjoin)r:r;r<s r get_client_metadata_scopesrAise)%% $ 05P5a5a5mxx3DDEE & 27T7e7e7qxx5FFGGr"auth_server_urlc|s(t|}|jd|jdgSg}t|}|jd|j}|jr|jdk7rd|jj d}|j t ||d|jj d}|j t |||jj dd}|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)rr1r2r3rstripr0r)rBr,r5r4r6 oauth_path oidc_paths r 8build_oauth_authorization_server_metadata_discovery_urlsrGs6 *%==/V]]O3Z[\\D o &F--FMM?3H{{v{{c)>v{{?Q?QRU?V>WX  GHj128 8J8J38O7PQ  GHi01{{))#.//PQ  GHi01  KK"KLM KK"EFG Kr"cK|jdk(r0 |jd{}tj|}|Sy7#t$rYywxYww)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)areadrmodel_validate_jsonr)rcontentmetadatas r "handle_protected_resource_responserNs\s" $NN,,G0DDWMHO-  s8AAAAAA AAAAcK|jdk(r2 |jd{}tj|}d|fS|jdks|jdk\ryy7=#t$rYywxYww)NrIT)TNii)FN)r)rJrrKr)rrLasms r handle_auth_metadata_responserQs}s" $NN,,G33GU'V WWr"auth_server_metadataclient_metadata auth_base_urlc|r"|jrt|j}n t|d}|jddd}t d||ddiS) z9Build registration request or skip if already registered.z /registerTjson)by_aliasmode exclude_nonePOSTz Content-Typezapplication/json)rZr)registration_endpointstrr model_dumpr)rVrWrXregistration_urlregistration_datas r "create_client_registration_requestrdsa  4 J J3IIJ"=+>'22Dv\`2a 6+2Cn^pMq rrr"cFK|jdvr=|jd{td|jd|j |jd{}t j |}|S7Y7#t $r}td|d}~wwxYww)zHandle registration response.)rINzRegistration failed: r>zInvalid registration response: )r)rJr textr rKr)rrL client_infoes r handle_registration_responserjs:-nn$')B!B"B#B=B!B B BBB!c||sy t|}|jdk(xr|jdvS#t$rYywxYw)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 Fhttps)r/)rr1r3 Exception)rRr5s r is_valid_client_metadata_urlrosG #}}'HFKKy,HH s )/ ;;oauth_metadataclient_metadata_urlc*|sy|sy|jduS)aDetermine 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)rprqs r should_use_client_metadata_urlrt s!"    ? ?4 GGr" redirect_urisct|d|S)aCreate 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_idtoken_endpoint_auth_methodru)r )rqrus r $create_client_info_from_metadata_urlrz$s &%#)# r"cK |jd{}tj|}|S7#t$r}t d|d}~wwxYww)avParse 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 NzInvalid token response: )rJrrKrr )rrLtoken_responseris r handle_token_response_scopesr};sY > ((#77@) > 8<==>s0A535A5 AA  AA)N).loggingr urllib.parserrhttpxrrpydanticrrmcp.client.authr r mcp.client.streamable_httpr mcp.shared.authr r rrr mcp.typesr getLogger__name__loggerr`r!r&r*listr9rArGrNtupleboolrQrUrdrjrortrzr}r"r rs7 *#,C;.   8 $(d ,:(:sTz: Fh F3: F#3:#[^#cghkcl#R;?$J!:T!A$14#7 4Z 0)cTXj)fi)nrsvnw)X%2 ( uT=[_K_E_?` XsXwX s'$. sAT seh s  s L L>X L cDjT(H!D(HtH H6DH-1&\D-@.>>>r"