I have built an application by using Spring Boot and Thymeleaf. My application works as supposed in my localhost, but when I package it as a .war and deploy it in a test tomcat server, it prompts the login page and then either redirects me to the error page or brings me back to the login page.
I have tried multiple things, and I think that there is an issue with the way I am handling the formLogin()
inside my SecurityConfig.java class. More specifically, since Tomcat adds the base-url (e.g. from localhost:8080
to serverUrl:8080/reservation
) when uploading my app, the loginProcessingUrl class probably fails to identify the “/process-login” class located on the login.html page.
Please find below my SecurityConfig.java class
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private UserService userService; private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler; private AccessDeniedHandler accessDeniedHandler; @Autowired public SecurityConfig(UserService userService, CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler, AccessDeniedHandler accessDeniedHandler) { this.userService = userService; this.customAuthenticationSuccessHandler = customAuthenticationSuccessHandler; this.accessDeniedHandler = accessDeniedHandler; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authenticationProvider()); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/login-form-page","/resources/**").permitAll() .antMatchers("/", "/new-reservation", "/your-reservations","/all-reservations", "/change-password").hasAnyRole("ADMIN","EMPLOYEE","MANAGER") .antMatchers("/users","/user-reservations","/arrival-date","/duplicate-reservations","/all-reservations","/registration**") .hasAnyRole("ADMIN").and() .formLogin() .loginPage("/login-form-page") .loginProcessingUrl("/process-login") .successHandler(customAuthenticationSuccessHandler) .permitAll() .and() .logout() .logoutUrl("/login-form-page") .permitAll() .and() .exceptionHandling().accessDeniedHandler(accessDeniedHandler); } @Override public void configure(WebSecurity web) { web.ignoring() .antMatchers("/resources/**", "/static/**"); } @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider auth = new DaoAuthenticationProvider(); auth.setUserDetailsService(userService); auth.setPasswordEncoder(passwordEncoder()); return auth; }
And here is a small sample of the login.html page.
<div class="form-container sign-in-container"> <form id="loginForm" name="regForm" th:action="@{/process-login}" method="POST"> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> <h1>Sign In</h1> <!-- Login Error --> <div th:if="${param.error}" class="alert alert-danger col-xs-10">Wrong email and/or password</div> <!-- Logout notify --> <div th:if="${param.logout}" class="alert alert-success 1 col-xs-10">You have been logged out.</div>
All the .html pages are located in
-resources -templates
Lastly, the only error I see in the logs is the following
DEBUG o.s.w.s.r.ResourceHttpRequestHandler - Resource not found
Advertisement
Answer
For anyone interested, I managed to solve the above issue. It seems like it was not a misconfiguration in the loginProcessingUrl()
class. Instead, the issue was the way a remote server handles the JSESSIONID
and csrf
.
More specifically, what I had to do is
- Added the following block of code in my SecurityConfig.java
cookieServerCsrfTokenRepository.setCookieHttpOnly(false); http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
- Next, added the block of code below
@Bean public ServletContextInitializer servletContextInitializer(@Value("${secure.cookie}") boolean secure) { return new ServletContextInitializer() { @Override public void onStartup(ServletContext servletContext) throws ServletException { servletContext.getSessionCookieConfig().setSecure(secure); } }; }
The secure.cookie
value needs to be set (in the application.properties
to true if you intend to utilise the HTTPs protocol.