o
    iB                     @  s   d Z ddlmZ ddlmZmZ ddl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 dd	lmZ dd
lmZ ddlmZ ddlmZmZ erZddlmZ ddlmZ eeZ G dd deZ!G dd deZ"dS )zAzure (Microsoft Entra) OAuth provider for FastMCP.

This provider implements Azure/Microsoft Entra ID OAuth authentication
using the OAuth Proxy pattern for non-DCR OAuth flows.
    )annotations)TYPE_CHECKINGAny)AsyncKeyValue)	SecretStrfield_validator)BaseSettingsSettingsConfigDict)
OAuthProxy)JWTVerifier)ENV_FILEparse_scopes)
get_logger)NotSetNotSetT)AuthorizationParams)OAuthClientInformationFullc                   @  s   e Zd ZU dZededdZdZded< dZ	ded	< dZ
ded
< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< dZded< eddded ddZeddded ddZdS )!AzureProviderSettingsz"Settings for Azure OAuth provider.FASTMCP_SERVER_AUTH_AZURE_ignore)
env_prefixenv_fileextraNz
str | None	client_idzSecretStr | Noneclient_secret	tenant_ididentifier_uribase_url
issuer_urlredirect_pathlist[str] | Nonerequired_scopesadditional_authorize_scopesallowed_client_redirect_urisjwt_signing_keylogin.microsoftonline.comstrbase_authoritybefore)modevobjectreturnc                 C     t |S Nr   clsr+    r2   i/var/www/html/karishye-ai-python/venv/lib/python3.10/site-packages/fastmcp/server/auth/providers/azure.py_parse_scopes3      z#AzureProviderSettings._parse_scopesc                 C  r.   r/   r   r0   r2   r2   r3   "_parse_additional_authorize_scopes8   r5   z8AzureProviderSettings._parse_additional_authorize_scopes)r+   r,   r-   r!   )__name__
__module____qualname____doc__r	   r   model_configr   __annotations__r   r   r   r   r   r    r"   r#   r$   r%   r(   r   classmethodr4   r6   r2   r2   r2   r3   r      s2   
 

r   c                      s^   e Zd ZdZeeeeeeeeeedededd* fddZd+ fd#d$Zd, fd(d)Z  ZS )-AzureProvideru
  Azure (Microsoft Entra) OAuth provider for FastMCP.

    This provider implements Azure/Microsoft Entra ID authentication using the
    OAuth Proxy pattern. It supports both organizational accounts and personal
    Microsoft accounts depending on the tenant configuration.

    Scope Handling:
    - required_scopes: Provide unprefixed scope names (e.g., ["read", "write"])
      → Automatically prefixed with identifier_uri during initialization
      → Validated on all tokens and advertised to MCP clients
    - additional_authorize_scopes: Provide full format (e.g., ["User.Read"])
      → NOT prefixed, NOT validated, NOT advertised to clients
      → Used to request Microsoft Graph or other upstream API permissions

    Features:
    - OAuth proxy to Azure/Microsoft identity platform
    - JWT validation using tenant issuer and JWKS
    - Supports tenant configurations: specific tenant ID, "organizations", or "consumers"
    - Custom API scopes and Microsoft Graph scopes in a single provider

    Setup:
    1. Create an App registration in Azure Portal
    2. Configure Web platform redirect URI: http://localhost:8000/auth/callback (or your custom path)
    3. Add an Application ID URI under "Expose an API" (defaults to api://{client_id})
    4. Add custom scopes (e.g., "read", "write") under "Expose an API"
    5. Set access token version to 2 in the App manifest: "requestedAccessTokenVersion": 2
    6. Create a client secret
    7. Get Application (client) ID, Directory (tenant) ID, and client secret

    Example:
        ```python
        from fastmcp import FastMCP
        from fastmcp.server.auth.providers.azure import AzureProvider

        # Standard Azure (Public Cloud)
        auth = AzureProvider(
            client_id="your-client-id",
            client_secret="your-client-secret",
            tenant_id="your-tenant-id",
            required_scopes=["read", "write"],  # Unprefixed scope names
            additional_authorize_scopes=["User.Read", "Mail.Read"],  # Optional Graph scopes
            base_url="http://localhost:8000",
            # identifier_uri defaults to api://{client_id}
        )

        # Azure Government
        auth_gov = AzureProvider(
            client_id="your-client-id",
            client_secret="your-client-secret",
            tenant_id="your-tenant-id",
            required_scopes=["read", "write"],
            base_authority="login.microsoftonline.us",  # Override for Azure Gov
            base_url="http://localhost:8000",
        )

        mcp = FastMCP("My App", auth=auth)
        ```
    NT)r   r   r   r   r   r   r    r"   r#   r$   client_storager%   require_authorization_consentr(   r   str | NotSetTr   r   r   str | NotSetT | Noner   r   r    r"   list[str] | NotSetT | Noner#   r$   list[str] | NotSetTr?   AsyncKeyValue | Noner%   str | bytes | NotSetTr@   boolr(   r-   Nonec                  s  t dd |||||||||	|
||d D }|js"d}t||js+d}t||js4d}t||js=d}t||jpEd|j | _|j	pKg | _	|j}|j
}d	| d
| d}d	| d
| d}t|||jd|jd}|jrx|j nd}d	| d
| d}d	| d
| d}t j|||j|||j|j|jp|j|j||j|d d}|dkrd| }td|j|| jrd| j nd| dS )u  Initialize Azure OAuth provider.

        Args:
            client_id: Azure application (client) ID from your App registration
            client_secret: Azure client secret from your App registration
            tenant_id: Azure tenant ID (specific tenant GUID, "organizations", or "consumers")
            identifier_uri: Optional Application ID URI for your custom API (defaults to api://{client_id}).
                This URI is automatically prefixed to all required_scopes during initialization.
                Example: identifier_uri="api://my-api" + required_scopes=["read"]
                → tokens validated for "api://my-api/read"
            base_url: Public URL where OAuth endpoints will be accessible (includes any mount path)
            issuer_url: Issuer URL for OAuth metadata (defaults to base_url). Use root-level URL
                to avoid 404s during discovery when mounting under a path.
            redirect_path: Redirect path configured in Azure App registration (defaults to "/auth/callback")
            base_authority: Azure authority base URL (defaults to "login.microsoftonline.com").
                For Azure Government, use "login.microsoftonline.us".
            required_scopes: Custom API scope names WITHOUT prefix (e.g., ["read", "write"]).
                - Automatically prefixed with identifier_uri during initialization
                - Validated on all tokens
                - Advertised in Protected Resource Metadata
                - Must match scope names defined in Azure Portal under "Expose an API"
                Example: ["read", "write"] → validates tokens containing ["api://xxx/read", "api://xxx/write"]
            additional_authorize_scopes: Microsoft Graph or other upstream scopes in full format.
                - NOT prefixed with identifier_uri
                - NOT validated on tokens
                - NOT advertised to MCP clients
                - Used to request additional permissions from Azure (e.g., Graph API access)
                Example: ["User.Read", "Mail.Read", "offline_access"]
                These scopes allow your FastMCP server to call Microsoft Graph APIs using the
                upstream Azure token, but MCP clients are unaware of them.
            allowed_client_redirect_uris: List of allowed redirect URI patterns for MCP clients.
                If None (default), all URIs are allowed. If empty list, no URIs are allowed.
            client_storage: Storage backend for OAuth state (client registrations, encrypted tokens).
                If None, a DiskStore will be created in the data directory (derived from `platformdirs`). The
                disk store will be encrypted using a key derived from the JWT Signing Key.
            jwt_signing_key: Secret for signing FastMCP JWT tokens (any string or bytes). If bytes are provided,
                they will be used as is. If a string is provided, it will be derived into a 32-byte key. If not
                provided, the upstream client secret will be used to derive a 32-byte key using PBKDF2.
            require_authorization_consent: Whether to require user consent before authorizing clients (default True).
                When True, users see a consent screen before being redirected to Azure.
                When False, authorization proceeds directly without user confirmation.
                SECURITY WARNING: Only disable for local development or testing environments.
        c                 S  s   i | ]\}}|t ur||qS r2   )r   ).0kr+   r2   r2   r3   
<dictcomp>   s
    z*AzureProvider.__init__.<locals>.<dictcomp>)r   r   r   r   r   r   r    r"   r#   r$   r%   r(   zPclient_id is required - set via parameter or FASTMCP_SERVER_AUTH_AZURE_CLIENT_IDzXclient_secret is required - set via parameter or FASTMCP_SERVER_AUTH_AZURE_CLIENT_SECRETztenant_id is required - set via parameter or FASTMCP_SERVER_AUTH_AZURE_TENANT_ID. Use your Azure tenant ID (found in Azure Portal), 'organizations', or 'consumers'a  required_scopes must include at least one scope - set via parameter or FASTMCP_SERVER_AUTH_AZURE_REQUIRED_SCOPES. Azure's OAuth API requires the 'scope' parameter in authorization requests. Use the unprefixed scope names from your Azure App registration (e.g., ['read', 'write'])zapi://zhttps:///z/v2.0z/discovery/v2.0/keysRS256)jwks_uriissueraudience	algorithmr"    z/oauth2/v2.0/authorizez/oauth2/v2.0/token)upstream_authorization_endpointupstream_token_endpointupstream_client_idupstream_client_secrettoken_verifierr   r    r   r$   r?   r%   r@   r&   z using authority zAInitialized Azure OAuth provider for client %s with tenant %s%s%sz and identifier_uri N)r   model_validateitemsr   
ValueErrorr   r   r"   r   r#   r(   r   get_secret_valuesuper__init__r   r    r   r$   r%   loggerinfo)selfr   r   r   r   r   r   r    r"   r#   r$   r?   r%   r@   r(   settingsmsgtenant_id_finalbase_authority_finalrO   rN   rW   client_secret_strauthorization_endpointtoken_endpointauthority_info	__class__r2   r3   r]   z   s   =

zAzureProvider.__init__clientr   paramsr   r'   c                   sv   |}t |dr"t|dd}|dur"|jddid}|r"td| t ||I dH }d|v r2dnd}| | dS )a  Start OAuth transaction and redirect to Azure AD.

        Override parent's authorize method to filter out the 'resource' parameter
        which is not supported by Azure AD v2.0 endpoints. The v2.0 endpoints use
        scopes to determine the resource/audience instead of a separate parameter.

        Args:
            client: OAuth client information
            params: Authorization parameters from the client

        Returns:
            Authorization URL to redirect the user to Azure AD
        resourceN)updatezNFiltering out 'resource' parameter '%s' for Azure AD v2.0 (use scopes instead)?&zprompt=select_account)hasattrgetattr
model_copyr^   debugr\   	authorize)r`   rk   rl   params_to_useoriginal_resourceauth_url	separatorri   r2   r3   ru   %  s   
zAzureProvider.authorizetxn_idtransactiondict[str, Any]c                   s   | dp	| jp	g }g }|D ]}d|v sd|v r|| q|| j d|  q| jr3|| j | }||d< t ||S )zBuild Azure authorization URL with prefixed scopes.

        Overrides parent to prefix scopes with identifier_uri before sending to Azure,
        while keeping unprefixed scopes in the transaction for MCP clients.
        scopesz://rL   )	getr"   appendr   r#   extendcopyr\   _build_upstream_authorize_url)r`   rz   r{   unprefixed_scopesprefixed_scopesscopemodified_transactionri   r2   r3   r   J  s   	z+AzureProvider._build_upstream_authorize_url)r   rA   r   rA   r   rA   r   rB   r   rA   r   rA   r    rA   r"   rC   r#   rC   r$   rD   r?   rE   r%   rF   r@   rG   r(   rA   r-   rH   )rk   r   rl   r   r-   r'   )rz   r'   r{   r|   r-   r'   )	r7   r8   r9   r:   r   r]   ru   r   __classcell__r2   r2   ri   r3   r>   >   s(    > ,%r>   N)#r:   
__future__r   typingr   r   key_value.aio.protocolsr   pydanticr   r   pydantic_settingsr   r	   fastmcp.server.auth.oauth_proxyr
   !fastmcp.server.auth.providers.jwtr   fastmcp.settingsr   fastmcp.utilities.authr   fastmcp.utilities.loggingr   fastmcp.utilities.typesr   r   mcp.server.auth.providerr   mcp.shared.authr   r7   r^   r   r>   r2   r2   r2   r3   <module>   s$    !