aaron-y-chen opened a new pull request, #71920: URL: https://github.com/apache/airflow/pull/71920
related: #71735 ## Why In `apache-airflow-providers-fab==3.8.1rc1` (#71735), Azure AD token validation uses the configured tenant identifier directly as the expected `iss` claim. Per [Microsoft Entra ID guidance on validating the issuer](https://learn.microsoft.com/en-us/entra/identity-platform/access-tokens#validate-the-issuer), the token issuer must match the canonical `issuer` from the tenant's OpenID Connect metadata (which uses the canonical lowercase tenant GUID), causing deployments configured with domain names (e.g. `*.onmicrosoft.com` or custom domains) or uppercase GUIDs to fail login with `InvalidClaimError`. ## How to Reproduce In an environment with `apache-airflow-providers-fab==3.8.1rc1` installed, running token validation against domain or uppercase GUID authorities fails: ```python from types import SimpleNamespace from airflow.providers.fab.auth_manager.security_manager.override import ( FabAirflowSecurityManagerOverride as SecurityManager, ) from authlib.jose import JsonWebKey, jwt as authlib_jwt TENANT_GUID = "72f988bf-86f1-41af-91ab-2d7cd011db47" CLIENT_ID = "app-xyz" key = JsonWebKey.generate_key("RSA", 2048, options={"kid": "test-kid"}, is_private=True) public_key = key.as_dict(is_private=False, kid="test-kid") id_token = authlib_jwt.encode( {"alg": "RS256", "kid": "test-kid"}, { "iss": f"https://login.microsoftonline.com/{TENANT_GUID}/v2.0", "aud": CLIENT_ID, "tid": TENANT_GUID, "oid": "user-oid", }, key, ).decode() azure_remote = SimpleNamespace( client_kwargs={}, client_id=CLIENT_ID, api_base_url="https://login.microsoftonline.com/microsoft.onmicrosoft.com/oauth2/v2.0/", ) sm = SimpleNamespace( oauth_remotes={"azure": azure_remote}, _get_azure_tenant_id=lambda: SecurityManager._get_azure_tenant_id(sm), _get_microsoft_jwks=lambda: {"keys": [public_key]}, ) # Fails on 3.8.1rc1 with InvalidClaimError: invalid_claim: Invalid claim 'iss' SecurityManager._decode_and_validate_azure_jwt(sm, id_token) ``` ## Summary of Changes - **Canonicalize & Resolve Tenant GUIDs**: Added `_resolve_azure_tenant_guid()` to normalize GUIDs locally and resolve domain names to canonical tenant GUIDs via Microsoft OpenID Connect discovery (with in-memory caching). - **Strict Endpoint Parsing & Fail-Closed Security**: Replaced regex with `urllib.parse.urlsplit` to safely extract configured tenant identifiers from HTTPS `login.microsoftonline.com` endpoints, and added `AzureTenantResolutionError(FabException)` for discovery/validation failures. | Configured `tenant_identifier` | Resolution Strategy | `_resolve_azure_tenant_guid` Output | | :--- | :--- | :--- | | **Lowercase GUID** (`72f988bf-86f1-41af-91ab-2d7cd011db47`) | Validated & normalized locally (no HTTP call) | `72f988bf-86f1-41af-91ab-2d7cd011db47` | | **Uppercase GUID** (`72F988BF-86F1-41AF-91AB-2D7CD011DB47`) | Normalized to canonical lowercase (no HTTP call) | `72f988bf-86f1-41af-91ab-2d7cd011db47` | | **Default Domain** (`microsoft.onmicrosoft.com`) | Resolved via Microsoft OpenID discovery metadata | `72f988bf-86f1-41af-91ab-2d7cd011db47` | | **Custom Verified Domain** (`contoso.com`) | Resolved via Microsoft OpenID discovery metadata | `<canonical-tenant-guid>` | <br> --- ##### Was generative AI tooling used to co-author this PR? <!-- If generative AI tooling has been used in the process of authoring this PR, please change below checkbox to `[X]` followed by the name of the tool, uncomment the "Generated-by". --> - [x] Yes (please specify the tool below) Generated-by: [GPT 5.6-sol] following [the guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
