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]

Reply via email to