Extract authentication from Bearer Token after Issuer Resolver with Spring Security 5

Viewed 1986

I created a resource server with the new Spring Resource Server.

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>

And I'll have two different providers, so I created a JwtIssuerAuthenticationManagerResolver.

JwtIssuerAuthenticationManagerResolver resolver =
            new JwtIssuerAuthenticationManagerResolver(
                    "http://localhost:8180/auth/realms/externalauth",
                    "http://localhost:8080/auth/realms/myauth");

...

protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2ResourceServer(oauth2 ->
                        oauth2.authenticationManagerResolver(resolver));
}

And I want to after token is considered a valid token, get it and extract and set SecurityContext.

I tried with BearerTokenResolver but didn't work, also I tried with implements Converter<Jwt, AbstractAuthenticationToken>.

But I'm getting this error:

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

Thanks in advance

1 Answers

I had the similar exception when I tried implement customer JwtAuthenticationConverter for keycloak. Not sure if this related to your problem but found a solution as described below.

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {

  Map<String, AuthenticationManager> authenticationManagers = new HashMap<>();

  JwtIssuerAuthenticationManagerResolver authenticationManagerResolver =
     new JwtIssuerAuthenticationManagerResolver(authenticationManagers::get);

  @Override
  protected void configure(HttpSecurity http) throws Exception {

  List<String> issuers = new ArrayList<>();
  issuers.add("http://localhost:4040/auth/realms/branch1");
  issuers.add("http://localhost:4040/auth/realms/branch2");

  issuers.stream().forEach(issuer -> addManager(authenticationManagers, issuer));

  http
        .httpBasic().disable()
        .authorizeRequests(auth -> auth

              .anyRequest().authenticated()
        ).oauth2ResourceServer(oauth2ResourceServer -> {
     oauth2ResourceServer.authenticationManagerResolver(this.authenticationManagerResolver);
  });
}

public void addManager(Map<String, AuthenticationManager> authenticationManagers, String issuer) {
  JwtAuthenticationProvider authenticationProvider = new JwtAuthenticationProvider(JwtDecoders.fromOidcIssuerLocation(issuer));
  authenticationProvider.setJwtAuthenticationConverter(getJwtAuthenticationConverter());
  authenticationManagers.put(issuer, authenticationProvider::authenticate);
}

private Converter<Jwt, AbstractAuthenticationToken> getJwtAuthenticationConverter() {
  JwtAuthenticationConverter conv = new JwtAuthenticationConverter();

        conv.setJwtGrantedAuthoritiesConverter(jwt -> {

           Map<String, Object> realmAccess = (Map<String,Object>) jwt.getClaims().get("realm_access");
           if(realmAccess == null) {
              return new ArrayList<>();
           }

           List<String > roles = (List<String>) realmAccess.get("roles");
           return roles.stream()
                 .map(r -> "ROLE_" + r)
                 .map(SimpleGrantedAuthority::new)
                 .collect(Collectors.toList());
        });
        return conv;
  }
Related