Reputation: 1317
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
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