Skip to content

Setting clock-skew according to documentation disables security features #18230

@RainerGanss

Description

@RainerGanss

Expected Behavior

I want to be able to set the clock-skew (ideally per property) and not change anything else.

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          clock-skew: 5m  # does not exist - would have been great

Current Behavior

According to OAuth 2.0 Resource Server JWT the correct way to do so is:

@Bean
JwtDecoder jwtDecoder() {
     NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
             JwtDecoders.fromIssuerLocation(issuerUri);

     OAuth2TokenValidator<Jwt> withClockSkew = new DelegatingOAuth2TokenValidator<>(
            new JwtTimestampValidator(Duration.ofSeconds(60)),
            new JwtIssuerValidator(issuerUri));

     jwtDecoder.setJwtValidator(withClockSkew);

     return jwtDecoder;
}

This works - but it is dangerous in my opinion. I also set the two (very important) properties

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: xxx
          jwk-set-uri: xxx

which triggers the auto configuration OAuth2ResourceServerJwtConfiguration

@Bean
@ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
JwtDecoder jwtDecoderByJwkKeySetUri(ObjectProvider<JwkSetUriJwtDecoderBuilderCustomizer> customizers) {
	JwkSetUriJwtDecoderBuilder builder = NimbusJwtDecoder.withJwkSetUri(this.properties.getJwkSetUri())
		.jwsAlgorithms(this::jwsAlgorithms);
	customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
	NimbusJwtDecoder nimbusJwtDecoder = builder.build();
	String issuerUri = this.properties.getIssuerUri();
	OAuth2TokenValidator<Jwt> defaultValidator = (issuerUri != null)
			? JwtValidators.createDefaultWithIssuer(issuerUri) : JwtValidators.createDefault();
	nimbusJwtDecoder.setJwtValidator(getValidators(defaultValidator));
	return nimbusJwtDecoder;
}

If I understand it correctly, if I follow the documentation the JwtDecoder will NOT use the JwkSetUri property, the jwsAlgorithms and also not use the default validators. Both methods JwtValidators.createDefaultWithIssuer(issuerUri) : JwtValidators.createDefault(); will not only create the timestamp validator (and issuer validator if available) but also the X509CertificateThumbprintValidator (which is package visible btw). This one will also be missing if I configure the clock skew according to the documentation.

Context

What I implemented now is the following:

@Value("${xxx.jwt.clock-skew:PT5M}")
private Duration clockSkew;

@Bean
public BeanPostProcessor jwtDecoderClockSkewPostProcessor(final OAuth2ResourceServerProperties properties) {
    return new BeanPostProcessor() {
        @Override
        public Object postProcessAfterInitialization(@Nonnull final Object bean, @Nonnull final String beanName) {
            if (bean instanceof final NimbusJwtDecoder jwtDecoder) {
                jwtDecoder.setJwtValidator(createValidators(properties));
            }
            return bean;
        }
    };
}

private OAuth2TokenValidator<Jwt> createValidators(final OAuth2ResourceServerProperties properties) {
    final List<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();
    validators.add(new JwtTimestampValidator(clockSkew));

    final String issuerUri = properties.getJwt().getIssuerUri();
    if (issuerUri != null) {
        validators.add(new JwtIssuerValidator(issuerUri));
    }

    return JwtValidators.createDefaultWithValidators(validators);
}

My opinion:

  • The static methods at JwtValidators should maybe be replaced by a builder? That would have helped.
  • The auto configuration of the JwtDecoder seems hard to combine with other properties (like the clock-skew). Tapping into this configuration like I did was pretty tricky (until I arrived at the solution above).

Cheers,
Rainer

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions