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

Customizable set of JwtClaimValidators for OAuth Resource Server #13249

Open
romangr opened this issue May 31, 2023 · 7 comments
Open

Customizable set of JwtClaimValidators for OAuth Resource Server #13249

romangr opened this issue May 31, 2023 · 7 comments
Labels
in: config An issue in spring-security-config type: enhancement A general enhancement

Comments

@romangr
Copy link

romangr commented May 31, 2023

Expected Behavior

I expect that additional JwtClaimValidator instances should be easily configured and injected for token processing. It should not require disabling auto-configuration logic that is very helpful in many aspects. Possible solution is to use declared beans of JwtClaimValidator type.

Current Behavior

Currently there is no way to add custom validators without redefining the whole OAuth2ResourceServerJwtConfiguration because validators are not injected but created inside the configuration.

Context

I'm implementing a starter library for microservices system. I created my own auto configuration class and it's quite small because I mostly rely on the OAuth2ResourceServerJwtConfiguration. But when I need to add a custom JWT claims validator the only way to do it is to redefine the whole standard configuration. It's not convenient because the standard configuration contains must have validators like issuer validator and some other logic that is useful (e.g. resolving the source of public key for token validation). I think there is much more room for errors in this approach then if we just provide a way to add custom validators without touching the default configuration.

What I have now is just the same configuration class as in the Spring Security library but I inject all the beans of JwtClaimValidator type to the field and then add all those beans to the list of validators

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(JwtDecoder.class)
static class JwtDecoderConfiguration {

    private final OAuth2ResourceServerProperties properties;
    private final List<JwtClaimValidator<?>> claimValidators;

    JwtDecoderConfiguration(OAuth2ResourceServerProperties properties, List<JwtClaimValidator<?>> claimValidators) {
      this.properties = properties;
      this.claimValidators = claimValidators;
    }

    private OAuth2TokenValidator<Jwt> getValidators(Supplier<OAuth2TokenValidator<Jwt>> defaultValidator) {
      OAuth2TokenValidator<Jwt> defaultValidators = defaultValidator.get();
      List<String> audiences = this.properties.getAudiences();
      List<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();
      validators.add(defaultValidators);
      validators.addAll(claimValidators);
      if (!CollectionUtils.isEmpty(audiences)) {
        validators.add(new JwtClaimValidator<List<String>>(JwtClaimNames.AUD,
          (aud) -> aud != null && !Collections.disjoint(aud, audiences)));
      }
      return new DelegatingOAuth2TokenValidator<>(validators);
    }
   
    // All code from OAuth2ResourceServerJwtConfiguration
    ...
  }

It is a working solution but in my opinion it'd be much more convenient and less error prone if it worked this way out of the box.

@jzheaux
Copy link
Contributor

jzheaux commented Jun 7, 2023

Thanks for the report, @romangr. I think a customizer like https://github.com/spring-projects/spring-boot/blob/a38d5d0fe0634908ca7faa44607bd646c70b76d1/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/JwkSetUriJwtDecoderBuilderCustomizer.java could be added:

@Bean 
JwtDecoderValidatorCustomizer jwtDecoderValidatorCustomizer(List<OAuth2TokenValidator<Jwt>> claimValidators) {
    return (validator) -> {
        claimValidators.add(validator);
        return new DelegatingOAuth2TokenValidator<>(claimValidators);
    }
}

I've created spring-projects/spring-boot#35783 to get feedback from the Boot team.

@jzheaux jzheaux added in: config An issue in spring-security-config and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 7, 2023
@romangr
Copy link
Author

romangr commented Jun 8, 2023

Nice, thank you!

@romangr
Copy link
Author

romangr commented Jul 13, 2023

This enhancement was implemented in spring-projects/spring-boot#35874

@CanalThomas
Copy link

Hello @romangr, would you have an example that use these changes you made in order to add a custom validator ? I'm quiet new to Spring, the problem you faced is exactly the same that I'm facing now, so I'd appreciate if you could help.

@romangr
Copy link
Author

romangr commented Sep 19, 2023

Hi @CanalThomas, you can simply add a validator bean to your configuration:

  @Bean
  public JwtClaimValidator<String> customJwtClaimValidator() {
    return new JwtClaimValidator<>(
        "claimName",
        actualValue -> "expectedValue".equals(actualValue)
    );
  }

But this feature is not released yet, it's available in the snapshot repository with 3.2.0-M2

@CanalThomas
Copy link

Hi, thanks a lot for that quick response and for you contribution to Spring. Have a good day!

1 similar comment
@CanalThomas
Copy link

Hi, thanks a lot for that quick response and for you contribution to Spring. Have a good day!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: config An issue in spring-security-config type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants