Spring Security Authorization Issue - java

I am trying to authorize my rest service method for user or admin. But it seems it's not authorizing it and by passing the secured and preAuthorize tags.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true, mode = org.springframework.context.annotation.AdviceMode.ASPECTJ, proxyTargetClass = true)
public class UserDetailsSecurityConfig extends WebSecurityConfigurerAdapter {
//Some Code Here
}
My application config file:
#EnableWebMvc
#Configuration
#ComponentScan({ "com.ws.service.*" })
#Import({ UserDetailsSecurityConfig.class })
#javax.ws.rs.ApplicationPath("webresources")
public class AppConfig extends Application {
//Some Code Here
}
My Rest service method:
#GET
#Secured("ROLE_ADMIN")
#PreAuthorize("hasRole('ROLE_ADMIN')")
#Path("getUser")
#Produces({"application/xml", "application/json"})
public User GetUser() {
User result;
try{
result = new User();
}catch(NoResultException ne){
result = null;
}
return result;
}
Now either I sign in as admin user with ROLE_ADMIN or simple user with ROLE_USER. Spring Security authorize this method.
I have changed my security logs to fine where it seems that preAuthorize annotation worked. But, in the end gets same result.
Finest: Looking for Pre/Post annotations for method 'GetUser' on target class 'class com.ws.service.UserFacadeREST'
Fine: #org.springframework.security.access.prepost.PreAuthorize(value=hasRole('ROLE_ADMIN')) found on specific method: public com.ws.UpUser com.ws.service.UserFacadeREST.GetUser()
Fine: Caching method [CacheKey[com.ws.service.UserFacadeREST; public com.ws.User com.ws.service.UserFacadeREST.GetUser()]] with attributes [[authorize: 'hasRole('ROLE_ADMIN')', filter: 'null', filterTarget: 'null']]
When I try to log-in it logs me in successfully. I logged in from "user" who has "ROLE_USER" in database.
Fine: /login at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
Fine: /login at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
Fine: HttpSession returned null object for SPRING_SECURITY_CONTEXT
Fine: No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#5094f334. A new one will be created.
Fine: /login at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
Fine: Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#50da4786
Fine: /login at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
Fine: /login at position 5 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
Fine: Checking match of request : '/login'; against '/logout'
Fine: /login at position 6 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
Fine: Checking match of request : '/login'; against '/login'
Fine: Request is to process authentication
Fine: Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
Fine: Delegating to org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy#72e0fc63
Fine: Delegating to org.springframework.security.web.csrf.CsrfAuthenticationStrategy#5c8272c1
Fine: Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#4428690f: Principal: org.springframework.security.core.userdetails.User#36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#380f4: RemoteIpAddress: 127.0.0.1; SessionId: a50e5eecf72b5493c618ffbb20f0; Granted Authorities: ROLE_USER
Fine: Redirecting to DefaultSavedRequest Url: http://localhost:8080/LmsWebService/webresources/upuser/getUser
Fine: Redirecting to 'http://localhost:8080/LmsWebService/webresources/upuser/getUser'
Fine: SecurityContext stored to HttpSession: 'org.springframework.security.core.context.SecurityContextImpl#4428690f: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#4428690f: Principal: org.springframework.security.core.userdetails.User#36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#380f4: RemoteIpAddress: 127.0.0.1; SessionId: a50e5eecf72b5493c618ffbb20f0; Granted Authorities: ROLE_USER'
Fine: SecurityContextHolder now cleared, as request processing completed
Fine: /webresources/upuser/getUser at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
Fine: /webresources/upuser/getUser at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
Fine: Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl#4428690f: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#4428690f: Principal: org.springframework.security.core.userdetails.User#36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#380f4: RemoteIpAddress: 127.0.0.1; SessionId: a50e5eecf72b5493c618ffbb20f0; Granted Authorities: ROLE_USER'
Fine: /webresources/upuser/getUser at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
Fine: Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#50da4786
Fine: /webresources/upuser/getUser at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
Fine: /webresources/upuser/getUser at position 5 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
Fine: Checking match of request : '/webresources/upuser/getuser'; against '/logout'
Fine: /webresources/upuser/getUser at position 6 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
Fine: Request 'GET /webresources/upuser/getuser' doesn't match 'POST /login
Fine: /webresources/upuser/getUser at position 7 of 14 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
Fine: /webresources/upuser/getUser at position 8 of 14 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
Fine: /webresources/upuser/getUser at position 9 of 14 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
Fine: pathInfo: arg1=/upuser/getUser; arg2=/upuser/getUser (property equals)
Fine: queryString: both null (property equals)
Fine: requestURI: arg1=/LmsWebService/webresources/upuser/getUser; arg2=/LmsWebService/webresources/upuser/getUser (property equals)
Fine: serverPort: arg1=8080; arg2=8080 (property equals)
Fine: requestURL: arg1=http://localhost:8080/LmsWebService/webresources/upuser/getUser; arg2=http://localhost:8080/LmsWebService/webresources/upuser/getUser (property equals)
Fine: scheme: arg1=http; arg2=http (property equals)
Fine: serverName: arg1=localhost; arg2=localhost (property equals)
Fine: contextPath: arg1=/LmsWebService; arg2=/LmsWebService (property equals)
Fine: servletPath: arg1=/webresources; arg2=/webresources (property equals)
Fine: Removing DefaultSavedRequest from session if present
Fine: /webresources/upuser/getUser at position 10 of 14 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
Fine: /webresources/upuser/getUser at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
Fine: SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken#4428690f: Principal: org.springframework.security.core.userdetails.User#36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#380f4: RemoteIpAddress: 127.0.0.1; SessionId: a50e5eecf72b5493c618ffbb20f0; Granted Authorities: ROLE_USER'
Fine: /webresources/upuser/getUser at position 12 of 14 in additional filter chain; firing Filter: 'SessionManagementFilter'
Fine: /webresources/upuser/getUser at position 13 of 14 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
Fine: /webresources/upuser/getUser at position 14 of 14 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
Fine: Secure object: FilterInvocation: URL: /webresources/upuser/getUser; Attributes: [authenticated]
Fine: Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#4428690f: Principal: org.springframework.security.core.userdetails.User#36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#380f4: RemoteIpAddress: 127.0.0.1; SessionId: a50e5eecf72b5493c618ffbb20f0; Granted Authorities: ROLE_USER
Fine: Voter: org.springframework.security.web.access.expression.WebExpressionVoter#3fb68f13, returned: 1
Fine: Authorization successful
Fine: RunAsManager did not change Authentication object
Fine: /webresources/upuser/getUser reached end of additional filter chain; proceeding with original chain
Info: MonitorFilter::WARNING: the monitor filter must be the first filter in the chain.
Fine: Chain processed normally
Fine: SecurityContextHolder now cleared, as request processing completed
Can anyone tell me what I am doing wrong in all this thing. Or Spring Security doesn't work with glassfish.
My Environment:
Java EE 1.6
Spring Security
GlassFish Server 4.1
MySql Databse
Maven
JPA
EDIT # 1
#Configuration
#EnableWebSecurity
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, mode = org.springframework.context.annotation.AdviceMode.ASPECTJ, proxyTargetClass = true)
public class UserDetailsSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService( new CustomJDBCDaoImpl() );
}
}

Related

Spring security use wrong security context when there are two of them

I have 2 types of users, Schools and Volunteers, Each have their own UserDetails implementation, and UserDetailsService implementations, also each have different http configuration:
This one is for schools
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/school/**")
.userDetailsService(service)
.formLogin().loginPage("/school/login").permitAll().usernameParameter("username")
.passwordParameter("password").failureUrl("/school/login?error=true")
.and()
.authorizeRequests()
.antMatchers("/school/register").permitAll()
.antMatchers("/school/confirm**").permitAll()
.antMatchers("/school/**").hasRole(School.class.getSimpleName())
.and()
.rememberMe().tokenValiditySeconds(2592000).rememberMeParameter("remember-me")
.userDetailsService(service).key("S").rememberMeCookieName("S")
.and()
.logout().logoutSuccessUrl("/").logoutUrl("/school/logout");
}
And this one is for volunteers
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/volunteer/**")
.userDetailsService(service)
.formLogin().loginPage("/volunteer/login").permitAll().usernameParameter("username")
.passwordParameter("password").failureUrl("/volunteer/login?error=true")
.and()
.authorizeRequests()
.antMatchers("/volunteer/register").permitAll()
.antMatchers("/volunteer/confirm**").permitAll()
.antMatchers("/volunteer/**").hasRole(Volunteer.class.getSimpleName())
.and()
.rememberMe().tokenValiditySeconds(2592000).rememberMeParameter("remember-me")
.userDetailsService(service).key("V").rememberMeCookieName("V")
.and()
.logout().logoutSuccessUrl("/").logoutUrl("/volunteer/logout");
}
In both service is their user details service implementation
They are configured in two nested classes that extends WebSecurityConfigurerAdapter.
So my problem is that when i log in as school, and then go to (for example) http://localhost/volunteer, it shows 403 forbidden instead of login form.
I turned on debug and saw that it just found authenticated user in security context and use it, and while it has no required role it fails with 403, then if i explicitly go to login page for volunteers and login, it then couldn't login as school with the same 403. Here is logs:
This and etc. for login as school:
17:11:50.628 [http-nio-8081-exec-9] DEBUG security.web.util.matcher.AntPathRequestMatcher: Checking match of request : '/school/login'; against '/volunteer/**'
17:11:50.629 [http-nio-8081-exec-9] DEBUG security.web.util.matcher.AntPathRequestMatcher: Checking match of request : '/school/login'; against '/school/**'
17:11:50.629 [http-nio-8081-exec-9] DEBUG security.web.FilterChainProxy: /school/login at position 1 of 15 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
17:11:50.629 [http-nio-8081-exec-9] DEBUG security.web.FilterChainProxy: /school/login at position 2 of 15 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
17:11:50.629 [http-nio-8081-exec-9] DEBUG security.web.context.HttpSessionSecurityContextRepository: HttpSession returned null object for SPRING_SECURITY_CONTEXT
17:11:50.629 [http-nio-8081-exec-9] DEBUG security.web.context.HttpSessionSecurityContextRepository: No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#1dd229eb. A new one will be created.
17:11:50.629 [http-nio-8081-exec-9] DEBUG security.web.FilterChainProxy: /school/login at position 3 of 15 in additional filter chain; firing Filter: 'HeaderWriterFilter'
17:11:50.630 [http-nio-8081-exec-9] DEBUG security.web.header.writers.HstsHeaderWriter: Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#19d9486b
17:11:50.630 [http-nio-8081-exec-9] DEBUG security.web.FilterChainProxy: /school/login at position 4 of 15 in additional filter chain; firing Filter: 'CharacterEncodingFilter'
17:11:50.630 [http-nio-8081-exec-9] DEBUG security.web.FilterChainProxy: /school/login at position 5 of 15 in additional filter chain; firing Filter: 'CsrfFilter'
17:11:50.630 [http-nio-8081-exec-9] DEBUG security.web.FilterChainProxy: /school/login at position 6 of 15 in additional filter chain; firing Filter: 'LogoutFilter'
17:11:50.630 [http-nio-8081-exec-9] DEBUG security.web.util.matcher.AntPathRequestMatcher: Checking match of request : '/school/login'; against '/school/logout'
17:11:50.630 [http-nio-8081-exec-9] DEBUG security.web.FilterChainProxy: /school/login at position 7 of 15 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
17:11:50.630 [http-nio-8081-exec-9] DEBUG security.web.util.matcher.AntPathRequestMatcher: Checking match of request : '/school/login'; against '/school/login'
17:11:50.630 [http-nio-8081-exec-9] DEBUG security.web.authentication.UsernamePasswordAuthenticationFilter: Request is to process authentication
And then when i go to volunteer section:
17:15:03.860 [http-nio-8081-exec-5] DEBUG security.web.util.matcher.AntPathRequestMatcher: Checking match of request : '/volunteer'; against '/volunteer/**'
17:15:03.861 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 1 of 15 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
17:15:03.861 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 2 of 15 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
17:15:03.861 [http-nio-8081-exec-5] DEBUG security.web.context.HttpSessionSecurityContextRepository: Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl#b35de31c: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#b35de31c: Principal: com.primaryrun.model.school.SecureSchool#16d; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#166c8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EC164B454F5406F933CCB3C6CFEF2E1D; Granted Authorities: ROLE_School'
17:15:03.861 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 3 of 15 in additional filter chain; firing Filter: 'HeaderWriterFilter'
17:15:03.861 [http-nio-8081-exec-5] DEBUG security.web.header.writers.HstsHeaderWriter: Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#439cf926
17:15:03.861 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 4 of 15 in additional filter chain; firing Filter: 'CharacterEncodingFilter'
17:15:03.861 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 5 of 15 in additional filter chain; firing Filter: 'CsrfFilter'
17:15:03.861 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 6 of 15 in additional filter chain; firing Filter: 'LogoutFilter'
17:15:03.861 [http-nio-8081-exec-5] DEBUG security.web.util.matcher.AntPathRequestMatcher: Request 'GET /volunteer' doesn't match 'POST /volunteer/logout
17:15:03.861 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 7 of 15 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.util.matcher.AntPathRequestMatcher: Request 'GET /volunteer' doesn't match 'POST /volunteer/login
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 8 of 15 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 9 of 15 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 10 of 15 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 11 of 15 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.authentication.rememberme.RememberMeAuthenticationFilter: SecurityContextHolder not populated with remember-me token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken#b35de31c: Principal: com.primaryrun.model.school.SecureSchool#16d; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#166c8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EC164B454F5406F933CCB3C6CFEF2E1D; Granted Authorities: ROLE_School'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 12 of 15 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.authentication.AnonymousAuthenticationFilter: SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken#b35de31c: Principal: com.primaryrun.model.school.SecureSchool#16d; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#166c8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EC164B454F5406F933CCB3C6CFEF2E1D; Granted Authorities: ROLE_School'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 13 of 15 in additional filter chain; firing Filter: 'SessionManagementFilter'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 14 of 15 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.FilterChainProxy: /volunteer at position 15 of 15 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.util.matcher.AntPathRequestMatcher: Checking match of request : '/volunteer'; against '/volunteer/register'
17:15:03.864 [http-nio-8081-exec-5] DEBUG security.web.util.matcher.AntPathRequestMatcher: Checking match of request : '/volunteer'; against '/volunteer/confirm**'
17:15:03.865 [http-nio-8081-exec-5] DEBUG security.web.util.matcher.AntPathRequestMatcher: Checking match of request : '/volunteer'; against '/volunteer/**'
17:15:03.865 [http-nio-8081-exec-5] DEBUG security.web.access.intercept.FilterSecurityInterceptor: Secure object: FilterInvocation: URL: /volunteer; Attributes: [hasRole('ROLE_Volunteer')]
17:15:03.865 [http-nio-8081-exec-5] DEBUG security.web.access.intercept.FilterSecurityInterceptor: Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#b35de31c: Principal: com.primaryrun.model.school.SecureSchool#16d; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#166c8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EC164B454F5406F933CCB3C6CFEF2E1D; Granted Authorities: ROLE_School
17:15:03.865 [http-nio-8081-exec-5] DEBUG security.access.vote.AffirmativeBased: Voter: org.springframework.security.web.access.expression.WebExpressionVoter#3466a837, returned: -1
17:15:03.887 [http-nio-8081-exec-5] DEBUG context.support.ReloadableResourceBundleMessageSource: No properties file found for [classpath:localization/messages_en_US] - neither plain properties nor XML
17:15:03.888 [http-nio-8081-exec-5] DEBUG context.support.ReloadableResourceBundleMessageSource: Re-caching properties for filename [classpath:localization/messages_en] - file hasn't been modified
17:15:03.889 [http-nio-8081-exec-5] DEBUG context.support.ReloadableResourceBundleMessageSource: No properties file found for [classpath:localization/messages] - neither plain properties nor XML
17:15:03.890 [http-nio-8081-exec-5] DEBUG security.web.access.ExceptionTranslationFilter: Access is denied (user is not anonymous); delegating to AccessDeniedHandler
Is it possible in spring security to be logged in as different users at the same time?
If so, how to achieve this? Do I have to somehow create new security context, authentication provider or some other stuff?
Why does it use Schools' security context if i am at the volunteers side?
Solved by adding a filter to spring security filter chain
http.addFilterBefore(new MultipleLoginFilter(), SecurityContextPersistenceFilter.class);
That store/extract security context in session under different name.
Used annotation to describe dimension via reflection:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SecurityDimension {
String name();
}
That annotate user details implementations.
Also configured logout to invalidate only the user that pressed logout:
http.clearAuthentication(true)
.invalidateHttpSession(false).logoutSuccessHandler(new SimpleLoginInvalidator())
Where SimpleLoginInvalidator is:
public class SimpleLoginInvalidator implements LogoutSuccessHandler {
private static final Logger logger = LoggerFactory.getLogger(SimpleLoginInvalidator.class);
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
HttpSession session = request.getSession();
try {
String dimensionName = authentication.getPrincipal().getClass().getAnnotation(SecurityDimension.class).name();
session.removeAttribute(dimensionName + "_" + SPRING_SECURITY_CONTEXT_KEY);
logger.debug("Cleared security context for dimension: " + dimensionName);
} catch (NullPointerException npe) {
logger.debug("Could not clear custom security context attribute", npe);
}
}
}
Hope it helps someone, still looking for more 'out of the box' answer
MultipleLoginFilter :
public class MultipleLoginFilter extends OncePerRequestFilter {
private static final Pattern pattern = Pattern.compile("(?<!/)/([^/?#]+)");
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
logger.debug("Performing multiple login management");
HttpSession session = request.getSession(false);
String path = request.getRequestURI().replace(request.getContextPath(), "");
String desiredDimension = getDesiredDimension(path);
logger.debug("Requesting security context for security dimension: " + desiredDimension);
SecurityContext context = (SecurityContext) session.getAttribute(SPRING_SECURITY_CONTEXT_KEY);
if (context == null) {
logger.debug("Current context is empty, trying to find and associate the one stored session...");
populateSecurityContextByDimension(session, desiredDimension);
} else {
logger.debug("Extracted non-null current security context: " + context);
String dimensionName = context.getAuthentication().getPrincipal().getClass().getAnnotation(SecurityDimension.class).name();
if (!path.matches("/" + dimensionName + "(/.+)?")) {
logger.debug("Extracted security context is not associated with desired security dimension(" + desiredDimension + "). Storing in session...");
session.setAttribute(dimensionName + "_" + SPRING_SECURITY_CONTEXT_KEY, context);
populateSecurityContextByDimension(session, desiredDimension);
} else {
logger.debug("Current security context is associated with desired security dimension, proceed as default.");
}
}
filterChain.doFilter(request, response);
}
private String getDesiredDimension(String requestUrl) {
Matcher m = pattern.matcher(requestUrl);
String desiredDimension = "";
if (m.find() && m.groupCount() == 1) {
desiredDimension = m.group(1);
} else {
logger.error("Could not identify desired security dimension from url: " + requestUrl);
}
return desiredDimension;
}
private void populateSecurityContextByDimension(HttpSession session, String desiredDimension) {
logger.debug("Extracting stored security context associated with desired dimension(" + desiredDimension + ")...");
SecurityContext localContext = (SecurityContext) session.getAttribute(desiredDimension + "_" + SPRING_SECURITY_CONTEXT_KEY);
session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, localContext);
if(localContext != null) {
logger.debug("Storing extracted context as current, context: " + localContext);
} else {
logger.debug("No security context for dimension(" + desiredDimension + ") in session, assigning null.");
}
}
}

Spring Oauth2 Authorization_Grant - cannot access resources after token - User Anonymous

I'm trying to secure my REST Api with authorization grant flow with spring.
I could obtain (with Postman) an access token, i put the authorization into the header with Bearer, but i could not access resources because Spring Security tell me that:
2017-04-06 17:36:33 [http-nio-8080-exec-9] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository[186] - HttpSession returned null object for SPRING_SECURITY_CONTEXT
2017-04-06 17:36:33 [http-nio-8080-exec-9] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository[116] - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#6e24700e. A new one will be created.
2017-04-06 17:36:33 [http-nio-8080-exec-9] DEBUG o.s.s.w.h.writers.HstsHeaderWriter[130] - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#3e385c64
2017-04-06 17:36:33 [http-nio-8080-exec-9] DEBUG o.s.security.web.FilterChainProxy[325] - /api/user at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2017-04-06 17:36:33 [http-nio-8080-exec-9] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter[100] - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#9057bc48: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#2cd90: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: B1FF11055AA4F347AB8AA7B6E467D93F; Granted Authorities: ROLE_ANONYMOUS'
2017-04-06 17:36:33 [http-nio-8080-exec-9] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor[219] - Secure object: FilterInvocation: URL: /api/user; Attributes: [authenticated]
2017-04-06 17:36:33 [http-nio-8080-exec-9] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor[348] - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#9057bc48: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#2cd90: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: B1FF11055AA4F347AB8AA7B6E467D93F; Granted Authorities: ROLE_ANONYMOUS
2017-04-06 17:36:33 [http-nio-8080-exec-9] DEBUG o.s.s.access.vote.AffirmativeBased[66] - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#53b3549c, returned: -1
2017-04-06 17:36:33 [http-nio-8080-exec-9] DEBUG o.s.s.w.a.ExceptionTranslationFilter[173] - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
So basically, after having obtained the access token, if i use it, i will be an Anonymous User, basically because SPRING_SECURITY_CONTEXT is null...
This is my ResourceServer configuration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{
private final Logger logger = LoggerFactory.getLogger(ResourceServerConfig.class);
#Autowired
DataSource dataSource;
#Override
public void configure(HttpSecurity http) throws Exception {
logger.debug("Api security configured");
http
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().access("hasRole('USER')")
.and().exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.and().httpBasic();
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore());
}
}
This one is the authentication Server
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).authenticationManager(authManager);
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
}
I'm trying to access /api/user with this auth Bearer 77a226bf-74a4-4a89-b2a6-e130c215566b which came from the auth server token request after logging in with the user...
What's wrong?
I've had exactly the same issue after updating spring boot from 1.4 to 1.5. The problem was solved by disabling boot's autoconfiguration black magic.
#EnableAutoConfiguration(exclude = {OAuth2AutoConfiguration.class})
I believe they've added some new ~~bug~~ feature which breaks old apps config.
I think User Role is not getting fetched from the database.
Have to define the role column?
This will help you:
https://dzone.com/articles/spring-security-4-authenticate-and-authorize-users

Extending SimpleUrlAuthenticationFailureHandler produces 404 with No mapping found warning

I am trying to extend SimpleUrlAuthenticationFailureHandler to achieve some custom functionality upon authentication failure in spring security. All of my config is in java code so there is no security xml files, etc. the code for CustomAuthenticationFailureHandler is as below;
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler{
public CustomAuthenticationFailureHandler(String defaultFailureUrl) {
super(defaultFailureUrl);
}
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
String userName = request.getParameter("username");
System.out.println("Invalid login attempt by user " + userName);
// This performs custom auditing upon each login failure
userLogRepository.logUserActivity(userName, -1, request.getRemoteHost(), exception);
super.onAuthenticationFailure(request, response, exception);
}
}
and this handler is applied to the spring security as below;
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("userDetailsService")
UserDetailsService userDetailsService;
#Autowired
#Qualifier("userLogRepository")
UserLogRepository userLogRepository;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
CsrfTokenResponseHeaderBindingFilter csrfTokenFilter = new CsrfTokenResponseHeaderBindingFilter();
http.addFilterAfter(csrfTokenFilter, CsrfFilter.class);
http.authorizeRequests().antMatchers("/rest/**").access("hasRole('ROLE_REST_USER')")
.and().formLogin().successHandler(new CustomLoginSuccessHandler(new AjaxAuthenticationSuccessHandler(new SavedRequestAwareAuthenticationSuccessHandler())))
// If I use the following failureUrl method it all seems to work correctly but then I don't have the custom implementaiton.
//.failureUrl("/login?error=1").permitAll()
.failureHandler(new CustomAuthenticationFailureHandler("/login?error=1"))
.and().logout().invalidateHttpSession(true).addLogoutHandler(new CustomLogoutSuccessHandler()).permitAll()
.and().exceptionHandling().accessDeniedPage("/403")
.and().csrf();
}
I have put the org.springframework.security package in debug mode logging for both config 1) using the failureUrl and 2) using custom failure handler. In the below log snippets the DefaultLoginPageGeneratingFilter seems to redirect correctly to "/login?error=1" if the failureUrl configuration is use.
Using failureUrl method (This works)
2016-10-06 15:43:24,839 [http-bio-8080-exec-5 : DEBUG] SimpleUrlAuthenticationFailureHandler : Redirecting to /login?error=1
2016-10-06 15:43:24,839 [http-bio-8080-exec-5 : DEBUG] DefaultRedirectStrategy : Redirecting to '/web-console/login?error=1'
2016-10-06 15:43:24,840 [http-bio-8080-exec-5 : DEBUG] HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#798d735c
2016-10-06 15:43:24,840 [http-bio-8080-exec-5 : DEBUG] HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2016-10-06 15:43:24,840 [http-bio-8080-exec-5 : DEBUG] SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2016-10-06 15:43:24,843 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-10-06 15:43:24,843 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#4ef1ae10. A new one will be created.
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 5 of 14 in additional filter chain; firing Filter: 'CsrfTokenResponseHeaderBindingFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 6 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /logout
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 7 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /login
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 8 of 14 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#798d735c
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2016-10-06 15:43:24,845 [http-bio-8080-exec-6 : DEBUG] SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
Using Custom failure handler (This doesn't work)
2016-10-06 15:37:20,413 [http-bio-8080-exec-6 : DEBUG] DefaultRedirectStrategy : Redirecting to '/web-console/login?error=1'
2016-10-06 15:37:20,413 [http-bio-8080-exec-6 : DEBUG] HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#26019c88
2016-10-06 15:37:20,414 [http-bio-8080-exec-6 : DEBUG] HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2016-10-06 15:37:20,414 [http-bio-8080-exec-6 : DEBUG] SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2016-10-06 15:37:20,417 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-10-06 15:37:20,417 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-10-06 15:37:20,417 [http-bio-8080-exec-7 : DEBUG] HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
2016-10-06 15:37:20,417 [http-bio-8080-exec-7 : DEBUG] HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#58e4d010. A new one will be created.
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 5 of 14 in additional filter chain; firing Filter: 'CsrfTokenResponseHeaderBindingFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 6 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /logout
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 7 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /login
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 8 of 14 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 9 of 14 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] DefaultSavedRequest : pathInfo: both null (property equals)
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] DefaultSavedRequest : queryString: arg1=null; arg2=error=1 (property not equals)
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] HttpSessionRequestCache : saved request doesn't match
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 10 of 14 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 99432565D3173E5497B49BC0DF428692; Granted Authorities: ROLE_ANONYMOUS'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 12 of 14 in additional filter chain; firing Filter: 'SessionManagementFilter'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 13 of 14 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 14 of 14 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /logout
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] AntPathRequestMatcher : Checking match of request : '/login'; against '/rest/**'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterSecurityInterceptor : Public object - authentication not attempted
2016-10-06 15:37:20,420 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 reached end of additional filter chain; proceeding with original chain
I have only attached relevant log snippets as the debug mode has produce a lot of logs which I don't think are relevant, however do let me know if required any I can add more.
I am not sure if I am missing something in configuration here. Would someone please advice me how should I approach the failure url redirection scenario while using the custom failure handler?
As mentioned in one of the comments using custom login form has worked even if the login page is the same name as default i.e. /login. Looking at the code of DefaultLoginPageGeneratingFilter it only sets the logout and failure url if failure handler is not used. My working WebSecurityConfigurerAdapter config looks like as below;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)/*.passwordEncoder(new BCryptPasswordEncoder())*/;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(csrfTokenFilter, CsrfFilter.class);
http.authorizeRequests().antMatchers("/rest/**").access("hasRole('ROLE_REST_USER')")
.and().formLogin().loginPage("/login").usernameParameter("username").passwordParameter("password").permitAll()
.successHandler(loginSuccessHandler)
.failureHandler(authenticationFailureHandler).permitAll()
.and().logout().invalidateHttpSession(true).addLogoutHandler(logoutSuccessHandler).permitAll()
.and().exceptionHandling().accessDeniedPage("/403")
.and().csrf();
}

404 error page configuration with Spring 4 annotations

I have a Spring MVC project with Spring 4. My server is tomcat 7.
I'm trying to make a 404 page, I tried many things, but I couldn't do that.
What am I missing?
Here is WebAppContext :
#Configuration
#ComponentScan(basePackages = {
"com.***"
})
#EnableWebMvc
public class WebAppContext extends WebMvcConfigurerAdapter {
private static final String VIEW_RESOLVER_PREFIX = "/WEB-INF/pages/";
private static final String VIEW_RESOLVER_SUFFIX = ".jsp";
#Autowired
private EventLogService eventLogService;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public SimpleMappingExceptionResolver exceptionResolver() {
SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
Properties exceptionMappings = new Properties();
exceptionMappings.put("org.springframework.security.web.authentication.rememberme.CookieTheftException", "user/login?error=sessionExpired");
exceptionMappings.put("java.lang.RuntimeException", "error/error");
exceptionMappings.put("java.lang.Exception", "error/error");
exceptionResolver.setExceptionMappings(exceptionMappings);
Properties statusCodes = new Properties();
statusCodes.put("error/403", "403");
statusCodes.put("error/404", "404");
statusCodes.put("error/error", "500");
exceptionResolver.setStatusCodes(statusCodes);
return exceptionResolver;
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix(VIEW_RESOLVER_PREFIX);
viewResolver.setSuffix(VIEW_RESOLVER_SUFFIX);
return viewResolver;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
registry.addInterceptor(new EventLogInterceptor(eventLogService)).addPathPatterns("/xyz/{urlText}");
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor(){
LocaleChangeInterceptor localeChangeInterceptor=new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
#Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
cookieLocaleResolver.setDefaultLocale(new Locale("en"));
return cookieLocaleResolver;
}
}
Here is my security config
#Override
protected void configure(HttpSecurity http) throws Exception {
http
//Configures form login
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login/authenticate")
.failureUrl("/login?error=bad_credentials")
.and()
.exceptionHandling().accessDeniedPage("/403")
//Configures the logout function
.and()
.logout()
.deleteCookies("JSESSIONID")
.logoutUrl("/logout")
.logoutSuccessUrl("/")
//Configures url based authorization
.and()
.authorizeRequests()
//Anyone can access the urls
.antMatchers(
"/auth/**",
"/signin",
"/login",
"/feedback",
"/signup/**",
"/user/forgotPass/**"
).permitAll()
.antMatchers(
"/user/settings/**"
).authenticated()
.antMatchers(
"/report/**"
).hasAnyRole("ADMIN")
.antMatchers("/manage/**"
).hasAnyRole("ADMIN", "EDITOR")
.and()
.rememberMe().rememberMeServices(springSocialSecurityRememberMeServices())
.key("MyRememberMe")
.and()
.apply(new SpringSocialConfigurer());
}
Application Config:
public class ApplicationConfig implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
private static final String DISPATCHER_SERVLET_MAPPING = "/";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(ApplicationContext.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(rootContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping(DISPATCHER_SERVLET_MAPPING);
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
FilterRegistration.Dynamic characterEncoding = servletContext.addFilter("characterEncoding", characterEncodingFilter);
characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
FilterRegistration.Dynamic security = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
security.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
servletContext.addListener(new ContextLoaderListener(rootContext));
}
}
My page is at /src/main/webapp/WEB-INF/pages/error/404.jsp location.
I get this error page, when I try a random url:
Here is the log file:
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-09-01 09:25:05 DEBUG HttpSessionSecurityContextRepository:167 - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl#44339553: Authentication: org.springframework.security.authentication.RememberMeAuthenticationToken#44339553: Principal: com.**#2e96279e[id=10,username=**,firstName=**,lastName=**,role=ROLE_USER,socialSignInProvider=<null>,profileImageUrl;=<null>]; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2015-09-01 09:25:05 DEBUG HstsHeaderWriter:129 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#a3c01f
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 5 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/logout'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 6 of 14 in additional filter chain; firing Filter: 'SocialAuthenticationFilter'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 7 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:127 - Request 'GET /test' doesn't match 'POST /login/authenticate
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 8 of 14 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 9 of 14 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 10 of 14 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
2015-09-01 09:25:05 DEBUG RememberMeAuthenticationFilter:142 - SecurityContextHolder not populated with remember-me token, as it already contained: 'org.springframework.security.authentication.RememberMeAuthenticationToken#44339553: Principal: com.**#2e96279e[id=10,username=**,firstName=**,lastName=**,role=ROLE_USER,socialSignInProvider=<null>,profileImageUrl;=<null>]; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2015-09-01 09:25:05 DEBUG AnonymousAuthenticationFilter:107 - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.RememberMeAuthenticationToken#44339553: Principal: com.**#2e96279e[id=10,username=**,firstName=**,lastName=**,role=ROLE_USER,socialSignInProvider=<null>,profileImageUrl;=<null>]; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 12 of 14 in additional filter chain; firing Filter: 'SessionManagementFilter'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 13 of 14 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2015-09-01 09:25:05 DEBUG FilterChainProxy:337 - /test at position 14 of 14 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/auth/**'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/signin'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/login'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/feedback'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/signup/**'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/user/forgotpass/**'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/user/activate/**'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/user/register/**'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/user/{username}/**'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/user/settings/**'
2015-09-01 09:25:05 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/test'; against '/report/**'
2015-09-01 09:25:05 DEBUG FilterSecurityInterceptor:185 - Public object - authentication not attempted
2015-09-01 09:25:05 DEBUG FilterChainProxy:323 - /test reached end of additional filter chain; proceeding with original chain
2015-09-01 09:25:05 DEBUG DispatcherServlet:845 - DispatcherServlet with name 'dispatcher' processing GET request for [/test]
2015-09-01 09:25:05 DEBUG RequestMappingHandlerMapping:297 - Looking up handler method for path /test
2015-09-01 09:25:05 DEBUG RequestMappingHandlerMapping:305 - Did not find handler method for [/test]
2015-09-01 09:25:05 DEBUG SimpleUrlHandlerMapping:169 - Matching patterns for request [/test] are [/**]
2015-09-01 09:25:05 DEBUG SimpleUrlHandlerMapping:194 - URI Template variables for request [/test] are {}
2015-09-01 09:25:05 DEBUG SimpleUrlHandlerMapping:124 - Mapping [/test] to HandlerExecutionChain with handler [org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#3396f11f] and 1 interceptor
2015-09-01 09:25:05 DEBUG DispatcherServlet:931 - Last-Modified value for [/test] is: -1
2015-09-01 09:25:05 DEBUG DispatcherServlet:1018 - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling
2015-09-01 09:25:05 DEBUG DispatcherServlet:991 - Successfully completed request
2015-09-01 09:25:05 DEBUG ExceptionTranslationFilter:115 - Chain processed normally
2015-09-01 09:25:05 DEBUG SecurityContextPersistenceFilter:97 - SecurityContextHolder now cleared, as request processing completed
This issue is related to Servlet 3 spec rather than Spring MVC 4. Although Servlet 3 provided a programatic mechanism to configure the web components (Servlets, Filters etc.), it is still not full fledged. There is a JIRA which explains this https://java.net/jira/browse/SERVLET_SPEC-50.
So, the solution is to add web.xml and configure error pages there in traditional way.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/j2ee"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd"
version="3.0">
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/pages/error/404.jsp</location>
</error-page>
</web-app>

Spring security custom login form issue

When making post request to login controller url (/api/auth) I recieve index.html in response.
My security config:
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.
inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/assets/**","/index.html","/css/**","/js/**","/views/**","/bower_components/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/api/auth")
.permitAll().and().csrf().disable();
http.authorizeRequests().anyRequest().authenticated().and().csrf().disable();
}
}
My angular controller:
app.controller('LoginController', function ($rootScope, $scope, $http, $location) {
var authenticate = function (credentials, callback) {
var headers = credentials ? {authorization: "Basic " + btoa(credentials.username + ":" + credentials.password)} : {};
credentials ? console.log(credentials.username + " " + credentials.password) : console.log("empty credentials")
//console.log(header);
$http.post('/#/api/auth', {"headers":headers}).success(function (data) {
if (data.name) {
$rootScope.authenticated = true;
console.log("in authenticate " + data.name)
} else {
$rootScope.authenticated = false;
console.log("in authenticate data in null")
}
callback && callback();
}).error(function () {
$rootScope.authenticated = false;
console.log("error in authenticate")
callback && callback();
});
}
authenticate();
$scope.credentials = {};
$scope.login = function () {
authenticate($scope.credentials, function () {
if ($rootScope.authenticated) {
$location.path("/");
console.log("in callback " + $scope.credentials)
$scope.error = false;
} else {
$location.path("/api/auth");
console.log("error in callback")
$scope.error = true;
}
});
};
})
My rest controller:
#Controller
#RequestMapping("/api")
public class LoginLogoutController {
#RequestMapping(method = RequestMethod.POST, value="/auth")
public void home(#RequestBody String wrap){
System.out.println(wrap);
}
Spring security logs (this logs appear when I try to post login and password):
20:48:06.469 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No HttpSession currently exists
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#11dc2a2b
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/index.html'; against '/logout'
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 5 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/index.html'; against '/api/auth'
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
20:48:06.470 [http-apr-8090-exec-7] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
20:48:06.471 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
20:48:06.471 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
20:48:06.471 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
20:48:06.471 [http-apr-8090-exec-7] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/index.html'; against '/assets/**'
20:48:06.471 [http-apr-8090-exec-7] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/index.html'; against '/index.html'
20:48:06.471 [http-apr-8090-exec-7] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /index.html; Attributes: [permitAll]
20:48:06.471 [http-apr-8090-exec-7] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
20:48:06.474 [http-apr-8090-exec-7] DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#152d862b, returned: 1
20:48:06.474 [http-apr-8090-exec-7] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Authorization successful
20:48:06.474 [http-apr-8090-exec-7] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - RunAsManager did not change Authentication object
20:48:06.474 [http-apr-8090-exec-7] DEBUG o.s.security.web.FilterChainProxy - /index.html reached end of additional filter chain; proceeding with original chain
20:48:06.474 [http-apr-8090-exec-7] DEBUG o.s.s.w.a.ExceptionTranslationFilter - Chain processed normally
20:48:06.474 [http-apr-8090-exec-7] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
20:48:06.474 [http-apr-8090-exec-7] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
Other rest endpoints work fine. Spring default login form works great but issue appears when I try to run with custom login form.

Categories

Resources