-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
Conversation
There was a problem hiding this 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"; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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> { |
There was a problem hiding this comment.
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"; |
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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 -> { |
There was a problem hiding this comment.
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 -> { |
There was a problem hiding this comment.
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; | ||
}; | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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
d5b48d0
to
9918402
Compare
There was a problem hiding this 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(){ |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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())); | ||
|
There was a problem hiding this comment.
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
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. |
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