Spring Security: Java Config does not work - java

I am trying to set up a java configurated spring environment including spring security. The application starts without any error, but I am not able to login succeffully.
WebAppInitializer
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
#Order(value = 1)
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { HibernateConfig.class, SecurityConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebAppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
SecurityInitializer
import org.springframework.core.annotation.Order;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
#Order(value = 2)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
SecurityConfig
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/webjars/**","/css/**","/img/**");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(getUserQuery())
.authoritiesByUsernameQuery(getAuthoritiesQuery());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasAnyAuthority("EMPLOYEE", "TEAM_LEADER", "ADMIN")
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/success-login", true)
.loginProcessingUrl("/process-login")
.failureUrl("/error-login")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login")
.permitAll()
.and()
.rememberMe()
.and()
.csrf()
.disable();
}
private String getUserQuery() {
return "SELECT e_mail as username, password as password, active as enabled "
+ "FROM employee "
+ "WHERE e_mail = ?";
}
private String getAuthoritiesQuery() {
return "SELECT DISTINCT employee.e_mail as username, role.name as authority "
+ "FROM employee, employee_role, role "
+ "WHERE employee.id = employee_role.employee_id "
+ "AND role.id = employee_role.role_id "
+ "AND employee.e_mail = ? "
+ "AND employee.active = 1";
}
}
login.jsp
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<div class="login-container">
<form class="form-signin" method="POST" action="<c:url value='/process-login'/>">
<h2 class="form-signin-heading">Anmelden</h2>
<c:if test="${error == true}">
<div class="alert alert-danger">
<a class="close" data-dismiss="alert" href="#">×</a>
<p>Login fehlgeschlagen: Eingegebener Nutzername oder Passwort ist falsch.</p>
</div>
</c:if>
<input type="text" name="j_username" id="j_username"
class="form-control" placeholder="eMail Adresse" required autofocus>
<input type="password" name="j_password" id="j_password"
class="form-control" placeholder="Passwort" required> <label
class="checkbox"> <input type="checkbox" value="remember-me">
Angemeldet bleiben
</label>
<button class="btn btn-lg btn-primary btn-block" type="submit">Anmelden</button>
</form>
</div>
LoginController
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class LoginController {
#RequestMapping(value={"/login"}, method=RequestMethod.GET)
public ModelAndView showLoginPage() {
return new ModelAndView("login/login");
}
#RequestMapping(value="/success-login", method=RequestMethod.POST)
public ModelAndView successLogin() {
return new ModelAndView("/dashboard");
}
#RequestMapping(value="/process-login", method=RequestMethod.POST)
public ModelAndView processLogin() {
return new ModelAndView("/dashboard");
}
#RequestMapping(value="/error-login", method=RequestMethod.GET)
public ModelAndView invalidLogin() {
ModelAndView modelAndView = new ModelAndView("login/login");
modelAndView.addObject("error", true);
return modelAndView;
}
#RequestMapping(value="/logout", method=RequestMethod.POST)
public ModelAndView logout() {
return new ModelAndView("login/login");
}
}
Database:
Content of Role Table: "EMPLOYEE", "TEAM_LEADER", "ADMIN",
I am looking for a solution a long time, but unfortunately I can not find the error. I appreciate all your advices.
Update 1 - Log4J Log after one login
2013-11-19 11:17:47,223 [DEBUG] [AbstractSecurityInterceptor.java : 310] org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#9056f12c: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#380f4: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 45D43FE758F35164E5FE7BC9D08F81B8; Granted Authorities: ROLE_ANONYMOUS
2013-11-19 11:17:47,231 [DEBUG] [AffirmativeBased.java : 65] org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#2f7b1445, returned: -1
2013-11-19 11:17:47,237 [DEBUG] [ExceptionTranslationFilter.java : 165] org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Zugriff verweigert
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:139)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
2013-11-19 11:17:47,239 [DEBUG] [AndRequestMatcher.java : 66] org.springframework.security.web.util.matcher.AndRequestMatcher - Trying to match using Ant [pattern='/**', GET]
2013-11-19 11:17:47,239 [DEBUG] [AntPathRequestMatcher.java : 127] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'POST /j_spring_security_check' doesn't match 'GET /**
2013-11-19 11:17:47,240 [DEBUG] [AndRequestMatcher.java : 69] org.springframework.security.web.util.matcher.AndRequestMatcher - Did not match
2013-11-19 11:17:47,240 [DEBUG] [HttpSessionRequestCache.java : 44] org.springframework.security.web.savedrequest.HttpSessionRequestCache - Request not saved as configured RequestMatcher did not match
2013-11-19 11:17:47,240 [DEBUG] [ExceptionTranslationFilter.java : 185] org.springframework.security.web.access.ExceptionTranslationFilter - Calling Authentication entry point.
2013-11-19 11:17:47,241 [DEBUG] [DefaultRedirectStrategy.java : 36] org.springframework.security.web.DefaultRedirectStrategy - Redirecting to 'http://localhost:8080/holidayplanner/login'
2013-11-19 11:17:47,241 [DEBUG] [HttpSessionSecurityContextRepository.java : 300] org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2013-11-19 11:17:47,242 [DEBUG] [SecurityContextPersistenceFilter.java : 97] org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
2013-11-19 11:17:47,246 [DEBUG] [AntPathRequestMatcher.java : 145] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/webjars/**'
2013-11-19 11:17:47,246 [DEBUG] [AntPathRequestMatcher.java : 145] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/css/**'
2013-11-19 11:17:47,246 [DEBUG] [AntPathRequestMatcher.java : 145] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/img/**'
2013-11-19 11:17:47,247 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2013-11-19 11:17:47,247 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2013-11-19 11:17:47,247 [DEBUG] [HttpSessionSecurityContextRepository.java : 148] org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
2013-11-19 11:17:47,247 [DEBUG] [HttpSessionSecurityContextRepository.java : 90] org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#2664e105. A new one will be created.
2013-11-19 11:17:47,247 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2013-11-19 11:17:47,247 [DEBUG] [HstsHeaderWriter.java : 129] org.springframework.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#2f389f24
2013-11-19 11:17:47,247 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 4 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2013-11-19 11:17:47,247 [DEBUG] [AntPathRequestMatcher.java : 145] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/logout'
2013-11-19 11:17:47,248 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 5 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2013-11-19 11:17:47,248 [DEBUG] [AntPathRequestMatcher.java : 127] org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /login' doesn't match 'POST /success-login
2013-11-19 11:17:47,248 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 6 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2013-11-19 11:17:47,248 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 7 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2013-11-19 11:17:47,248 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 8 of 12 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
2013-11-19 11:17:47,248 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2013-11-19 11:17:47,248 [DEBUG] [AnonymousAuthenticationFilter.java : 102] org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#9056f12c: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#380f4: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 45D43FE758F35164E5FE7BC9D08F81B8; Granted Authorities: ROLE_ANONYMOUS'
2013-11-19 11:17:47,249 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2013-11-19 11:17:47,249 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2013-11-19 11:17:47,249 [DEBUG] [FilterChainProxy.java : 337] org.springframework.security.web.FilterChainProxy - /login at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2013-11-19 11:17:47,249 [DEBUG] [AbstractSecurityInterceptor.java : 194] org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /login; Attributes: [permitAll]
2013-11-19 11:17:47,249 [DEBUG] [AbstractSecurityInterceptor.java : 310] org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#9056f12c: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#380f4: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 45D43FE758F35164E5FE7BC9D08F81B8; Granted Authorities: ROLE_ANONYMOUS
2013-11-19 11:17:47,249 [DEBUG] [AffirmativeBased.java : 65] org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#2f7b1445, returned: 1
2013-11-19 11:17:47,249 [DEBUG] [AbstractSecurityInterceptor.java : 215] org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Authorization successful
2013-11-19 11:17:47,250 [DEBUG] [AbstractSecurityInterceptor.java : 227] org.springframework.security.web.access.intercept.FilterSecurityInterceptor - RunAsManager did not change Authentication object
2013-11-19 11:17:47,250 [DEBUG] [FilterChainProxy.java : 323] org.springframework.security.web.FilterChainProxy - /login reached end of additional filter chain; proceeding with original chain
2013-11-19 11:17:47,254 [DEBUG] [ExceptionTranslationFilter.java : 115] org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
2013-11-19 11:17:47,254 [DEBUG] [HttpSessionSecurityContextRepository.java : 300] org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2013-11-19 11:17:47,254 [DEBUG] [SecurityContextPersistenceFilter.java : 97] org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

Working Solution:
Finally I found a working solution with your help. Thanks for this. Following all needed Files if someone other is interested in a java configured spring security:
Login JSP:
<div class="login-container">
<form class="form-signin navbar navbar-default" method="POST" action="<c:url value='/login/process-login'/>">
<div class="form-signin-img">
<span class="form-signin-img-helper"></span>
<img src="<c:url value='/img/itensis_logo.gif'/>" />
</div>
<h2 class="form-signin-heading">${msg_heading}</h2>
<c:if test="${error == true}">
<div class="alert alert-danger">
<button type="button" class="close close-box">×</button>
<p>${msg_error}</p>
</div>
</c:if>
<input type="text" name="security_username" id="security_username" class="form-control" placeholder="${msg_username}" required autofocus>
<input type="password" name="security_password" id="security_password" class="form-control" placeholder="${msg_password}" required>
<label class="checkbox">
<input type="checkbox" name="remember_me_checkbox"> ${msg_rememberMe}
</label>
<button class="btn btn-lg btn-primary btn-block" type="submit">
<i class="fa fa-sign-in fa-lg"></i>
<span>${msg_login}</span>
</button>
</form>
SecurityConfig.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired private UserDetailsService userDetailService;
#Autowired private DataSource dataSource;
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/js/**","/css/**","/img/**","/webjars/**","/pages/**");
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
ShaPasswordEncoder shaPasswordEncoder = new ShaPasswordEncoder(256);
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(getUserQuery())
.authoritiesByUsernameQuery(getAuthoritiesQuery())
.passwordEncoder(shaPasswordEncoder);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasAuthority("BASIC_PERMISSION")
.and()
.formLogin()
.loginPage("/login/login")
.defaultSuccessUrl("/login/success-login", true)
.failureUrl("/login/error-login")
.loginProcessingUrl("/login/process-login")
.usernameParameter("security_username")
.passwordParameter("security_password")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login/login")
.logoutUrl("/login/logout")
.permitAll()
.and()
.rememberMe()
.key("your_key")
.rememberMeServices(rememberMeServices())
.and()
.csrf()
.disable();
}
#Bean
public RememberMeServices rememberMeServices() {
// Key must be equal to rememberMe().key()
TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("your_key", userDetailService);
rememberMeServices.setCookieName("remember_me_cookie");
rememberMeServices.setParameter("remember_me_checkbox");
rememberMeServices.setTokenValiditySeconds(2678400); // 1month
return rememberMeServices;
}
#Bean
public UserDetailsService userDetailService() {
return new SecurityUserDetailService();
}
private String getUserQuery() {
return "SELECT username as username, password as password, active as enabled "
+ "FROM employee "
+ "WHERE username = ?";
}
private String getAuthoritiesQuery() {
return "SELECT DISTINCT employee.username as username, permission.name as authority "
+ "FROM employee, employee_role, role, role_permission, permission "
+ "WHERE employee.id = employee_role.employee_id "
+ "AND role.id = employee_role.role_id "
+ "AND role.id = role_permission.role_id "
+ "AND permission.id = role_permission.permission_id "
+ "AND employee.username = ? "
+ "AND employee.active = 1";
}
}
LoginController.java
#Controller
#RequestMapping("/login")
public class LoginController {
#RequestMapping(value={"/login"}, method=RequestMethod.GET)
public ModelAndView showLoginPage() {
return new ModelAndView("loginForm");
}
#RequestMapping(value="/success-login", method=RequestMethod.GET)
public String successLogin() {
return "forward:/dashboard/dashboard";
}
#RequestMapping(value="/error-login", method=RequestMethod.GET)
public ModelAndView invalidLogin() {
ModelAndView modelAndView = new ModelAndView("loginForm");
modelAndView.addObject("error", true);
return modelAndView;
}
#RequestMapping(value="/logout", method=RequestMethod.POST)
public ModelAndView logout() {
return new ModelAndView("dashboardForm");
}
}
Update 1: SecurityUserDetailService
#Service
#Transactional
public class SecurityUserDetailService implements UserDetailsService {
#Autowired private EmployeeService employeeService;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
Employee loggedInEmployee = employeeService.findEmployeeByUsername(username);
List<GrantedAuthority> authorities = getAuthorities(loggedInEmployee);
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new User(
loggedInEmployee.getUsername(),
loggedInEmployee.getPassword().toLowerCase(),
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
authorities);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static List<GrantedAuthority> getAuthorities(Employee employee) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (Role role : employee.getRoles()) {
for (Permission permission : role.getPermissions()) {
authorities.add(new SimpleGrantedAuthority(permission.getName()));
}
}
return authorities;
}
}

Related

Cannot open Swagger UI in its Version 3 in my Spring Boot Example

I have a problem about opening swagger ui in my Spring Boot Example.
I get this kind of error when I access to localhost:8080/swagger-ui or localhost:8080/root-api-name:swagger-ui
Securing GET /springboot-blog-rest-api/swagger-ui
2022-07-22 01:38:58.820 DEBUG 30576 --- [nio-8080-exec-4] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2022-07-22 01:38:58.820 DEBUG 30576 --- [nio-8080-exec-4] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2022-07-22 01:38:58.820 DEBUG 30576 --- [nio-8080-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor : Failed to authorize filter invocation [GET /springboot-blog-rest-api/swagger-ui] with attributes [authenticated]
2022-07-22 01:38:58.820 DEBUG 30576 --- [nio-8080-exec-4] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2022-07-22 01:38:58.820 DEBUG 30576 --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy : Securing GET /error
2022-07-22 01:38:58.821 DEBUG 30576 --- [nio-8080-exec-4] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2022-07-22 01:38:58.821 DEBUG 30576 --- [nio-8080-exec-4] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2022-07-22 01:38:58.821 DEBUG 30576 --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy : Secured GET /error
2022-07-22 01:38:58.821 DEBUG 30576 --- [nio-8080-exec-4] a.DefaultWebInvocationPrivilegeEvaluator : filter invocation [/error] denied for AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
org.springframework.security.access.AccessDeniedException: Access is denied
I used springfox-swagger2 version 3 , springfox-boot-starter version 3 and lastly springfox-swagger-ui version 2.9.
How can I fix my issue?
Here is my SwaggerConfig File.
#Configuration
#EnableSwagger2
public class SwaggerConfig {
public static final String AUTHORIZATION_HEADER = "Authorization";
private ApiKey apiKey(){
return new ApiKey("JWT", AUTHORIZATION_HEADER, "header");
}
private ApiInfo apiInfo(){
return new ApiInfo(
"Spring Boot Blog REST APIs",
"Spring Boot Blog REST API Documentation",
"1",
"Terms of service",
new Contact("Name", "website-address", "Email"),
"License of API",
"API license URL",
Collections.emptyList()
);
}
#Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.securityContexts(Arrays.asList(securityContext()))
.securitySchemes(Arrays.asList(apiKey()))
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
private SecurityContext securityContext(){
return SecurityContext.builder().securityReferences(defaultAuth()).build();
}
private List<SecurityReference> defaultAuth(){
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return Arrays.asList(new SecurityReference("JWT", authorizationScopes));
}
}
Here is my SecurityConfig file
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
#Autowired
private JwtAuthenticationEntryPoint authenticationEntryPoint;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter(){
return new JwtAuthenticationFilter();
}
#Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers("/v2/api-docs/**",
"/swagger-ui/**","/swagger-resources/**","/swagger-ui.html","/webjars/**");
}
#Bean
protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests((authorize) -> authorize
.antMatchers(HttpMethod.GET, "/api/v1/**").permitAll()
.antMatchers("/api/v1/auth/**").permitAll()
.anyRequest()
.authenticated()
);
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
#Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
Here is the answer
I can access the url through localhost:8080/swagger-ui.html
If you are using Spring Security, use the following security configuration to allow public access to Swagger UI resources:
public class SecurityConfig {
private static final String[] AUTH_WHITELIST = {
// for Swagger UI v2
"/v2/api-docs",
"/swagger-ui.html",
"/swagger-resources",
"/swagger-resources/**",
"/configuration/ui",
"/configuration/security",
"/webjars/**",
// for Swagger UI v3 (OpenAPI)
"/v3/api-docs/**",
"/swagger-ui/**"
};
#Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) {
httpSecurity
// ... other configuration settings
.antMatchers(AUTH_WHITELIST).permitAll();
// ...
}
}

Spring Secutirty hasRole Always Return 403

I'm trying to restrict access to an endpoint based on roles. I searched here on stackoverflow for a solution and tried a few but was not successful in solving my problem. I tried to make the restriction both in the global configuration (WebSecurityConfig) and also with PreAuthorize Annotation, both returned 403 when called. My test user has the SYS_ADMIN role, I have already validated this flow and it actually has the role. Below are my sources.
Global WebSecurityConfig
#Configuration
#EnableWebSecurity
#EnableAutoConfiguration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private UserDetailsService jwtUserDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
#Override
#Bean
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.headers().frameOptions().disable();
httpSecurity.cors().and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/spring-security-rest/**").permitAll().and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/authentication/**").permitAll()
.antMatchers(HttpMethod.POST, "/api/persons/**").hasRole("SYS_ADMIN")
.antMatchers(HttpMethod.GET, "/api/roles/**").permitAll()
.anyRequest().authenticated().and()
.headers().frameOptions().sameOrigin().and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().mvcMatchers(HttpMethod.OPTIONS, "/**");
web.ignoring().mvcMatchers("/swagger-ui.html/**", "/configuration/**", "/swagger-resources/**", "/v2/api-docs",
"/webjars/**");
}
#Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Person Controller
package br.com.aquamain.backend.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import br.com.aquamain.backend.exception.InvalidPersonException;
import br.com.aquamain.backend.model.CustomPage;
import br.com.aquamain.backend.model.Person;
import br.com.aquamain.backend.service.PersonService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
#RestController
#RequestMapping("/api/persons")
#Api(tags = "Persons")
public class PersonController {
#Autowired
private PersonService personService;
...
#PostMapping(path = "new", consumes = "application/json")
#ApiOperation(value = "Create a new person.")
public ResponseEntity<?> save(#RequestBody Person person) {
try {
CustomPage<Person> persons = this.personService.save(person);
return new ResponseEntity<CustomPage<Person>>(persons, HttpStatus.CREATED);
} catch (InvalidPersonException error) {
return new ResponseEntity<String>(error.getMessage(), HttpStatus.BAD_REQUEST);
}
}
...
}
Role Model
package br.com.aquamain.backend.model;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
#Entity
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
#Table(name = "AQUARIUM_MAINTANCE_MONITOR_ROLE")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_ROLE", nullable = false, precision = 9, scale = 0)
private Integer id;
#JsonIgnoreProperties(value = {"roles"})
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "roles")
#JsonInclude(Include.NON_NULL)
private List<User> users;
#Column(name = "CODE_ROLE", nullable = true, length = 255)
private String code;
#Column(name = "DESCRIPTION_ROLE", nullable = true, length = 255)
private String description;
#Column(name = "NAME_ROLE", nullable = true, length = 255)
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Update:
JwtRequestFilter
package br.com.aquamain.backend.security;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import br.com.aquamain.backend.security.service.JwtUserDetailsService;
import br.com.aquamain.backend.security.utils.JwtTokenUtils;
import io.jsonwebtoken.ExpiredJwtException;
#Component
public class JwtRequestFilter extends OncePerRequestFilter {
#Autowired
private JwtUserDetailsService jwtUserDetailsService;
#Autowired
private JwtTokenUtils jwtTokenUtil;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
System.out.println("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
System.out.println("JWT Token has expired");
}
} else {
logger.warn("JWT Token does not begin with Bearer String");
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
Log:
[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/**', OPTIONS], Filters=[]] (1/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/swagger-ui.html/**'], Filters=[]] (2/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/configuration/**'], Filters=[]] (3/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/swagger-resources/**'], Filters=[]] (4/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/v2/api-docs'], Filters=[]] (5/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/webjars/**'], Filters=[]] (6/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#6d29e44e, org.springframework.security.web.context.SecurityContextPersistenceFilter#431fc40, org.springframework.security.web.header.HeaderWriterFilter#72dd71b5, org.springframework.web.filter.CorsFilter#258798b6, org.springframework.security.web.authentication.logout.LogoutFilter#48124669, br.com.aquamain.backend.security.JwtRequestFilter#4efcbbde, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#293ce7b0, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#7879d247, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#5e7f5483, org.springframework.security.web.session.SessionManagementFilter#4ce3c16a, org.springframework.security.web.access.ExceptionTranslationFilter#58ad93f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#6f778913]] (7/7)
[0;39m[32m2022-04-12 11:14:54 DEBUG o.s.security.web.FilterChainProxy - Securing POST /api/persons/new
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking WebAsyncManagerIntegrationFilter (1/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking SecurityContextPersistenceFilter (2/12)
[0;39m[32m2022-04-12 11:14:54 DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking HeaderWriterFilter (3/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking CorsFilter (4/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking LogoutFilter (5/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.logout.LogoutFilter - Did not match request to Or [Ant [pattern='/logout', GET], Ant [pattern='/logout', POST], Ant [pattern='/logout', PUT], Ant [pattern='/logout', DELETE]]
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking JwtRequestFilter (6/12)
[0;39mHibernate:
/* select
generatedAlias0
from
User as generatedAlias0
where
generatedAlias0.username=:param0 */ select
user0_.ID_USER as id_user1_3_,
user0_.LAST_LOGIN_DATE as last_log2_3_,
user0_.PASSWORD_USER as password3_3_,
user0_.RESET_PASSWORD_TOKEN as reset_pa4_3_,
user0_.USERNAME_USER as username5_3_
from
AQUARIUM_MAINTANCE_MONITOR_USER user0_
where
user0_.USERNAME_USER=?
Hibernate:
/* load br.com.aquamain.backend.model.Person */ select
person0_.ID_PERSON as id_perso1_0_1_,
person0_.BIRTHDAY_PERSON as birthday2_0_1_,
person0_.NAME_PERSON as name_per3_0_1_,
person0_.ID_USER as id_user4_0_1_,
user1_.ID_USER as id_user1_3_0_,
user1_.LAST_LOGIN_DATE as last_log2_3_0_,
user1_.PASSWORD_USER as password3_3_0_,
user1_.RESET_PASSWORD_TOKEN as reset_pa4_3_0_,
user1_.USERNAME_USER as username5_3_0_
from
AQUARIUM_MAINTANCE_MONITOR_PERSON person0_
left outer join
AQUARIUM_MAINTANCE_MONITOR_USER user1_
on person0_.ID_USER=user1_.ID_USER
where
person0_.ID_USER=?
[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking RequestCacheAwareFilter (7/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking SecurityContextHolderAwareRequestFilter (8/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking AnonymousAuthenticationFilter (9/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.AnonymousAuthenticationFilter - Did not set SecurityContextHolder since already authenticated UsernamePasswordAuthenticationToken [Principal=Id:1
Username:tony.stark
Last Login:2022-04-12T11:14:30.058-03:00
, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[]]
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking SessionManagementFilter (10/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.s.CompositeSessionAuthenticationStrategy - Preparing session with ChangeSessionIdAuthenticationStrategy (1/1)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking ExceptionTranslationFilter (11/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking FilterSecurityInterceptor (12/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource - Did not match request to Ant [pattern='/spring-security-rest/**'] - [permitAll] (1/5)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource - Did not match request to Ant [pattern='/api/authentication/**', POST] - [permitAll] (2/5)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.i.FilterSecurityInterceptor - Did not re-authenticate UsernamePasswordAuthenticationToken [Principal=Id:1
Username:tony.stark
Last Login:2022-04-12T11:14:30.058-03:00
, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[]] before authorizing
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.i.FilterSecurityInterceptor - Authorizing filter invocation [POST /api/persons/new] with attributes [hasRole('ROLE_SYS_ADMIN')]
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.e.WebExpressionVoter - Voted to deny authorization
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.i.FilterSecurityInterceptor - Failed to authorize filter invocation [POST /api/persons/new] with attributes [hasRole('ROLE_SYS_ADMIN')] using AffirmativeBased [DecisionVoters=[org.springframework.security.web.access.expression.WebExpressionVoter#4f47d6c4], AllowIfAllAbstainDecisions=false]
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.ExceptionTranslationFilter - Sending UsernamePasswordAuthenticationToken [Principal=Id:1
Username:tony.stark
Last Login:2022-04-12T11:14:30.058-03:00
, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[]] to access denied handler since access is denied
[0;39morg.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:73)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.attemptAuthorization(AbstractSecurityInterceptor.java:238)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:208)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:113)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:121)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at br.com.aquamain.backend.security.JwtRequestFilter.doFilterInternal(JwtRequestFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1723)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:833)
[32m2022-04-12 11:14:54 DEBUG o.s.s.w.a.AccessDeniedHandlerImpl - Responding with 403 status code
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match request to [Is Secure]
[0;39m[32m2022-04-12 11:14:54 DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - Cleared SecurityContextHolder to complete request
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/**', OPTIONS], Filters=[]] (1/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/swagger-ui.html/**'], Filters=[]] (2/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/configuration/**'], Filters=[]] (3/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/swagger-resources/**'], Filters=[]] (4/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/v2/api-docs'], Filters=[]] (5/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/webjars/**'], Filters=[]] (6/7)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#6d29e44e, org.springframework.security.web.context.SecurityContextPersistenceFilter#431fc40, org.springframework.security.web.header.HeaderWriterFilter#72dd71b5, org.springframework.web.filter.CorsFilter#258798b6, org.springframework.security.web.authentication.logout.LogoutFilter#48124669, br.com.aquamain.backend.security.JwtRequestFilter#4efcbbde, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#293ce7b0, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#7879d247, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#5e7f5483, org.springframework.security.web.session.SessionManagementFilter#4ce3c16a, org.springframework.security.web.access.ExceptionTranslationFilter#58ad93f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#6f778913]] (7/7)
[0;39m[32m2022-04-12 11:14:54 DEBUG o.s.security.web.FilterChainProxy - Securing POST /error
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking WebAsyncManagerIntegrationFilter (1/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking SecurityContextPersistenceFilter (2/12)
[0;39m[32m2022-04-12 11:14:54 DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking HeaderWriterFilter (3/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking CorsFilter (4/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking LogoutFilter (5/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.logout.LogoutFilter - Did not match request to Or [Ant [pattern='/logout', GET], Ant [pattern='/logout', POST], Ant [pattern='/logout', PUT], Ant [pattern='/logout', DELETE]]
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking JwtRequestFilter (6/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking RequestCacheAwareFilter (7/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking SecurityContextHolderAwareRequestFilter (8/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking AnonymousAuthenticationFilter (9/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking SessionManagementFilter (10/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking ExceptionTranslationFilter (11/12)
[0;39m[32m2022-04-12 11:14:54 TRACE o.s.security.web.FilterChainProxy - Invoking FilterSecurityInterceptor (12/12)
[0;39m[32m2022-04-12 11:14:54 DEBUG o.s.security.web.FilterChainProxy - Secured POST /error
[0;39m[32m2022-04-12 11:14:54 DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - Cleared SecurityContextHolder to complete request

Spring Boot permitAll not working in WebSecurityConfigurerAdapter

When I POST to /api/v1/auth/register, I get a 403 response generated by the configured accessDeniedHandler. However, I'm expecting this request to be permitted as it's covered by permitAll() and precedes anyRequest().authenticated().
Requests such as GET /api/v1/reference/countries work just fine. Also, my integration tests that hit these /api/v1/auth/** endpoints also work, which suggests something to do with CORS, although the preflight request is 200.
Any idea what's wrong with this security configuration?
#Configuration
#EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true
)
#Order(1)
#RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsServiceImpl userDetailsService;
private final Config config;
private final ObjectMapper objectMapper;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.authorizeRequests()
.antMatchers(
"/api/v1/auth/register",
"/api/v1/auth/register/check",
"/api/v1/auth/register/activate",
"/api/v1/auth/password/update",
"/api/v1/auth/recover",
"/api/v1/auth/recover/check",
"/api/v1/auth/recover/reset",
"/api/v1/csrf-token",
"/api/v1/reference/**"
)
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.successHandler((request, response, authentication) -> {
response.getWriter().append("OK");
response.setStatus(HttpServletResponse.SC_OK);
})
.failureHandler((request, response, exception) -> {
response.getWriter().append("Invalid credentials or inactive account");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
})
.loginProcessingUrl("/api/v1/auth/login")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/api/v1/auth/logout", "POST"))
.permitAll()
.and()
.exceptionHandling()
.accessDeniedHandler((request, response, accessDeniedException) -> {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
objectMapper.writeValue(
response.getWriter(),
ErrorResponseBody
.builder()
.code(ErrorType.ACCESS_DENIED)
.status(HttpServletResponse.SC_FORBIDDEN)
.message("Access denied")
.build()
);
})
.authenticationEntryPoint((request, response, authException) -> {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
objectMapper.writeValue(
response.getWriter(),
ErrorResponseBody
.builder()
.code(ErrorType.LOGIN_REQUIRED)
.status(HttpServletResponse.SC_UNAUTHORIZED)
.message("You are not authorized to access this resource")
.build()
);
})
.and()
.userDetailsService(userDetailsService);
if (config.isCsrfDisabled()) {
http
.csrf()
.disable();
}
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final var configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedOrigins(config.getAllowedOrigins());
configuration.setAllowedMethods(asList("GET", "POST", "PUT", "PATCH", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList(HttpHeaders.AUTHORIZATION, HttpHeaders.CACHE_CONTROL, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT));
final var source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
return source;
}
}
Here's my CORS config:
#Configuration
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class WebConfig {
private final Config config;
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
final var allowedOrigins = Optional
.ofNullable(config.getAllowedOrigins())
.map(origins -> origins.toArray(new String[]{}))
.orElse(new String[]{});
System.out.println("Enabling CORS for the following origins:" + Arrays.asList(allowedOrigins).toString());
registry
.addMapping("/api/**")
.allowedOrigins(allowedOrigins)
.allowCredentials(true)
.allowedMethods("*")
.allowedHeaders("*");
}
};
}
}
I'm invoking these endpoints from http://localhost:3000, which is one of the items returned by config.getAllowedOrigins().
Here's the Spring Security debug logging from the request:
2020-11-24 06:51:16.110 INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-11-24 06:51:16.112 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-11-24 06:51:16.158 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 44 ms
2020-11-24 06:51:16.193 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-11-24 06:51:16.200 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-11-24 06:51:16.205 DEBUG 1 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-11-24 06:51:16.206 DEBUG 1 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-11-24 06:51:16.214 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-11-24 06:51:16.217 DEBUG 1 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 4 of 13 in additional filter chain; firing Filter: 'CorsFilter'
2020-11-24 06:51:16.286 DEBUG 1 --- [nio-8080-exec-1] 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#461bbc94
2020-11-24 06:51:16.290 DEBUG 1 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-11-24 06:51:16.299 DEBUG 1 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2020-11-24 06:51:16.483 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-11-24 06:51:16.485 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-11-24 06:51:16.486 DEBUG 1 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-11-24 06:51:16.487 DEBUG 1 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-11-24 06:51:16.488 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-11-24 06:51:16.489 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 4 of 13 in additional filter chain; firing Filter: 'CorsFilter'
2020-11-24 06:51:16.494 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/v1/auth/register at position 5 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2020-11-24 06:51:16.525 DEBUG 1 --- [nio-8080-exec-2] o.s.security.web.csrf.CsrfFilter : Invalid CSRF token found for http://dev.api.example.com/api/v1/auth/register
2020-11-24 06:51:16.609 DEBUG 1 --- [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#461bbc94
2020-11-24 06:51:16.610 DEBUG 1 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-11-24 06:51:16.615 DEBUG 1 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
Disable CSRF using .csrf().disable() in configure(HttpSecurity http) More deatils are explained here
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
... // other configurations
}

Spring security returns HTTP 403 after successful authentication [duplicate]

This question already has answers here:
Springboot Security hasRole not working
(3 answers)
Closed 5 years ago.
I'm using spring 4.3.10.RELEASE and spring-security 4.2.3.RELEASE
When I try open /admin after successful authentication i get 403, but i have all required authorities, look at tomcat log.
My security configuration:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private DataSource dataSource;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated().and()
.formLogin().loginPage("/login").failureUrl("/login?error").permitAll().and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/login?logout")
.invalidateHttpSession(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET")).and()
.csrf().and()
.exceptionHandling().accessDeniedPage("/403");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery("SELECT username, password, enabled FROM app_user WHERE username = ?")
.authoritiesByUsernameQuery("SELECT username, role FROM app_user_role WHERE username = ?");
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
My Tomcat's log:
2017-07-28 14:18:15 DEBUG AntPathRequestMatcher:157 - Checking match of request : '/admin'; against '/resources/**'
2017-07-28 14:18:15 DEBUG AntPathRequestMatcher:157 - Checking match of request : '/admin'; against '/admin/**'
2017-07-28 14:18:15 DEBUG FilterSecurityInterceptor:219 - Secure object: FilterInvocation: URL: /admin; Attributes: [hasRole('ROLE_ADMIN')]
2017-07-28 14:18:15 DEBUG FilterSecurityInterceptor:348 - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#f9ea146f: Principal: org.springframework.security.core.userdetails.User#586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN,USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 9F780DC552AED23804184D55F3F9BF0D; Granted Authorities: ADMIN, USER
2017-07-28 14:18:15 DEBUG AffirmativeBased:66 - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#6e6a7061, returned: -1
2017-07-28 14:18:15 DEBUG ExceptionTranslationFilter:185 - 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)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
Solved! The key is prefix "ROLE_"
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.rolePrefix("ROLE_")
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery("SELECT username, password, enabled FROM app_user WHERE username = ?")
.authoritiesByUsernameQuery("SELECT username, role FROM app_user_role WHERE username = ?");
}

Spring MVC - HTTP Status 405 - Request method 'POST' not supported

I've read all the questions related with this problem but no solution worked for me...
I have a simple upload form.
The controller, i't a controller i've used a lot of times (never for a file upload though).
#Controller
public class FileUploadController {
#Autowired
private HttpServletRequest request;
#RequestMapping(value={"/upload"}, method= RequestMethod.GET)
public String getUploadForm() {
return "/upload";
}
#RequestMapping(value={"/upload"}, method=RequestMethod.POST)
public #ResponseBody String uploadedFile(#RequestParam("uploadedFile") UploadedFile uploadedFile, BindingResult result, ModelMap model,
RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return "/upload";
}
InputStream is = null;
OutputStream os = null;
MultipartFile file = uploadedFile.getFile();
String fileName = file.getOriginalFilename();
String imagepath = request.getSession().getServletContext().getRealPath("/resources/images");
try {
is = file.getInputStream();
File newFile = new File(imagepath+"/"+fileName);
if(!newFile.exists()){
newFile.createNewFile();
}
os = new FileOutputStream(newFile);
int read=0;
byte[] bytes = new byte[1024];
while((read = is.read(bytes)) != -1){
os.write(bytes, 0, read);
}
redirectAttributes.addFlashAttribute("css", "success");
redirectAttributes.addFlashAttribute("msg", "File "+fileName+ "aggiunto correttamente");
model.addAttribute("fileName", fileName);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "redirect:/floors";
}
}
Then I have the upload form, cleaned form all the css part:
<form:form method="POST" enctype="multipart/form-data" modelAttribute="uploadedFile">
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}" />
<form:errors path="*" cssClass="alert alert-danger alert-dismissible"
element="div" />
<label class="control-label col-sm-2">Carica
immagine</label>
<input type="file" name="file">
<form:errors path="file" class="control-label" />
<button id="singlebutton" name="singlebutton"
class="btn btn-primary" type="submit">Carica</button>
</div>
</form:form>
I don't know if it's useful, but this is UploadedFile.java, really simple
import org.springframework.web.multipart.MultipartFile;
public class UploadedFile{
MultipartFile file;
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
}
The form in HTML has:
<form id="uploadedFile" class="form-horizontal" action="/smartpark/upload" method="POST" enctype="multipart/form-data">
Where is the problem? I cannot even understand at which point che POST request goes wrong...
I'm adding the debug: Spring debug says:
2015-12-22 18:52:13 DEBUG FilterChainProxy:324 - /upload at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-12-22 18:52:13 DEBUG FilterChainProxy:324 - /upload at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-12-22 18:52:13 DEBUG HttpSessionSecurityContextRepository:192 - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl#468e6d7e: Authentication: org.springframework.security.authentication.RememberMeAuthenticationToken#468e6d7e: Principal: org.springframework.security.core.userdetails.User#62dd304: Username: mario; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#7798: RemoteIpAddress: 192.168.3.38; SessionId: null; Granted Authorities: ROLE_ADMIN'
2015-12-22 18:52:13 DEBUG FilterChainProxy:324 - /upload at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2015-12-22 18:52:13 DEBUG HstsHeaderWriter:128 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#26ee04e5
2015-12-22 18:52:13 DEBUG FilterChainProxy:324 - /upload at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2015-12-22 18:52:13 DEBUG CsrfFilter:106 - Invalid CSRF token found for http://192.168.3.240:8080/smartpark/upload
2015-12-22 18:52:13 DEBUG DispatcherServlet:861 - DispatcherServlet with name 'dispatcher' processing POST request for [/smartpark/Access_Denied]
2015-12-22 18:52:13 DEBUG RequestMappingHandlerMapping:306 - Looking up handler method for path /Access_Denied
2015-12-22 18:52:13 DEBUG ExceptionHandlerExceptionResolver:133 - Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
2015-12-22 18:52:13 DEBUG ResponseStatusExceptionResolver:133 - Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
2015-12-22 18:52:13 DEBUG DefaultHandlerExceptionResolver:133 - Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
2015-12-22 18:52:13 WARN PageNotFound:208 - Request method 'POST' not supported
2015-12-22 18:52:13 DEBUG DispatcherServlet:1034 - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling
2015-12-22 18:52:13 DEBUG DispatcherServlet:1000 - Successfully completed request
2015-12-22 18:52:13 DEBUG HttpSessionSecurityContextRepository$SaveToSessionResponseWrapper:211 - Skip invoking on
2015-12-22 18:52:13 DEBUG SecurityContextPersistenceFilter:105 - SecurityContextHolder now cleared, as request processing completed
Browser network logs don't say anything, just that the POST resource is not accomplished
Thanks
Things to Consider:
Check your request header and see if it's submitting to floors/upload. if not try to add action="floors/upload" property in your form tag.
Try to change your controller to (without the path)
#RequestMapping(value="upload", method=RequestMethod.POST)
I found the problem.
Following this link I saw that multipart file upload with spring and CSRF must be handled with care.
So I first disabled the CSRF to see if everything went well. After it, I added
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
to my SecurityWebApplicationInitializer.java so to not need the authentication to upload file on the server, but only to move them to their final destination.
Than I had to configure the filterMultipartResolver and everything went good.
Thank you all
Look into spring's PathVariables.
#RequestMapping(value = " /upload/{pathName}", method=RequestMethod.POST)
public String getOrder(#PathVariable String pathName){
// do what you need
}
IntelliJ suggested I use <form:form, which uses gave
<html xmlns:form="http://www.w3.org/1999/xhtml">
at the top of my .html file. I changed to just <form in my body and then my POST request worked.

Categories