-
Notifications
You must be signed in to change notification settings - Fork 6k
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
NimbusJwtDecoderJwkSupport should offer method to get OAuth2TokenValidator #6909
Comments
@TheFonz2017, thanks for the report.
The current guidance, which you pointed out, is still preferred: @Bean
public JwtDecoder jwtDecoder(OAuth2ResourceServerProperties properties) {
String issuer = properties.getJwt().getIssuerUri();
NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromOidcIssuerLocation(issuer);
OAuth2TokenValidator<Jwt> defaults = JwtValidators.createDefaultWithIssuer(issuer);
DelegatingOAuth2TokenValidator<Jwt> validators =
new DelegatingOAuth2TokenValidator<>(defaults, myValidator);
jwtDecoder.setJwtValidator(validators);
return jwtDecoder;
} There's also If those don't address your issue, can you explain some more detail about what you are trying to do that isn't simple? |
Hi Josh, thanks for your response, and sorry for not being clear enough. The actual problem is: - Why is this a problem? - The current guidance (which you said is still preferred) is fine, if an application wants to expose an entirely new Why not just create a new JwtDecoder as by the preferred guidance? - The answer to this lies in the way Spring Security OAuth2 creates the standard (auto-configured)
This behavior makes sense, and differs based on the configuration of the application. In my case, where I need to add additional custom And this is only necessary, since there is no proper Finally, it needs to be said that I am not just writing an application. I am writing a reuse library that's supposed to auto-configure additional token validation logic on top of the standard Spring Security OAuth2 one. That's why enhancing the standard Spring Security behavior is preferred over simply recreating it. I hope that clarifies it. Cheers! |
Related conversation @ #6978 (comment) @TheFonz2017 I understand your concern about copy-pasting code. I don't think I'm seeing that as a concern in this case, though. If you want to do exactly what the auto-configuration does, just adding a custom validator, you could do: @Autowired
public void addValidators(JwtDecoder jwtDecoder) {
OAuth2TokenValidator<Jwt> defaults = JwtValidators.createDefaultWithIssuer(issuer);
((NimbusJwtDecoder) jwtDecoder).setJwtValidator(
new DelegatingOAuth2TokenValidator<Jwt>(defaults, myCustomValidator));
} Since @Autowired
public void addValidators(JwtDecoder jwtDecoder) {
OAuth2TokenValidator<Jwt> defaults = jwtDecoder.getJwtValidator();
((NimbusJwtDecoder) jwtDecoder).setJwtValidator(
new DelegatingOAuth2TokenValidator<Jwt>(defaults, myCustomValidator));
} So, really, I'm not seeing why not having |
@jzheaux, thanks for your response. Note that I do not want to "do exactly as the auto-configuration does", but I want to let the auto-configuration do its thing and afterwards add my custom validators to the ones added by the auto-configuration. Since the auto-configuration creates two different JwtDecoders (with differing sets of JwtValidators) and these cannot be accessed using a getter, I have no other choice than to duplicate auto-configuration coding. I will explain, why what you are proposing still leads to duplicating framework coding: Note: in the meantime Let's look at the class: @Bean
@ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
public JwtDecoder jwtDecoderByJwkKeySetUri() {
return NimbusJwtDecoder.withJwkSetUri(this.properties.getJwkSetUri())
.jwsAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
}
//...
@Bean
@Conditional(IssuerUriCondition.class)
public JwtDecoder jwtDecoderByIssuerUri() {
return JwtDecoders.fromOidcIssuerLocation(this.properties.getIssuerUri());
} These two conditional bean declaration create two differently configured The first one, public final class NimbusJwtDecoder implements JwtDecoder {
//...
// !! createDefault() ≠ createDefaultWithIssuer(issuer) (see below) !!
private OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefault();
//...
private Jwt validateJwt(Jwt jwt){
OAuth2TokenValidatorResult result = this.jwtValidator.validate(jwt);
//...
} Where The second one public static JwtDecoder fromIssuerLocation(String issuer) {
//...
return withProviderConfiguration(configuration, issuer);
} ... doing ... private static JwtDecoder withProviderConfiguration(Map<String, Object> configuration, String issuer) {
//...
// !! createDefaultWithIssuer(issuer) ≠ createDefault() (see above) !!
OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefaultWithIssuer(issuer);
NimbusJwtDecoder jwtDecoder = withJwkSetUri(configuration.get("jwks_uri").toString()).build();
jwtDecoder.setJwtValidator(jwtValidator);
return jwtDecoder;
} ... where public static OAuth2TokenValidator<Jwt> createDefaultWithIssuer(String issuer) {
List<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();
validators.add(new JwtTimestampValidator()); // same validator as in "default" case
validators.add(new JwtIssuerValidator(issuer)); // additional validator!!!
return new DelegatingOAuth2TokenValidator<>(validators);
} ... meaning that there is not just a Thus, the JwtDecoders have different validators depending on whether the framework auto-configuration created them with an issuer URI (as a result of configuring one in So, even if I used your approach (which I tried before), I would have to duplicate the logic of
That is an exact duplication of the auto-configuration coding. And it could / should be avoided by providing a simple getter for the validators. |
@TheFonz2017 I appreciate your analysis, thank you. Can you show me what code you are trying to write that is cumbersome? It appears to me that that only thing you are replacing is |
Sure Josh, I am providing a security reuse library that an application shall be able to drop into its classpath. So my code looks as follows: // Copied from org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerJwkConfiguration
// Unfortunately there is (today) no better way to get the default configurations for Validators of Spring Security.
@Configuration
@AutoConfigureBefore(OAuth2ResourceServerAutoConfiguration.class)
@ConditionalOnClass(OAuth2ResourceServerProperties.class)
public class XsuaaResourceServerJwkConfiguration {
private final OAuth2ResourceServerProperties properties;
public XsuaaResourceServerJwkConfiguration(OAuth2ResourceServerProperties properties) {
Assert.notNull(properties, "Properties must not be null.");
this.properties = properties;
}
@Bean
@ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
@ConditionalOnMissingBean
public JwtDecoder jwtDecoderByJwkKeySetUri(XsuaaServiceBindings xsuaaServiceBindings) {
String jwkSetUri = this.properties.getJwt().getJwkSetUri();
OAuth2TokenValidator<Jwt> defaultValidators = JwtValidators.createDefault();
// My custom JwtValidator to be added additional to the ones that are standard in
// Spring Security auto-configuration.
OAuth2TokenValidator<Jwt> xsuaaAudienceValidator = new XsuaaAudienceValidator(xsuaaServiceBindings);
OAuth2TokenValidator<Jwt> combinedValidators = new DelegatingOAuth2TokenValidator<>(defaultValidators, xsuaaAudienceValidator);
NimbusJwtDecoderJwkSupport jwtDecoder = new NimbusJwtDecoderJwkSupport(jwkSetUri);
jwtDecoder.setJwtValidator(combinedValidators);
return jwtDecoder;
}
@Bean
@Conditional(IssuerUriCondition.class)
@ConditionalOnMissingBean
public JwtDecoder jwtDecoderByIssuerUri(XsuaaServiceBindings xsuaaServiceBindings) {
String oidcIssuerLocation = this.properties.getJwt().getIssuerUri();
OAuth2TokenValidator<Jwt> defaultValidators = JwtValidators.createDefaultWithIssuer(oidcIssuerLocation);
// My custom JwtValidator to be added additional to the ones that are standard in
// Spring Security auto-configuration.
OAuth2TokenValidator<Jwt> xsuaaAudienceValidator = new XsuaaAudienceValidator(xsuaaServiceBindings);
OAuth2TokenValidator<Jwt> combinedValidators = new DelegatingOAuth2TokenValidator<>(defaultValidators, xsuaaAudienceValidator);
NimbusJwtDecoderJwkSupport jwtDecoder = nimbusJwtDecoderFromOidcIssuerLocation(oidcIssuerLocation);
jwtDecoder.setJwtValidator(combinedValidators);
return jwtDecoder;
}
protected NimbusJwtDecoderJwkSupport nimbusJwtDecoderFromOidcIssuerLocation(String oidcIssuerLocation) {
return (NimbusJwtDecoderJwkSupport) JwtDecoders.fromOidcIssuerLocation(oidcIssuerLocation);
}
} Note: this code uses the Spring Security APIs of version 5.1.5 - not the current master, which was referenced in the discussion above - but the issue is still exactly the same. As you can see, this is copying the coding of the original Spring Security |
are there any plans to provide access to the set of validators? |
Thanks for reaching out, @mrodal. Does this feature in Spring Boot address your concern? If so, I think we can close this issue in favor of it. |
it does, thank you. I believe issue #13249 can also be closed |
Summary
NimbusJwtDecoderJwkSupport
is the underlying implementation for Spring SecurityJwtDecoder
.NimbusJwtDecoderJwkSupport
provides a method tosetJwtValidator(OAuth2TokenValidator<Jwt>)
, but it does not have a method to retrieve the set validator(s).NimbusJwtDecoderJwkSupport
is used to auto-configure aJwtDecoder
bean inOAuth2ResourceServerJwkConfiguration
and its instantiation and especially the set JWT validators depend on the existence of either a JWKS URI or an Issuer URI from thespring.security.oauth2.resourceserver.jwt.issuer-uri
.If an application or library wants to add additional JWT validators, today's guidance in Spring Security documentation is to re-declare a
JwtDecoder
bean and set the validators on it.Problem is, that now the application / library has no access to the configured defaults of Spring Security which (as described above) depend on the user's configurations.
Ideally we would like to do something like this:
As an alternative, it might also be ok to add an
addValidator(OAuth2TokenValidator<Jwt>)
method toNimbusJwtDecoderJwkSupport
, though presumably it's implementation would result in a lot of chainedDelegatingOAuth2TokenValidator<Jwt>
s.Actual Behavior
No way for an application to get the
OAuth2TokenValidator
s of the auto-configured standard Spring SecurityJwtDecoder
.Expected Behavior
A way for an application to get the
OAuth2TokenValidator
s of the auto-configured standard Spring SecurityJwtDecoder
or to add additional customOAuth2TokenValidator
.References
OAuth2ResourceServerJwkConfiguration (Auto-Configuration):
Version
Spring Security Version 5.1.5.RELEASE
The text was updated successfully, but these errors were encountered: