Reputation: 101
I am trying to configure Spring Security using Java configuration with Spring Boot.
My WebSecurityConfig class has a configure method like this
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/login", "/css/**", "/js/**", "/img/**", "/bootstrap/**" ).permitAll()
.antMatchers("/individual", "/application", "/upload").hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
.successHandler(successHandler);
}
I get the login page fine for unauthenticated users, and the user authenticates. However, when trying to access the url /individual I get a 403 error and this in the log
2015-11-12 13:59:46.373 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/individual'; against '/'
2015-11-12 13:59:46.373 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/individual'; against '/login'
2015-11-12 13:59:46.373 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/individual'; against '/css/**'
2015-11-12 13:59:46.373 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/individual'; against '/js/**'
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/individual'; against '/img/**'
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/individual'; against '/bootstrap/**'
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/individual'; against '/individual'
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /individual; Attributes: [hasRole('ROLE_USER')]
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@4c2eda81: Principal: org.springframework.security.core.userdetails.User@4c0ab982: Username: [email protected]; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffc7f0c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 6E0BF830C070912EAC0050D1285D5CF9; Granted Authorities: USER
2015-11-12 13:59:46.374 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@6f192fd7, returned: -1
2015-11-12 13:59:46.386 DEBUG 34468 --- [nio-8090-exec-6] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is not anonymous); delegating to AccessDeniedHandler
if I replace .hasRole("USER")
with .authenticated()
it works and the user gets the page desired, but no role is being checked.
I cannot figure out how to specify that the user must be authenticated and have the role USER. I have looked at many examples and tried many combinations but I cannot get it to work as desired. Most of the examples refer to older XML based configuration as well, which I want to avoid.
What do I need to do to specify that certain URL patterns can be accessed with authenticated users with certain roles?
As requested, the success handler method looks like this
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth)
throws IOException, ServletException {
// Here we want to check whether the user has already started the process and redirect to the appropriate stage
log.info("User {} has been authenticated", auth.getName());
if(auth.getName().equals("[email protected]"))
{
redirectStrategy.sendRedirect(request, response, "/individual");
return;
}
redirectStrategy.sendRedirect(request, response, "/application");
}
Note that this is early stage WIP, per the comments in the code. I know this works as the log message appears and without the role check in the WebSecurity class the desired page is served.
EDIT : noticed a typo in the question referring to roleService.getDefaultRole(). This was a mistake and has been corrected.
Upvotes: 5
Views: 18410
Reputation: 101
I have solved my own question, thanks in part to the various suggestions here making me research it differently. Also noted that FrontierPsychiatrist provided the answer as well, but I did not spot the response while I was working on it.
The problem is that Spring interchangably refers to ROLES and AUTHORITIES.
Having implemented the UserDetailsService
interface to allow Spring to load user records from the application database, I was creating an instance of org.springframework.security.core.userdetails.User
and setting the granted authorities. It can be seen in the log statements that the User object had that - Granted Authorities: USER
, but then my security config was checking for a role, and failing. The solution, simply, was to check for an authority instead. I have also cleaned up the config to separate the URL patterns to be ignored from security from the authentication & authorisation. Complete code snippet below
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers( "/css/**", "/js/**", "/img/**", "/bootstrap/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/individual","/application", "/upload").hasAuthority("USER")
.and()
.formLogin()
.loginPage("/login")
.successHandler(successHandler)
.permitAll()
.and()
.logout()
.deleteCookies("remove")
.logoutSuccessUrl("/login?logout")
.permitAll();
}
I really hope this helps others when using Java based configuration with Spring 4 MVC.
Upvotes: 1
Reputation: 1433
I think your logged in user [email protected] has the wrong authorities set. In the log you can see the authorities are ['USER'], but since you are working with roles it should be ['ROLE_USER']. Where do you define the authorities for [email protected]?
Otherwise try switching
.antMatchers("/individual", "/application", "/upload").hasRole("USER")
to
.antMatchers("/individual", "/application", "/upload").hasAuthority("USER")
Upvotes: 13
Reputation: 1019
Modify your configuration something like this.
http.authorizeRequests().antMatchers("/individual","/application", "/upload")
.hasRole("USER").and().authorizeRequests().anyRequest()
.authenticated().and()
.formLogin()
.loginPage("/login")
.successHandler(successHandler);
and if you don't want all the request to be authenticated you can replace anyRequest()
method with antMatchers("/urls-goes-here")
Upvotes: 0
Reputation: 1354
Here's a tutorial that does what you're trying to implement:
http://www.jcombat.com/spring/custom-authentication-success-handler-with-spring-security
I'm guessing you forgot to set the session attributes in your handler:
HttpSession session = request.getSession();
session.setAttribute("uname", authUser.getUsername());
session.setAttribute("authorities", authentication.getAuthorities());
Upvotes: -1