I'm trying to configure Spring Boot and Keycloak for SSO. I've created a basic AngularJS application that do some requests to the Spring boot backend. using this
The Angular app is working fine and now I'm trying to follow the new Spring Boot Keycloak apdater docuementation here
This is my keycloak.json that is in the WEB-INF folder.
{
"realm": "my-backend",
"bearer-only": true,
"realm-public-key": "MIIB...",
"auth-server-url": "http://localhost:8180/auth",
"ssl-required": "external",
"resource": "my-backend",
"principal-attribute": "preferred_username",
"credentials": {
"secret": "a75f55ca-8174-4072-8c60-b545c9ebf7e1"
}
Here is my security configuration :
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
/**
* Registers the KeycloakAuthenticationProvider with the authentication manager.
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
/**
* Defines the session authentication strategy.
*/
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
super.configure(http);
http
.authorizeRequests()
.antMatchers("/api/v1*").hasRole("user")
.antMatchers("/admin/hello*").hasRole("admin")
.anyRequest().permitAll();
}
}
The 2 roles, 'admin' and 'user' are created in Keycloak and the current user has this roles.
@RestController
@RequestMapping("/")
@CrossOrigin("*")
public class PharmaController {
public class Response{
private String message;
public Response(String msg){
this.message = msg;
}
/**
* @return the message
*/
public String getMessage() {
return message;
}
/**
* @param message the message to set
*/
public void setMessage(String message) {
this.message = message;
}
}
@RequestMapping(
path="api/v1/userinfo",
method = RequestMethod.GET)
@ResponseBody
public void getUserInformation(KeycloakAuthenticationToken token) {
if(token != null){
System.out.println("token :" + token);
try {
System.out.println(token.getAccount().getPrincipal().getName());
System.out.println(token.getAccount().getRoles());
} catch (Exception e) {
// TODO: handle exception
}
}else{
System.out.println("User not connected.");
}
}
@RequestMapping(
path="admin/hello",
method = RequestMethod.GET)
@ResponseBody
public Response adminHello(KeycloakAuthenticationToken token) {
return new Response("Hello");
}
}
{"data":"","status":200,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://localhost:8080/api/v1/userinfo","headers":{"Accept":"application/json, text/plain, */*","Access-Control-Allow-Origin":"*","Authorization":"BEARER eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSN2JSQUgtcmUwNnVEMHh4Vlotd1dyWVIycVI0S0pyMDFIZWQ2QmJMNnA4In0.eyJqdGkiOiI3ZDU4ZGM0Yi0wYzgwLTQwZDYtYWE5OC0yNDk5YzEzZTg2NmMiLCJleHAiOjE0ODM5MTY3OTgsIm5iZiI6MCwiaWF0IjoxNDgzOTE2NDk4LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgxODAvYXV0aC9yZWFsbXMvbXktcGhhcm1hIiwiYXVkIjoicGhhcm1hLXdlYmFwcCIsInN1YiI6IjIxMjI2YzNlLWYwY2UtNGRjNC1hYzk0LTRlNTVmZjc4YWRlMSIsInR5cCI6IkJlYXJlciIsImF6cCI6InBoYXJtYS13ZWJhcHAiLCJub25jZSI6Ijg4MWI1MjhhLWFkOTktNDcwYy04YzJiLTlhYjI0MzM2N2IwOCIsImF1dGhfdGltZSI6MTQ4MzkxNjQ5OCwic2Vzc2lvbl9zdGF0ZSI6Ijg4ZmExODJjLTljOTctNGI2Ny1hMTMzLTk5YjFkNmU4OTZiYyIsImFjciI6IjEiLCJjbGllbnRfc2Vzc2lvbiI6IjJiM2FjNDg1LWQ5ZjUtNDc2ZC1hYjQ1LTA2ZGZmM2VjMTQxMiIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjkwMDAiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsInZpZXctcHJvZmlsZSJdfX0sIm5hbWUiOiJVc2VyMSBGTiBVc2VyMSBMTiIsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIxIiwiZ2l2ZW5fbmFtZSI6IlVzZXIxIEZOIiwiZmFtaWx5X25hbWUiOiJVc2VyMSBMTiIsImVtYWlsIjoidXNlcjFAeW91LmNvbSJ9.M1RvECaBV3jvNXRxQzLzS4bfKnK-gQp85mkr9GD8HbOsGRui81pZP3Pb_NJ-ieaQ7pca7tO_06UNeSqbHut7c1APV3_GEGTnwuCkKdbu1QKrVwXSXMWNyt0nu_MOdjhzG3bQat3aG68b744KdCSi5i8OBg2L4I3Zmc6nPX5vklf1U7LUXyvs_bswLPZEy1_VQ_ACu_BSIVA8iv64Nl4ng4QlEc6pyEHbhQ2pKpE7wNIiZe-ndfeQWU5FgnV0Ya16b2Up9ZnFw7fpGHDGjzlIEV_As3K32vON171OuAhTKmIbVnG4kuoijQzeqHmkoB-ldfMKPPlLheSILtHvRn8WkA"}},"statusText":""}
This is the stack trace :
[org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@63858877:org.apache.tomcat.util.net.NioChannel@4d4fa76c:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:51832]], Status in: [OPEN_READ], State out: [OPEN]
2017-01-09 07:11:46.739 DEBUG 14692 --- [nio-8080-exec-2] o.a.coyote.http11.Http11InputBuffer : Received [GET /admin/hello HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Allow-Origin: *
Accept: application/json, text/plain, */*
Origin: http://localhost:9000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
Authorization: BEARER eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSN2JSQUgtcmUwNnVEMHh4Vlotd1dyWVIycVI0S0pyMDFIZWQ2QmJMNnA4In0.eyJqdGkiOiIyMzMzZmI0OC0yMGE2LTQ2YzctODM1YS0wNGRiMDYyNmEyYWEiLCJleHAiOjE0ODM5MTc0MDQsIm5iZiI6MCwiaWF0IjoxNDgzOTE3MTA0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgxODAvYXV0aC9yZWFsbXMvbXktcGhhcm1hIiwiYXVkIjoicGhhcm1hLXdlYmFwcCIsInN1YiI6IjIxMjI2YzNlLWYwY2UtNGRjNC1hYzk0LTRlNTVmZjc4YWRlMSIsInR5cCI6IkJlYXJlciIsImF6cCI6InBoYXJtYS13ZWJhcHAiLCJub25jZSI6IjQwZDc3MzAyLWViNTYtNGFhMS05OTllLTcyNDRiNmY3MTFkYiIsImF1dGhfdGltZSI6MTQ4MzkxNzEwNCwic2Vzc2lvbl9zdGF0ZSI6IjdmODlkODMyLTNkNTktNDc1Yi04NzI3LTRiZGQ5MDc4ODQ5YSIsImFjciI6IjEiLCJjbGllbnRfc2Vzc2lvbiI6IjJiOGNjMzc3LWY1NjUtNGE3NS1iMWY5LWEyNWFlZTY0ZGM3MCIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjkwMDAiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsInZpZXctcHJvZmlsZSJdfX0sIm5hbWUiOiJVc2VyMSBGTiBVc2VyMSBMTiIsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIxIiwiZ2l2ZW5fbmFtZSI6IlVzZXIxIEZOIiwiZmFtaWx5X25hbWUiOiJVc2VyMSBMTiIsImVtYWlsIjoidXNlcjFAeW91LmNvbSJ9.S5Jhrea_JzlXEuMPSfJ9Sd8HdNQyknklfdZFDMH_vaFWHiQShVVQAhM3wbwrz8NoJs3M6iFnkA-kuMPhCUR52y65HJ9mEXSxrUN6hPY4U9mEYIKw_kGVXFf_xOirA8lO9cvEmw7c7p2BN0DWmi85RshqhM6CEdGAtIL4z-rl-b3UDJkm9dT3uaMxcYb3l8lq0AkixqnaI8seFLdLgacdhfMblnKuyP6bgWUD2jl2X9ruVGfIHQeBdA19WesMJKHm9XqQaF1mjl0AM0k52bU7GZZ6cOD3yFwl2RMAUMlUPPyX9xq2L5kNEsgYdw4qlgdvjLaX_HipqHh7JHQksJv4Sg
Referer: http://localhost:9000/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6,fr;q=0.4
]
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.authenticator.AuthenticatorBase : Security checking request GET /admin/hello
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] org.apache.catalina.realm.RealmBase : No applicable constraints defined
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.authenticator.AuthenticatorBase : Not subject to any constraint
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] org.apache.tomcat.util.http.Parameters : Set encoding to UTF-8
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@2683da6f
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /admin/hello' doesn't match 'OPTIONS /**
2017-01-09 07:11:46.741 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2017-01-09 07:11:46.741 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2017-01-09 07:11:46.742 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2017-01-09 07:11:46.742 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2017-01-09 07:11:46.743 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2017-01-09 07:11:46.743 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 5 of 13 in additional filter chain; firing Filter: 'KeycloakPreAuthActionsFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:8080/admin/hello
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 6 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /admin/hello' doesn't match 'POST /sso/logout
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 7 of 13 in additional filter chain; firing Filter: 'KeycloakAuthenticationProcessingFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/sso/login']
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/admin/hello'; against '/sso/login'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=Authorization, expectedHeaderValue=null]
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : matched
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Request is to process authentication
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Attempting Keycloak authentication
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] a.s.a.SpringSecurityRequestAuthenticator : Completing bearer authentication. Bearer roles: [uma_authorization]
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] o.k.adapters.RequestAuthenticator : User 'user1' invoking 'http://localhost:8080/admin/hello' on client 'pharma-backend'
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] o.k.adapters.RequestAuthenticator : Bearer AUTHENTICATED
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Auth outcome: AUTHENTICATED
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.authentication.ProviderManager : Authentication attempt using org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider
2017-01-09 07:11:46.872 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2017-01-09 07:11:46.889 DEBUG 14692 --- [nio-8080-exec-2] o.k.a.s.management.HttpSessionManager : Session created: D309F84825BE807C7B34F16B111E92CD
2017-01-09 07:11:46.890 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Registering session D309F84825BE807C7B34F16B111E92CD, for principal user1
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Authentication success using bearer token/basic authentication. Updating SecurityContextHolder to contain: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 8 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 9 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : SecurityContextHolder not populated with anonymous token, as it already contained: 'org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] s.CompositeSessionAuthenticationStrategy : Delegating to org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy@29a23c3d
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Registering session D309F84825BE807C7B34F16B111E92CD, for principal user1
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Removing session D309F84825BE807C7B34F16B111E92CD from principal's set of registered sessions
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Removing principal user1 from registry
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] s.CompositeSessionAuthenticationStrategy : Delegating to org.springframework.security.web.csrf.CsrfAuthenticationStrategy@20f0cc02
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@a08a84cd: Authentication: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@1a43aa14
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /admin/hello' doesn't match 'POST /sso/logout
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/admin/hello'; against '/api/v1*'
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/admin/hello'; against '/admin/hello*'
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /admin/hello; Attributes: [hasRole('ROLE_admin')]
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}
2017-01-09 07:11:46.895 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@58311096, returned: -1
2017-01-09 07:11:46.896 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115) ~[spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
...
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5ca0c4c5
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@a08a84cd: Authentication: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@1a43aa14
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@2683da6f
2017-01-09 07:11:46.900 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost] : Processing ErrorPage[errorCode=0, location=/error]
2017-01-09 07:11:46.901 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/error]
2017-01-09 07:11:46.902 DEBUG 14692 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2017-01-09 07:11:46.904 DEBUG 14692 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]
2017-01-09 07:11:46.904 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'basicErrorController'
2017-01-09 07:11:46.904 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/error] is: -1
2017-01-09 07:11:46.927 DEBUG 14692 --- [nio-8080-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Written [{timestamp=Mon Jan 09 07:11:46 MYT 2017, status=403, error=Forbidden, message=Access is denied, path=/admin/hello}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@45db4b8b]
2017-01-09 07:11:46.927 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2017-01-09 07:11:46.927 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Successfully completed request
2017-01-09 07:11:46.928 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Disabling the response for futher output
2017-01-09 07:11:46.928 DEBUG 14692 --- [nio-8080-exec-2] o.apache.coyote.http11.Http11Processor : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@63858877:org.apache.tomcat.util.net.NioChannel@4d4fa76c:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:51832]], Status in: [OPEN_READ], State out: [OPEN]
I went through the same and here are my findings.
org.springframework.security.access.vote.RoleVoter assumes that your roles start from
private String rolePrefix = "ROLE_";
There is no such assumption in Keycloak (unless you name all your roles ROLE_someName), therefore no roles are actually found matching.
Similar explanation can be obtained from Spring Security Javadoc of SecurityExpressionOperations class for hasRole method
This is similar to {@link #hasAuthority(String)} except that this method implies
that the String passed in is a role. For example, if "USER" is passed in the
implementation may convert it to use "ROLE_USER" instead. The way in which the role
is converted may depend on the implementation settings.
To sum it up, I've ended with exactly the same solution as you did, using hasAuthority instead of hasRole now.
I solved it myself by replacing hasRole() by hasAuthority(). I still don't know why keycloak role is mapped to spring security authority. Any explaination is welcomed. Thank you.
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