Commit f843c63
authored
fix: Support Entra ID (Azure AD) token claims in OIDC auth (#6631)
* fix: Support Entra ID (Azure AD) token claims in OIDC auth
The OIDC token parser was written against Keycloak's token shape, which
rejected Microsoft Entra ID tokens in two independent ways.
Username extraction accepted only preferred_username or upn. Entra
client-credentials (app-only) tokens carry neither, so every
machine-to-machine caller failed authentication. Fall back to the calling
application's own identity when no human claim is present: azp on v2
tokens, appid on v1, then sub, which every issuer sets. A token with none
of the five claims still raises AuthenticationError.
Roles were read only from Keycloak's nested
resource_access.<client_id>.roles. Entra emits app roles in the top-level
roles claim, so the extracted list was always empty and RoleBasedPolicy
could never match. Merge the top-level claim into the existing
extraction, preserving order and dropping duplicates.
Both changes are additive, so Keycloak behavior is unchanged: the
username fallbacks only fire when preferred_username and upn are both
absent, and the merge only adds roles. Token validation is untouched.
Signed-off-by: Larry Singleton <166439969+larrysingleton007@users.noreply.github.com>
* docs: Document Entra ID claim support in OIDC authorization
The OIDC assumptions listed for the auth manager described only
Keycloak's token shape. Record that roles are also read from the
top-level roles claim and merged, and that the username falls back
through upn, azp, appid and sub when preferred_username is absent.
Signed-off-by: Larry Singleton <166439969+larrysingleton007@users.noreply.github.com>
* fix: Harden Entra ID OIDC claim handling from review
Refine the initial Entra ID support in response to review:
- Merge roles with list(dict.fromkeys(...)), the codebase's order-
preserving dedup idiom (feast/utils.py), so duplicates within the
top-level roles claim are also collapsed, not only cross-claim ones.
- Skip username claims whose value is null or non-string instead of
returning them, so a present-but-null early claim no longer shadows a
usable later claim; the -> str contract now holds.
- Correct the _extract_username_or_raise_error docstring: the raise
fires only when a token provides none of the five claims as a string.
Extend the tests: intra-claim role de-duplication, human-claim
precedence over appid/sub, and rejection of tokens whose only identity
claims are null or non-string.
Signed-off-by: Larry Singleton <166439969+larrysingleton007@users.noreply.github.com>
* docs: Add Entra ID token example and group-claim caveat
Add an app-only (client-credentials) Entra ID token example alongside
the Keycloak one, and note that Entra emits group object IDs (GUIDs)
rather than names and omits the groups claim under the overage limit,
so GroupBasedPolicy on Entra must reference those IDs.
Signed-off-by: Larry Singleton <166439969+larrysingleton007@users.noreply.github.com>
* test: Cover OIDC verified-decode sourcing and trim redundant asserts
Add a test that gives the unverified routing decode and the verified
decode different payloads and asserts identity and roles come from the
verified one, so a regression that read claims from the unverified
decode would be caught.
Drop the has_matching_role assertions in the roles-merge test: the exact
roles-list equality already pins the result, and has_matching_role has
its own coverage in test_user.py.
Signed-off-by: Larry Singleton <166439969+larrysingleton007@users.noreply.github.com>
* test: Extract shared OIDC discovery and signing-key fixtures
The OIDC token-parser tests each re-declared the same mock discovery
document and JWKS signing key. Move both into conftest.py fixtures and
have the tests consume them, removing the repeated setup blocks.
Signed-off-by: Larry Singleton <166439969+larrysingleton007@users.noreply.github.com>
* fix: Address review nitpicks on Entra OIDC PR
- Type the discovery_data test fixture as Dict[str, str].
- Split the Entra group-claim caveat into its own bullet in authz_manager.md.
- Log the token's claim keys at debug level before raising on a missing
username claim, to aid diagnosis (keys only, no values).
Signed-off-by: Larry Singleton <166439969+larrysingleton007@users.noreply.github.com>
---------
Signed-off-by: Larry Singleton <166439969+larrysingleton007@users.noreply.github.com>1 parent 0399380 commit f843c63
4 files changed
Lines changed: 305 additions & 62 deletions
File tree
- docs/getting-started/components
- sdk/python
- feast/permissions/auth
- tests/unit/permissions/auth
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | | - | |
| 47 | + | |
48 | 48 | | |
49 | | - | |
| 49 | + | |
50 | 50 | | |
| 51 | + | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
| |||
69 | 70 | | |
70 | 71 | | |
71 | 72 | | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
72 | 83 | | |
73 | 84 | | |
74 | 85 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
68 | 76 | | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | | - | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
73 | 84 | | |
74 | | - | |
| 85 | + | |
| 86 | + | |
75 | 87 | | |
76 | 88 | | |
77 | 89 | | |
| |||
194 | 206 | | |
195 | 207 | | |
196 | 208 | | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
197 | 213 | | |
198 | 214 | | |
199 | 215 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
1 | 4 | | |
2 | 5 | | |
3 | 6 | | |
| |||
62 | 65 | | |
63 | 66 | | |
64 | 67 | | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
65 | 84 | | |
66 | 85 | | |
67 | 86 | | |
| |||
0 commit comments