DrTeeth
DrTeeth

Reputation: 1317

Why does Spring Security reject my Keycloak auth token with "No AuthenticationProvider found"?

I'm trying to figure out why my Spring Boot application is rejecting my Keycloak JWT bearer token with a "No AuthenticationProvider found" error message.


I have a few services running in a docker compose environment:

ui (angular) -> proxy (nginx) -> rest api (spring boot) -> auth service (keycloak)

The angular ui pulls the correct keycloak client from the rest service, and then authenticates without issue. I get back a JWT token, and then turn around and hand that to follow on requests to the rest api in a header Authorization: bearer [token].

In the rest API, I can see the correct bearer token come in as a header:

2022-02-11 01:01:31.411 DEBUG 13 --- [nio-8080-exec-4] o.a.coyote.http11.Http11InputBuffer      : Received [GET /api/v3/accounts HTTP/1.0
X-Real-IP: 192.168.80.1
X-Forwarded-For: 192.168.80.1
Host: rest-api.mylocal.com
Connection: close
Accept: application/json, text/plain, */*
Authorization: Bearer eyJhbGciO...
...
2022-02-11 01:01:31.421 DEBUG 13 --- [nio-8080-exec-4] o.k.adapters.PreAuthActionsHandler       : adminRequest http://rest-api.mylocal.com/api/v3/accounts
...

So the bearer token is there, and with https://jwt.io/ I can verify it's what I would expect:

{
  "exp": 1644515847,
  ...
  "iss": "http://auth-service.mylocal.com/auth/realms/LocalTestRealm",
  ...
  "typ": "Bearer",
  "azp": "LocalTestClient",
  ...
  "allowed-origins": [
    "http://web-ui.mylocal.com"
  ],
  "realm_access": {
    "roles": [
      "offline_access",
      "default-roles-localtestrealm",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "scope": "openid email profile",
  ...
}

Processing continues by the rest api - it contacts the keycloak service and pulls the well known config:

...
2022-02-11 01:01:33.321  INFO 13 --- [nio-8080-exec-4] o.keycloak.adapters.KeycloakDeployment   : Loaded URLs from http://auth-service.mylocal.com/auth/realms/LocalTestRealm/.well-known/openid-configuration
...

Finally it looks like it successfully parses the bearer token apart, grabs the user and authenticates them:

2022-02-11 01:01:33.521 DEBUG 13 --- [nio-8080-exec-4] o.a.h.impl.conn.tsccm.ConnPoolByRoute    : Releasing connection [{}->http://auth-service.mylocal.com:80][null]
2022-02-11 01:01:33.521 DEBUG 13 --- [nio-8080-exec-4] o.a.h.impl.conn.tsccm.ConnPoolByRoute    : Pooling connection [{}->http://auth-service.mylocal.com:80][null]; keep alive indefinitely
2022-02-11 01:01:33.521 DEBUG 13 --- [nio-8080-exec-4] o.a.h.impl.conn.tsccm.ConnPoolByRoute    : Notifying no-one, there are no waiting threads
2022-02-11 01:01:33.530 DEBUG 13 --- [nio-8080-exec-4] o.k.a.rotation.JWKPublicKeyLocator       : Realm public keys successfully retrieved for client LocalTestClient. New kids: [8a7dIQFASdC8BHa0mUWwZX7RBBJSeJItdmzah0Ybpcw]
2022-02-11 01:01:33.546 DEBUG 13 --- [nio-8080-exec-4] o.k.a.BearerTokenRequestAuthenticator    : successful authorized
2022-02-11 01:01:33.550 TRACE 13 --- [nio-8080-exec-4] o.k.a.RefreshableKeycloakSecurityContext : checking whether to refresh.
2022-02-11 01:01:33.550 TRACE 13 --- [nio-8080-exec-4] org.keycloak.adapters.AdapterUtils       : useResourceRoleMappings
2022-02-11 01:01:33.550 TRACE 13 --- [nio-8080-exec-4] org.keycloak.adapters.AdapterUtils       : Setting roles:
2022-02-11 01:01:33.555 DEBUG 13 --- [nio-8080-exec-4] a.s.a.SpringSecurityRequestAuthenticator : Completing bearer authentication. Bearer roles: []
2022-02-11 01:01:33.556 DEBUG 13 --- [nio-8080-exec-4] o.k.adapters.RequestAuthenticator        : User 'bf7307ca-9352-4a02-b288-0565e2b57292' invoking 'http://rest-api.mylocal.com/api/v3/accounts' on client 'LocalTestClient'
2022-02-11 01:01:33.556 DEBUG 13 --- [nio-8080-exec-4] o.k.adapters.RequestAuthenticator        : Bearer AUTHENTICATED
2022-02-11 01:01:33.556 DEBUG 13 --- [nio-8080-exec-4] f.KeycloakAuthenticationProcessingFilter : Auth outcome: AUTHENTICATED

and then immediately after that fails with the No AuthenticationProvider found error:

2022-02-11 01:01:33.559 TRACE 13 --- [nio-8080-exec-4] f.KeycloakAuthenticationProcessingFilter : Failed to process authentication request

org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:234) ~[spring-security-core-5.5.1.jar!/:5.5.1]

I'm at a loss how it can say Bearer AUTHENTICATED followed by Auth outcome: AUTHENTICATED followed by No AuthenticationProvider found... I'm assuming it somehow can't convert this bearer token into a Keycloak token, even though it definitely came from my Keycloak server.

My app config:

@ComponentScan({"com.mycompany"})
@Configuration
@EnableJpaRepositories(basePackages = "com.mycompany")
@EntityScan("com.mycompany")
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class ApplicationConfiguration
        extends KeycloakWebSecurityConfigurerAdapter {

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        super.configure(http);

        http
                .authorizeRequests()
                // These paths (comma separated) are allowed to all
                .antMatchers("/api/v3/auth/config").permitAll()
                .and()
                .authorizeRequests()
                // Everything else should be authenticated
                .anyRequest().authenticated()
                .and()
                .csrf().disable();
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new NullAuthenticatedSessionStrategy();
    }

    @Bean
    public KeycloakConfigResolver keycloakConfigResolver() {
        // This just pulls the Keycloak config from a DB instead of the config file
        return new CustomKeycloakConfigResolver();

        // return new KeycloakSpringBootConfigResolver();
    }
}

Upvotes: 1

Views: 1510

Answers (1)

DrTeeth
DrTeeth

Reputation: 1317

Missing the global config to autowire in a Keycloak auth provider:

    @Autowired
    public void configureGlobal(final AuthenticationManagerBuilder auth)
            throws Exception {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider =
                keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
                new SimpleAuthorityMapper()
        );
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

Upvotes: 2

Related Questions