oscerd opened a new pull request, #1910:
URL: https://github.com/apache/camel-spring-boot/pull/1910

   `UndertowSpringSecurityCustomizer.jwtDecoderByIssuerUri()` built the decoder 
from the JWK set URI and
   installed only a claim-set converter:
   
   ```java
   final NimbusJwtDecoder jwtDecoder = 
NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
   jwtDecoder.setClaimSetConverter(new 
KeycloakUsernameSubClaimAdapter(getProvider().getUserNameAttribute()));
   return jwtDecoder;
   ```
   
   Despite the bean name, no `setJwtValidator` call was made, so the default 
validator applied: signature and
   timestamps were checked, the `iss` claim was not, and the configured 
`clientId` was used only to build the
   `ClientRegistration` — never bound to the token. Spring Security's own 
`withIssuerLocation` path installs an
   issuer validator; this construction path does not.
   
   **Why the audience check is the substantive part.** Pinning the JWKS URI 
already ties tokens to the realm, so
   issuer validation alone adds little — every client of that realm shares the 
same signing key. A token minted
   for a different client of the same realm therefore validated here. Binding 
the token to the configured client
   is what closes that.
   
   ### Change
   
   ```java
   final OAuth2TokenValidator<Jwt> withIssuer = 
JwtValidators.createDefaultWithIssuer(issuerUri);
   if (!getProvider().isValidateAudience()) {
       return withIssuer;
   }
   return new DelegatingOAuth2TokenValidator<>(withIssuer,
           new JwtAudienceValidator(getClientRegistration().getClientId()));
   ```
   
   `JwtAudienceValidator` accepts a token whose `aud` contains the configured 
client id, or — for providers such
   as Keycloak that record the requesting client separately — whose `azp` 
equals it.
   
   The issuer is derived from the same `url` + `realmId` the client 
registration already resolves, via a shared
   `realmUri()` helper, so the issuer is by construction the prefix of the JWK 
set URI (asserted in a test).
   
   ### Behaviour change and opt-out
   
   This is deliberate: a deployment presenting tokens minted for a *different* 
client will now be rejected, which
   is the point. For anyone relying on that:
   
   ```properties
   camel.security.undertow.keycloak.validate-audience = false
   ```
   
   Documented in `intro.adoc`, and it surfaces in config metadata. Worth an 
upgrade-guide entry in `apache/camel`
   when this lands — happy to open that.
   
   ### Tests
   
   This starter had **no test module**; this adds one along with 
`spring-boot-starter-test` (test scope only,
   outside the generated dependency block).
   
   - `JwtAudienceValidatorTest` — 5 cases: accepted via `aud`, accepted via 
`azp`, accepted when one of several
     audiences, **rejected for another client of the same realm**, rejected 
when neither claim is present.
   - `KeycloakIssuerUriTest` — 4 cases: issuer derivation, path on the 
configured URL ignored, issuer is the
     prefix of the generated JWK set URI (guards the two from drifting apart), 
and audience validation defaults on.
   
   9 tests, all passing. Full reactor `mvn clean install -DskipTests` — BUILD 
SUCCESS.
   
   ### Not addressed here
   
   CAMEL-24497 also notes that the registration of the non-static inner 
`@EnableWebSecurity SecurityConfiguration`
   is statically unconfirmed, and suggests a test asserting the filter chain 
actually installs. I have **not**
   added that — it needs a Spring context with a reachable provider, which is a 
different kind of test than the
   unit coverage above. Left on the issue; if the chain never registers, that 
is a separate and worse fail-open
   than this one.


-- 
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