CAMEL-24319: camel-keycloak add optional token type (typ) and authorized party (azp) validation - #25259
Conversation
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
…zed party (azp) validation Adds two opt-in KeycloakSecurityPolicy settings, disabled by default for backward compatibility and applied on both the local JWT verification and token introspection paths: - expectedTokenTypes: allow-list of accepted "typ" values, guarding against token-type confusion (e.g. an ID or refresh token presented where an access token is expected) - expectedAuthorizedParty: expected "azp" value, ensuring the token was issued for the expected client Mirrors the existing expectedAudience opt-in (CAMEL-23875). Includes unit tests and documentation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 10 tested, 28 compile-only — current: 9 all testedMaveniverse Scalpel detected 38 affected modules (current approach: 9).
|
gnodet
left a comment
There was a problem hiding this comment.
Claude Code on behalf of Guillaume Nodet
Thanks for adding token type and authorized party validation to camel-keycloak! The feature is well-structured and the JWT validation path looks solid. I found a few issues that should be addressed before merging:
🔴 HIGH — validatePermissions() missing token type and authorized party checks on introspection path
The PR adds validateTokenTypeFromIntrospection() and validateAuthorizedPartyFromIntrospection() calls to both authenticateToken() and validateRoles(), but not to validatePermissions().
In beforeProcess(), when only requiredPermissions is configured (no roles), the flow skips authenticateToken() entirely (the condition is !rolesRequired && !permissionsRequired) and goes straight to validatePermissions(). On its introspection branch, validatePermissions() checks active status, issuer, and audience — but does not call the two new validation methods.
This means token type and authorized party validation can be bypassed when useTokenIntrospection=true with only permissions configured.
The prior CAMEL-23875 commit (4bad2c9) correctly added audience validation to all three code paths (authenticateToken, validateRoles, validatePermissions). This PR should follow the same pattern.
Suggested fix — add the missing calls to validatePermissions() in the introspection branch, analogous to how they were added in validateRoles():
// In validatePermissions(), introspection branch, after audience validation:
validateTokenTypeFromIntrospection(introspectionResult, exchange);
validateAuthorizedPartyFromIntrospection(introspectionResult, exchange);🟡 MEDIUM — validateTokenTypeFromIntrospection() reads getClaim("typ") instead of standard token_type field
The new validateTokenTypeFromIntrospection() method uses introspectionResult.getClaim("typ") to read the token type. However, RFC 7662 defines the standard introspection response field as "token_type", and IntrospectionResult already has a typed accessor getTokenType() that reads claims.get("token_type").
While Keycloak does forward the JWT typ claim in its introspection response, using the non-standard field name makes the code fragile against non-Keycloak introspection endpoints. Consider using getTokenType() or checking both fields for robustness.
🟡 LOW — No tests for introspection validation paths
The PR adds tests to KeycloakSecurityHelperTest for the local JWT verification path, but the new validateTokenTypeFromIntrospection() and validateAuthorizedPartyFromIntrospection() methods have no test coverage.
The CAMEL-23875 commit included 5 introspection-specific tests in KeycloakSecurityProcessorTest (e.g., testTokenMissingExpectedAudienceRejectedWithRequiredPermissionsIntrospection), establishing a precedent that introspection paths should be tested. Adding similar tests for the new validation methods would ensure complete coverage.
…issions-only introspection path gnodet's review found that validateTokenTypeFromIntrospection/ validateAuthorizedPartyFromIntrospection were wired into authenticateToken() and validateRoles() but not validatePermissions(). With useTokenIntrospection=true and only requiredPermissions configured, beforeProcess() goes straight to validatePermissions(), so both checks could be bypassed. Add them to that path with the same gating (matching the CAMEL-23875 audience pattern), and add two introspection tests that reject a permission-satisfying token with the wrong token type / azp. Also document why the "typ" claim (JWT token category that Keycloak forwards) is used rather than the RFC 7662 "token_type" OAuth field. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
|
Thanks @gnodet — all three addressed in 67c2962: 🔴 HIGH — validatePermissions() bypass: Confirmed and fixed. Added 🟡 LOW — tests: Added two introspection tests mirroring 🟡 MEDIUM — typ vs token_type: I kept Re-requesting review. Claude Code on behalf of Andrea Cosentino (@oscerd). |
gnodet
left a comment
There was a problem hiding this comment.
Re-review after latest commits. All three previous findings are properly addressed:
-
Security bypass in
validatePermissions()(HIGH) — Fixed.validateTokenTypeFromIntrospection()andvalidateAuthorizedPartyFromIntrospection()are now called in the introspection branch ofvalidatePermissions()(lines 512-520), matching the pattern established by CAMEL-23875 for audience validation across all three code paths. ✅ -
typvstoken_typerationale (MEDIUM) — Addressed with a clear code comment (lines 448-450). The JWTtypclaim (Bearer/Refresh/ID) distinguishes token categories, while RFC 7662token_typeis alwaysBearer— sound reasoning for a Keycloak-specific component. ✅ -
Missing introspection tests (LOW) — Fixed with two new tests:
testTokenWrongTokenTypeRejectedWithRequiredPermissionsIntrospectionandtestTokenWrongAuthorizedPartyRejectedWithRequiredPermissionsIntrospectionspecifically covering the bypass scenario. ✅
Fix commit is minimal and focused: 13 lines in the processor, 79 lines of tests. CI passes.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
What
Adds two opt-in hardening settings to
KeycloakSecurityPolicy, so a Camel-protected route can validate the token's type (typ) and authorized party (azp) in addition to the existing signature / issuer / active / (opt-in) audience checks:expectedTokenTypes— comma-separated allow-list of acceptedtypvalues (e.g."Bearer"). Guards against token-type confusion, e.g. an ID token or refresh token being presented where an access token is expected.expectedAuthorizedParty— expectedazpvalue (e.g."my-client"); ensures the token was issued for the expected client.Both checks are applied on both validation paths (local JWT verification and token introspection) and are disabled by default for backward compatibility, mirroring the existing
expectedAudienceopt-in (CAMEL-23875).Why
KeycloakSecurityPolicyalready verifies signature, issuer, active state and optionally audience, but never checkedtyp/azp. keycloak-core itself ships aTokenTypeCheck, and OAuth2 resource servers are expected to reject non-access-token types. This closes that gap without changing any default behaviour.Tests
Four new unit tests in
KeycloakSecurityHelperTest(accept/reject for bothtypandazp); fullcamel-keycloaksuite green (27 tests, 0 failures).Docs
keycloak-security.adocgains a "Token Type and Authorized Party Validation" section. No upgrade-guide entry — the change is opt-in and non-breaking.Jira: https://issues.apache.org/jira/browse/CAMEL-24319
Authored by Claude Code on behalf of Andrea Cosentino.
🤖 Generated with Claude Code