I`m setting up a Keycloak instance to work with spring boot app with spring security included. I use postman to test the service. I start with getting new access token and that works fine. When I do a HTTP GET call to secured endpoint - everything goes ok, staff is returned. But when I do a HTTP POST/PUT/DELETE call to secured endpoint Keycloak says Error 403 Forbidden. Please take a look and tell me what goes wrong.
I have already tested http.csrf().disable() option, and then works fine, but it is not the solution for production.
SecurityConfig.java
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
.antMatchers( "/api/**").hasRole("my_admin")
.anyRequest().permitAll();
}
application.yml:
keycloak:
auth-server-url: http://localhost:11080/auth
realm: myrealm
resource: myclient
public-client: true
principal-attribute: preferred_username
ssl-required: external
use-resource-role-mappings: true
Some logs from application (keycloak trace log level):
2019-04-01 14:04:54.741 DEBUG 2952 --- [io-1080-exec-10] o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:1080/api/my-endpoint
2019-04-01 14:04:54.741 DEBUG 2952 --- [io-1080-exec-10] .k.a.t.AbstractAuthenticatedActionsValve : AuthenticatedActionsValve.invoke /api/my-endpoint
2019-04-01 14:04:54.741 DEBUG 2952 --- [io-1080-exec-10] o.k.a.AuthenticatedActionsHandler : AuthenticatedActionsValve.invoke http://localhost:1080/api/my-endpoint
2019-04-01 14:04:54.741 DEBUG 2952 --- [io-1080-exec-10] o.k.a.AuthenticatedActionsHandler : Policy enforcement is disabled.
2019-04-01 14:04:54.742 DEBUG 2952 --- [io-1080-exec-10] o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:1080/error
2019-04-01 14:04:54.743 DEBUG 2952 --- [io-1080-exec-10] f.KeycloakAuthenticationProcessingFilter : Request is to process authentication
2019-04-01 14:04:54.743 DEBUG 2952 --- [io-1080-exec-10] f.KeycloakAuthenticationProcessingFilter : Attempting Keycloak authentication
2019-04-01 14:04:54.743 TRACE 2952 --- [io-1080-exec-10] o.k.adapters.RequestAuthenticator : --> authenticate()
2019-04-01 14:04:54.743 TRACE 2952 --- [io-1080-exec-10] o.k.adapters.RequestAuthenticator : try bearer
2019-04-01 14:04:54.743 DEBUG 2952 --- [io-1080-exec-10] o.k.a.BearerTokenRequestAuthenticator : Found [1] values in authorization header, selecting the first value for Bearer.
2019-04-01 14:04:54.743 DEBUG 2952 --- [io-1080-exec-10] o.k.a.BearerTokenRequestAuthenticator : Verifying access_token
2019-04-01 14:04:54.743 TRACE 2952 --- [io-1080-exec-10] o.k.a.BearerTokenRequestAuthenticator : access_token: eyJhbs...blablab....signature
2019-04-01 14:04:54.744 DEBUG 2952 --- [io-1080-exec-10] o.k.a.BearerTokenRequestAuthenticator : successful authorized
2019-04-01 14:04:54.744 TRACE 2952 --- [io-1080-exec-10] o.k.a.RefreshableKeycloakSecurityContext : checking whether to refresh.
2019-04-01 14:04:54.744 TRACE 2952 --- [io-1080-exec-10] org.keycloak.adapters.AdapterUtils : useResourceRoleMappings
2019-04-01 14:04:54.744 TRACE 2952 --- [io-1080-exec-10] org.keycloak.adapters.AdapterUtils : Setting roles:
2019-04-01 14:04:54.744 TRACE 2952 --- [io-1080-exec-10] org.keycloak.adapters.AdapterUtils : role: my_admin
2019-04-01 14:04:54.744 DEBUG 2952 --- [io-1080-exec-10] a.s.a.SpringSecurityRequestAuthenticator : Completing bearer authentication. Bearer roles: [my_admin]
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] o.k.adapters.RequestAuthenticator : User 'my_user' invoking 'http://localhost:1080/error' on client 'myclient'
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] o.k.adapters.RequestAuthenticator : Bearer AUTHENTICATED
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] f.KeycloakAuthenticationProcessingFilter : Auth outcome: AUTHENTICATED
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] f.KeycloakAuthenticationProcessingFilter : Authentication success using bearer token/basic authentication. Updating SecurityContextHolder to contain: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@fb0506b7: Principal: my_user; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@ecf147d; Granted Authorities: ROLE_my_admin
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] o.k.a.AuthenticatedActionsHandler : AuthenticatedActionsValve.invoke http://localhost:1080/error
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] o.k.a.AuthenticatedActionsHandler : Policy enforcement is disabled.
you should do two followings config:
http.csrf().disable()
I found out that I have not used CSRF token in ajax requests. Spring Security automatically enables CSRF protection. CSRF token is automatically generated for first call of web service and it has session scope. You need to save that token in meta tag. It is required to include CSRF token to every non-GET request (GET requests are not needed to be protected with CSRF token, beacuse they are designed to non-modifying API calls).
Solution: Just need to include that line in header of html page (thymeleaf):<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<meta id="_csrf" name="_csrf" th:content="${_csrf.token}"/>
and use it in ajax call in header:headers: {
'X-CSRF-TOKEN': $('#_csrf').attr('content')
},
It is a CSRF protection provided by Spring Security. Do you really need this protection with Keycloak token? The token is only included in the cookie or it is also present in the Authorization header?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With