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

Support OIDC as part of autoconfiguration #86

Closed
TheFonz2017 opened this issue May 28, 2019 · 4 comments
Closed

Support OIDC as part of autoconfiguration #86

TheFonz2017 opened this issue May 28, 2019 · 4 comments
Labels
enhancement New feature or request

Comments

@TheFonz2017
Copy link

XsuaaJwtDecoder is a JwtDecoder which needs to be exposed by applications to profit from the XsuaaAudienceValidator. However, the way it is implemented does not properly reflect the Spring Security standard OAuth2TokenValidator configurations

In fact, the way Spring Security auto-configures OAuth2TokenValidators is more involved as can be seen in class org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerJwkConfiguration.
Spring Security checks if the user has configured the spring.security.oauth2.resourceserver.jwt.jwk-set-uri, and if so, will configure a JwtDecoder with the following default JwtValidators (see JwtValidators.createDefault()):

  • JwtTimestampValidator().

If the user configured the spring.security.oauth2.resourceserver.jwt.issuer-uri, however, Spring Security adds the following JwtValidators (see JwtValidators.createDefaultWithIssuer(...)):

  • JwtTimestampValidator()
  • JwtIssuerValidator(issuer)

XsuaaJwtDecoder does not reflect that properly in its implementation:

XsuaaJwtDecoder(XsuaaServiceConfiguration xsuaaServiceConfiguration, int cacheValidityInSeconds, int cacheSize, OAuth2TokenValidator<Jwt>... tokenValidators) {
     ...
     // this is only true in the case where the user did NOT configure the issuer-uri.
     this.tokenValidators.add(new JwtTimestampValidator());

     if (tokenValidators == null) {
	this.tokenValidators.add(new XsuaaAudienceValidator(xsuaaServiceConfiguration));
     } else {
	this.tokenValidators.addAll(Arrays.asList(tokenValidators));
     }
}

A more correct approach would be to replicate the behaviour of Spring Security (as given in org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerJwkConfiguration):

// 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.

/**
 * Auto-configuration class that exposes a JwtDecoder which has the standard
 * Spring Security Jwt validators as well as the XSUAA-specific validators.
 * @See: org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerJwkConfiguration
 */
@Configuration
class XsuaaResourceServerJwkConfiguration {

    private final OAuth2ResourceServerProperties properties;

    XsuaaResourceServerJwkConfiguration(OAuth2ResourceServerProperties properties) {
        this.properties = properties;
    }

    @Bean
    @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
    @ConditionalOnMissingBean
    public JwtDecoder jwtDecoderByJwkKeySetUri() {
        String jwkSetUri = this.properties.getJwt().getJwkSetUri();
        OAuth2TokenValidator<Jwt> defaultValidators = JwtValidators.createDefault();
        OAuth2TokenValidator<Jwt> xsuaaAudienceValidator = new XsuaaAudienceValidator(...);
        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() {
        String oidcIssuerLocation = this.properties.getJwt().getIssuerUri();
        OAuth2TokenValidator<Jwt> defaultValidators = JwtValidators.createDefaultWithIssuer(oidcIssuerLocation);
        OAuth2TokenValidator<Jwt> xsuaaAudienceValidator = new XsuaaAudienceValidator(...);
        OAuth2TokenValidator<Jwt> combinedValidators = new DelegatingOAuth2TokenValidator<>(defaultValidators, xsuaaAudienceValidator);
        NimbusJwtDecoderJwkSupport jwtDecoder = (NimbusJwtDecoderJwkSupport) JwtDecoders.fromOidcIssuerLocation(oidcIssuerLocation);
        jwtDecoder.setJwtValidator(combinedValidators);
        return jwtDecoder;
    }
}
@nenaraab
Copy link
Contributor

nenaraab commented Jun 17, 2019

Hi @TheFonz2017,

thanks for the request. Your request basically does not consider multi-tenancy support.

  • The Jwt Web keys can differentiate by tenant (aka subdomain) and
    that's why we can not make use of a "static" NimbusJwtDecoder object. See XsuaaJwtDecoder for your reference.
  • As of now we can not leverage the issuer validation, as the openId configuration does not provide the "correct" issuer information, which can vary by tenant, if i've understood correctly. For example: https://authentication.eu10.hana.ondemand.com/.well-known/openid-configuration . This is a known issue .

Further references:

@TheFonz2017
Copy link
Author

Hi Nena,

can you please check the assumption that customers should be able to configure their own tenant-specific public keys for XSUAA? I have a few doubts about it.

Two observations:

  1. If you look at the tenant-specific JWKS endpoint and you compare it to the tenant-unspecific endpoint the keys are identical.
  2. XSUAA is a cloud product provided by SAP. I doubt that a customer should maintain tenant-specific public keys for a piece of software hosted by SAP.

Btw. where would a customer maintain these public keys today? Is there a UI in Cloud cockpit?

As to your second point about the issuer URI: that is currently a limitation of XSUAA.
It returns a wrong issuer URI (containing localhost) in the open ID configuration endpoint.
If this were fixed, configuration would be much simpler - provided that the standard Spring Security behavior is still supported, which it isn't today due to the XSUAA lib's implementation.
However, that is fixed in the PR.

If you are looking for an implementation of the open-id configuration endpoint returning the proper (even tenant-specific) issuer URI, let me know. I have an internal sample implementation available.

Cheers!

@nenaraab
Copy link
Contributor

nenaraab commented Jul 3, 2019

Hi @TheFonz2017

we will consider the OIDC flow in one of our next versions.

Best regards,
Nena

@nenaraab nenaraab changed the title Wrong default OAuth2TokenValidator configurations in XsuaaJwtDecoder Support OIDC as part of autoconfiguration Jul 3, 2019
@nenaraab nenaraab added the enhancement New feature or request label Jul 11, 2019
@nenaraab
Copy link
Contributor

IAS OIDC Token validation is supported by java-security and spring-security for multi-tenant enabled applications.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants