Skip to content

Support customization of JwtAuthenticationProvider and BearerTokenResolver in multi-tenant systems (related to JwtIssuerAuthenticationManagerResolver) #8648

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

Closed
AbstractConcept opened this issue Jun 3, 2020 · 1 comment
Assignees
Labels
status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement

Comments

@AbstractConcept
Copy link

Expected Behavior

It should be possible to override / customize BearerTokenResolver and JwtAuthenticationProvider inside JwtIssuerAuthenticationManagerResolver class, in a multi-tenant environment, so that the end-user can set non-standard behavior that may be desired (for example, custom JWT parsing).

Current Behavior

Customization is not possible at all, end-user is forced to use predefined implementations inside JwtIssuerAuthenticationManagerResolver, and this leads to errors if JWTs contain something uncommon, same if there's something specific with Bearer Tokens.

Context

Please, see also #8535 for the original issue regarding BearerTokenResolver, as the scope of it would ideally be included in a PR that could be a result of this issue.
Additionally, this could be related to #6778, at least to some extent.

The context explanation will be mostly about TrustedIssuerJwtAuthenticationManagerResolver part of the issue, but it's very similar to JwtClaimIssuerConverter part.

Using an external oauth2ResourceServer, in a multi-tenant environment, it should be possible to override / select a custom JwtAuthenticationProvider with a custom JwtAuthenticationConverter, as not all of the JWT tokens are the same, and this leads to errors.

Currently, according to the official documentation (https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2resourceserver-multitenancy), if there is a need to support multi-tenancy by JWT Claim, one can use JwtIssuerAuthenticationManagerResolver that has to be configured by a class extending WebSecurityConfigurerAdapter, however, it comes with an overriden

public AuthenticationManager resolve(String issuer) method in the TrustedIssuerJwtAuthenticationManagerResolver static class, that contains:

  1. a predefined, hardcoded JwtAuthenticationProvider,
  2. which in turn contains a predefined, hardcoded JwtAuthenticationConverter,
  3. which in turn contains a predefined, hardcoded JwtGrantedAuthoritiesConverter, the root of my problems.

Normally, the issue could be solved by configuring a Customizer<JwtConfigurer> within the HttpSecurity DSL, but OAuth2ResourceServerConfigurer runs the validateConfiguration() method that throws an IllegalStateException because, quote:

If an authenticationManagerResolver() is configured, then it takes precedence over any jwt() or opaqueToken() configuration

That's of course understandable, however, there should be a way to configure your own Customizer/JwtGrantedAuthoritiesConverter.

Currently, I have solved my own issue by using my own implementation of a JwtIssuerAuthenticationManagerResolver, that I have used instead of the 'official' one, that basically creates a new JwtAuthenticationConverter and sets my custom JwtGrantedAuthoritiesConverter, but I am willing to work on a PR, to provide a more "official" solution.

Some additional information would be great though: could the solution be based on allowing the end-user to provide his own BearerTokenResolver / JwtAuthenticationProvider, that will take priority over the default one?

@AbstractConcept AbstractConcept added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels Jun 3, 2020
@jzheaux
Copy link
Contributor

jzheaux commented Jun 4, 2020

@AbstractConcept, thanks for the feedback and the ideas. Let's take them one at a time:

provide his one BearerTokenResolver

I see you've already found #8535 - I look forward to your contribution!

provider his one ... JwtAuthenticationProvider

Since JwtIssuerAuthenticationManagerResolver is all about converting the JWT's issuer into an AuthenticationManager, I imagine what you'd want here is the ability to configure a strategy that can supply a JwtAuthenticationProvider for a given issuer.

This is the intent behind the AuthenticationManagerResolver<String> constructor. For example, you can do:

@Component
public class MyAuthenticationManagerResolver 
        implements AuthenticationManagerResolver<String> {
    private Map<String, AuthenticationManager> authenticationManagers = ...;

    public AuthenticationManager resolve(String issuer) {
        return authenticationManagers.get(issuer);
    }

    public void addTrustedIssuer(String issuer) {
        AuthenticationManager authenticationManager = // ... your by-issuer customizations
        this.authenticationManagers.put(issuer, authenticationManager);
    }
}

// ...

@Autowired
MyAuthenticationManagerResolver resolver;

protected void configure(HttpSecurity http) {
    http
        // ...
        .oauth2ResourceServer(oauth2 -> oauth2
            .authenticationManagerResolver(
                    new JwtIssuerAuthenticationManagerResolver(this.resolver))
        );
}

Since I believe this addresses your issue I'll close this ticket, but please re-open if you feel there's more to discuss.

@jzheaux jzheaux closed this as completed Jun 4, 2020
@jzheaux jzheaux added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 4, 2020
@jzheaux jzheaux self-assigned this Jun 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants