Issue
My project is using Spring Boot 1.5.6, the goal is to have two separate login forms, one for standard users and one for admins.
My problem is that Spring ignores the config paramter for loginProcessingUrl
, for the admin as well as for the user area.
It looks like there's never a handler registered for the POST request?
The config below is an adapted version from this tutorial: http://www.baeldung.com/spring-security-two-login-pages
WebSecurityConfig
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Autowired
private UserDetailsService userDetailsService;
@Configuration
@Order(1)
public static class AdminSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
DaoAuthenticationProvider daoAuthenticationProvider;
public AdminSecurityConfigurationAdapter() {
super();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/admin/*")
.authorizeRequests()
.anyRequest()
.hasRole("ADMIN")
.and()
.formLogin()
.loginPage("/loginAdmin")
.loginProcessingUrl("/doAdminLogin")
.failureUrl("/loginAdmin?error=loginError")
.defaultSuccessUrl("/admin/dashboard")
//TODO implement logout pages
.and()
.logout()
.logoutUrl("/admin_logout")
.logoutSuccessUrl("/protectedLinks")
.deleteCookies("JSESSIONID")
.and()
.exceptionHandling()
.accessDeniedPage("/403")
.and()
.csrf().disable();
}
}
@Configuration
@Order(2)
public static class UserSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
DaoAuthenticationProvider daoAuthenticationProvider;
public UserSecurityConfigurationAdapter() {
super();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider);
}
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/user/*")
.authorizeRequests()
.anyRequest()
.hasRole("USER")
.and()
.formLogin()
.loginPage("/loginUser")
.loginProcessingUrl("/doUserLogin")
.failureUrl("/loginUser?error=loginError")
.defaultSuccessUrl("/user/start")
//TODO configure logout
.and()
.logout()
.logoutUrl("/user_logout")
.logoutSuccessUrl("/protectedLinks")
.deleteCookies("JSESSIONID")
.and()
.exceptionHandling()
.accessDeniedPage("/403")
.and()
.csrf().disable();
}
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder(11);
}
Here's the relevant part of loginAdmin.html:
<form name="f" action="doAdminLogin" method="POST"> <input type="text" name="username" placeholder="Username" required=""> <input type="password" name="password" placeholder="Passwort" required=""> <button class="btn1">Submit</button> </form>
(The version for loginUser.html is basically the same, so I'll omit it here.)
After clicking the Submit button, Spring returns just returns a 404 message. Here's the debug log for the POST request:
Reqest Log
o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@3da35d95
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/doAdminLogin'; against '/admin/*'
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/doAdminLogin'; against '/user/*'
o.s.security.web.FilterChainProxy : /doAdminLogin has no matching filters
o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing POST request for [/doAdminLogin]
s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /doAdminLogin
s.w.s.m.m.a.RequestMappingHandlerMapping : Did not find handler method for [/doAdminLogin]
o.s.w.s.handler.SimpleUrlHandlerMapping : Matching patterns for request [/doAdminLogin] are [/**]
o.s.w.s.handler.SimpleUrlHandlerMapping : URI Template variables for request [/doAdminLogin] are {}
o.s.w.s.handler.SimpleUrlHandlerMapping : Mapping [/doAdminLogin] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[ServletContext resource [/], class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@1bdb3e41]]] and 1 interceptor
o.s.web.cors.DefaultCorsProcessor : Skip CORS processing: request is from same origin
o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
o.s.web.servlet.DispatcherServlet : Successfully completed request
Below is the part of the startup log regarding the RequestMappingHandlers:
Startup Log
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin || /admin/dashboard]}" onto public java.lang.String org.app.controller.web.DashboardController.dashboard(java.lang.String,org.springframework.ui.Model)
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/loginUser]}" onto public java.lang.String org.app.controller.web.LoginController.loginUser()
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/loginAdmin]}" onto public java.lang.String org.app.controller.web.LoginController.loginAdmin()
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/user/rsvp]}" onto public java.lang.String org.app.controller.web.RsvpController.dashboard(java.lang.String,org.springframework.ui.Model)
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto 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)
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
It looks to me like the loginProcessingUrl config parameters just gets lost?
Any help would be greatly appreciated!
Solution
According to the baeldung tutorial it is the
antMatchers
definition:
Users: http.antMatcher("/user*")
and loginUrl loginProcessingUrl("/user_login")
In this case antMatcher matches with the loginProcessingUrl definition
The new implementation has the following definition:
.antMatcher("/user/*")
and loginUrl loginProcessingUrl("/doUserLogin")
In this case antMatcher doesn't match with the loginProcessingUrl definition
Possible Solution (in this options the login forms have to change the post method accordingly to the new loginProcessUrl that match with anMatcher defintion)
Change the loginProcessUrl in order to match to anMatcher("/users/*)
.loginProcessingUrl("/user/login")
And finally to the same to the "admin" section.
Hope this info helps you.
Answered By - Daniel C.
Answer Checked By - Pedro (JavaFixing Volunteer)