Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder holds a reference to JWSVerificationKeySelector before ConfigurableJWTProcessor.setJWSKeySelector is executed #12960

Closed
meverden opened this issue Apr 3, 2023 · 3 comments
Assignees
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: bug A general bug
Milestone

Comments

@meverden
Copy link

meverden commented Apr 3, 2023

The ConfigurableJWTProcessor.setJWSKeySelector(JWSKeySelector) is unable to update the reference used by NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder.processor(). The processor holds a reference to the default JWSKeySelector created within NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder.jwsKeySelector() via a method reference within JwkSetUriReactiveJwtDecoderBuilder.getExpectedJwsAlgorithms() before the ConfigurableJWTProcessorsetJWSKeySelector(JWSKeySelector) is executed.

The following unit test will show that the processor is executing the wrong JWSVerificationKeySelector.isAllowed(JWSAlgorithm) reference.

@ExtendWith(MockitoExtension.class)
class NimbusReactiveJwtDecoderTest {

    @Mock private WebClient webClient;
    @Mock private RequestHeadersUriSpec<?> requestHeadersUriSpec;
    @Mock private ResponseSpec responseSpec;

    @Test
    void customizeJWSKeySelector() throws Exception {

        var jwkSet = new JWKSet(
                new RSAKeyGenerator(RSAKeyGenerator.MIN_KEY_SIZE_BITS)
                .algorithm(JWSAlgorithm.RS512)
                .keyID(UUID.randomUUID().toString())
                .keyUse(KeyUse.SIGNATURE)
                .generate());

        var jwkSource = new ImmutableJWKSet<>(jwkSet);

        var jwt = new NimbusJwtEncoder(jwkSource).encode(
                JwtEncoderParameters.from(JwsHeader.with(SignatureAlgorithm.RS512).build(), 
                        JwtClaimsSet.builder().issuer("issuer").build()));

        // stub WebClient response for ReactiveRemoteJWKSource
        Mockito.doReturn(requestHeadersUriSpec).when(webClient).get();
        Mockito.doReturn(requestHeadersUriSpec).when(requestHeadersUriSpec).uri(Mockito.anyString());
        Mockito.when(requestHeadersUriSpec.retrieve()).thenReturn(responseSpec);
        Mockito.when(responseSpec.bodyToMono(String.class)).thenReturn(Mono.just(jwkSet.toString()));
        
        var decoder = NimbusReactiveJwtDecoder
                .withJwkSetUri("http://localhost/oauth2/jwks") // use NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder
                .webClient(webClient) // stub remote call
                .jwtProcessorCustomizer(processor -> {

                    // this reference will not be used by the "Function<JWSAlgorithm, Boolean> expectedJwsAlgorithms" within JwkSetUriReactiveJwtDecoderBuilder.processor()
                    var jwsKeySelector = new JWSVerificationKeySelector<>(Set.of(JWSAlgorithm.RS512),  jwkSource);

                    // the JwkSetUriReactiveJwtDecoderBuilder.processor() still holds a reference to the JWSVerificationKeySelector instantiated
                    // within JwkSetUriReactiveJwtDecoderBuilder.jwsKeySelector(), via the method reference created by JwkSetUriReactiveJwtDecoderBuilder.getExpectedJwsAlgorithms(), held before the customizer is executed.
                    processor.setJWSKeySelector((JWSVerificationKeySelector) jwsKeySelector);
                })
                .build();

        // execute the processor
        decoder.decode(jwt.getTokenValue())
            .block();
    }

}
@meverden meverden added status: waiting-for-triage An issue we've not yet triaged type: bug A general bug labels Apr 3, 2023
@jzheaux
Copy link
Contributor

jzheaux commented Apr 3, 2023

Thanks, @meverden, for the observation. Are you able to submit a PR that addresses the issue? It would be nice to include your test as part of the contribution.

@jzheaux jzheaux added in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) and removed status: waiting-for-triage An issue we've not yet triaged labels Apr 3, 2023
@jzheaux jzheaux added this to the 5.7.x milestone Apr 3, 2023
@meverden
Copy link
Author

meverden commented Apr 3, 2023

@jzheaux, yes, I'll submit a PR.

@meverden
Copy link
Author

meverden commented Apr 4, 2023

@jzheaux , #12965 has been submitted.

meverden pushed a commit to meverden/spring-security that referenced this issue Apr 11, 2023
Updating the NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder processor to execute the ConfigurableJWTProcessor customizations before holding a reference to the JWSKeySelector.

Closes spring-projectsgh-12960
@jzheaux jzheaux self-assigned this Apr 12, 2023
@jzheaux jzheaux modified the milestones: 5.7.x, 5.7.8 Apr 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants