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

Extract the ID Token JwtDecoderFactory to enable user customization #6415

Closed
wants to merge 1 commit into from

Conversation

raphaelDL
Copy link
Contributor

This commit ensures that the JwtDecoder is not a private field inside
the Oidc authentication provider by extracting this class and giving the
possibility to customize the way different providers are validated.

Fixes: gh-6379

@jgrandja jgrandja self-assigned this Jan 11, 2019
@jgrandja jgrandja changed the title Extracts the JwTDecoder to enable users customize its behavior Extracts the ID Token JwtDecoderFactory to enable user customization Jan 11, 2019
@jgrandja jgrandja changed the title Extracts the ID Token JwtDecoderFactory to enable user customization Extract the ID Token JwtDecoderFactory to enable user customization Jan 11, 2019
Copy link
Contributor

@jgrandja jgrandja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @raphaelDL ! Please see my comments inline.

*/
public final class OidcIdTokenDecoderFactory implements JwtDecoderFactory<ClientRegistration> {
private final Map<String, JwtDecoder> jwtDecoders = new ConcurrentHashMap<>();
private static final String MISSING_SIGNATURE_VERIFIER_ERROR_CODE = "missing_signature_verifier";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move the static members to top of declarations.

* @param jwtValidatorFactory
*/
public final void setJwtValidatorFactory(Function<ClientRegistration, OAuth2TokenValidator<Jwt>> jwtValidatorFactory) {
this.jwtValidatorFactory = jwtValidatorFactory;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should Assert.notNull

}
String jwkSetUri = clientRegistration.getProviderDetails().getJwkSetUri();
NimbusJwtDecoder jwtDecoder = new NimbusJwtDecoder(withJwkSetUri(jwkSetUri).build());
OAuth2TokenValidator<Jwt> jwtValidator = new DelegatingOAuth2TokenValidator<>(jwtValidatorFactory.apply(clientRegistration));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to use DelegatingOAuth2TokenValidator given that we're directly assigning the one returned instance.

* @see OAuth2TokenValidator
* @see Jwt
*/
public class ReactiveOidcIdTokenDecoderFactory implements ReactiveJwtDecoderFactory<ClientRegistration> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make class final

*/
public class ReactiveOidcIdTokenDecoderFactory implements ReactiveJwtDecoderFactory<ClientRegistration> {
private final Map<String, ReactiveJwtDecoder> jwtDecoders = new ConcurrentHashMap<>();
private static final String MISSING_SIGNATURE_VERIFIER_ERROR_CODE = "missing_signature_verifier";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move the static members to top of declarations.

}

@Test
public void createWhenWithCustomDecoderTheSuccess() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this test makes sense. It's pretty much the same as above test. Please remove it.


@Override
public JwtDecoder createDecoder(ClientRegistration clientRegistration) {
return this.jwtDecoders.computeIfAbsent(clientRegistration.getRegistrationId(), key -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should Assert.notNull on clientRegistration


@Override
public ReactiveJwtDecoder createDecoder(ClientRegistration clientRegistration) {
return this.jwtDecoders.computeIfAbsent(clientRegistration.getRegistrationId(), key -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should Assert.notNull on clientRegistration

}
return idTokenValidator;
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that the only tests we need here are as follows:

  • setJwtValidatorFactoryWhenNullThenThrowIllegalArgumentException
  • createDecoderWhenClientRegistrationNullThenThrowIllegalArgumentException
  • createDecoderWhenJwkSetUriEmptyThenThrowOAuth2AuthenticationException
  • createDecoderWhenClientRegistrationValidThenReturnDecoder
  • createDecoderWhenCustomJwtValidatorFactorySetThenApplied

Can you please add these tests? Please let me know if you need any clarification.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much, I've submitted the changes

* @author Rafael Dominguez
* @since 5.2
*/
public class ReactiveOidcIdTokenDecoderFactoryTests {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments apply from OidcIdTokenDecoderFactoryTests

@raphaelDL raphaelDL force-pushed the gh-6379 branch 4 times, most recently from d5b48d0 to 9918402 Compare January 11, 2019 18:27
Copy link
Contributor

@jgrandja jgrandja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates. Almost there....some more changes in tests.

}

@Test
public void createDecoderWhenCustomJwtValidatorFactorySetThenApplied(){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not testing that the custom JwtValidatorFactory is actually called. We need to verify that Function.apply() is actually called. For an example, see NimbusReactiveJwtDecoderTests.decodeWhenUsingSignedJwtThenReturnsClaimsGivenByClaimSetConverter. That test mock(Converter.class) and than verify(claimSetConverter).convert(any(Map.class)). You will need to do the same for Function. Make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'm working on it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How's it coming along. Do you need any help?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've submitted the changes, I don't know why they are not reflected here 🤔

assertThat(jwtDecoder).isNotNull();
}

@Test(expected = IllegalArgumentException.class)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our preferred method of testing a thrown exception is assertThatThrownBy(). Let's remove expected = IllegalArgumentException.class for all test cases and use assertThatThrownBy() instead.

}

@Test
public void createDecoderWhenDefaultJwtValidatorFactorySetThenApplied() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this test - createDecoderWhenCustomJwtValidatorFactorySetThenApplied is the main thing we need to test.

@Test(expected = IllegalArgumentException.class)
public void setJwtValidatorFactoryWhenNullThenThrowIllegalArgumentException(){
idTokenDecoderFactory.setJwtValidatorFactory(null);
idTokenDecoderFactory.createDecoder(registration.build());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this line as it will never get called


private OidcIdTokenDecoderFactory idTokenDecoderFactory;

private JwtDecoder jwtDecoder;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this and just create it in each test?


private ReactiveOidcIdTokenDecoderFactory idTokenDecoderFactory;

private ReactiveJwtDecoder reactiveJwtDecoder;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this and just create it in each test?

This commit ensures that the JwtDecoder is not a private field inside
the Oidc authentication provider by extracting this class and giving the
possibility to customize the way different providers are validated.

Fixes: spring-projectsgh-6379

when(customValidator.apply(any(ClientRegistration.class)))
.thenReturn(customJwtValidatorFactory.apply(registration.build()));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jgrandja here are the changes, I think they are not reflected because the comment is in the method signature

@jgrandja jgrandja added New Feature in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) labels Jan 14, 2019
@jgrandja jgrandja added this to the 5.2.0.M1 milestone Jan 14, 2019
jgrandja added a commit that referenced this pull request Jan 14, 2019
@jgrandja
Copy link
Contributor

Thanks @raphaelDL for getting this done before tomorrow's release. This is now in master! I added a polish commit for some minor updates to the tests and javadoc.

@jgrandja jgrandja closed this Jan 14, 2019
@rwinch rwinch added the type: enhancement A general enhancement label May 3, 2019
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: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Expose ID Token JwtDecoderFactory
3 participants