I have a project which totally skipped Spring security usage and handled things manually.
Now, however, I would like to incorporate spring security into my project. After doing everything, the default login form is showing, and I have managed to get user to authenticate using a UserDetailsService implementation (userLoginService in my code). I have followed through the debugging steps to ensure that Spring authenticates users properly.
But, while redirecting to the protected endpoint after authentication, Spring redirects me again to the login page, as if the authentication was never performed. I have been digging into this for 3 days now and I already feel tired. The image below shows the POST call to authentication endpoint, redirection to protected endpoint (/), and then redirection to the login form again.
I am using Spring Security 3.2.7, and my application is configued through xml.
My experience with xml configuration is really lacking and after going through the references of Spring Security 3 and 4 both, I haven't been able to discover why this keeps happening. My best guess was that the role was mixing things up somehow but I couldn't figure anything out regarding this.
Things that I have discovered though:
- I have debugged till the passwords are matched internally and also checked for authenticated field to be true, which it did.
- If I put (/merchants) outside this protection, the authentication object returns an Anonymous authentication
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
. - Authentication failure works fine.
Below are the codes:
spring-security.xml
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<http use-expression="true">
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
<form-login />
<csrf />
</http>
<authentication-manager>
<authentication-provider user-service-ref="userLoginService">
<password-encoder hash="sha-256"/>
</authentication-provider>
</authentication-manager>
</beans:beans>
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:util="http://www.springframework.org/schema/util"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:component-scan base-package="com.example.panel"/>
<import resource="applicationContext.xml"/>
<context:property-placeholder location="classpath:message.properties"/>
<mvc:resources mapping="/media/**" location="/WEB-INF/media/"/>
<mvc:annotation-driven/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/media/**"/>
<mvc:exclude-mapping path="/user/test"/>
<mvc:exclude-mapping path="/user/some-mapping"/>
<bean class="com.example.panel.interceptor.Interceptor">
<property name="some-map" ref="map-list"/>
</bean>
</mvc:interceptor>
</mvc:interceptors>
.... other beans here
<util:map id="mapList">
<entry key="1" value-ref="ADMIN"/>
........................
</util:map>
and my web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<listener>
<listener-class> org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-security.xml,
classpath:dispatcher-servlet.xml,
classpath:applicationContext.xml
</param-value>
</context-param>
<welcome-file-list>
<welcome-file>/</welcome-file>
</welcome-file-list>
<session-config>
<session-timeout>60</session-timeout>
<tracking-mode>SSL</tracking-mode>
</session-config>
<!--Multipart Filter-->
<filter>
<filter-name>MultipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
<init-param>
<param-name>multipartResolverBeanName</param-name>
<param-value>multipartResolver</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MultipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- MDC INSERTING SERVLET FILTER -->
<filter>
<filter-name>MDCInsertingServletFilter</filter-name>
<filter-class>
ch.qos.logback.classic.helpers.MDCInsertingServletFilter
</filter-class>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>MDCInsertingServletFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring Security -->
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<security-constraint>
<web-resource-collection>
<web-resource-name>panel</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
</web-app>
And my applicationContext.xml contain just a few bean declarations.
What can I do fix the security here in this application? Thanks in advance :)
UPDATE
spring security logs
2018-02-08 09:37:19 [INFO] Spring Security Debugger line: 39 -
************************************************************
Request received for GET '/spring_security_login':
org.apache.catalina.connector.RequestFacade@5e366601
servletPath:/spring_security_login
pathInfo:null
headers:
host: localhost:8443
user-agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0
accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/ *;q=0.8
accept-language: en-US,en;q=0.7,bn;q=0.3
accept-encoding: gzip, deflate, br
referer: https://localhost:8443/panel/spring_security_login
cookie: Idea-e04cc54f=d38290c3-dd3e-450f-b445-765ae8b09682; JSESSIONID=4DFA0CA25924C875A75D36369AC3B7D8
dnt: 1
connection: keep-alive
upgrade-insecure-requests: 1
cache-control: max-age=0
Security filter chain: [
SecurityContextPersistenceFilter
WebAsyncManagerIntegrationFilter
CsrfFilter
UsernamePasswordAuthenticationFilter
DefaultLoginPageGeneratingFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2018-02-08 09:37:39 [INFO] Spring Security Debugger line: 39 -
************************************************************
Request received for POST '/j_spring_security_check':
org.apache.catalina.connector.RequestFacade@5e366601
servletPath:/j_spring_security_check
pathInfo:null
headers:
host: localhost:8443
user-agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0
accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/ *;q=0.8
accept-language: en-US,en;q=0.7,bn;q=0.3
accept-encoding: gzip, deflate, br
referer: https://localhost:8443/panel/spring_security_login
content-type: application/x-www-form-urlencoded
content-length: 92
cookie: Idea-e04cc54f=d38290c3-dd3e-450f-b445-765ae8b09682; JSESSIONID=4DFA0CA25924C875A75D36369AC3B7D8
dnt: 1
connection: keep-alive
upgrade-insecure-requests: 1
Security filter chain: [
SecurityContextPersistenceFilter
WebAsyncManagerIntegrationFilter
CsrfFilter
UsernamePasswordAuthenticationFilter
DefaultLoginPageGeneratingFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2018-02-08 09:37:39 [INFO] c.d.b.s.UserLoginService line: 40 - login => org.springframework.security.core.userdetails.User@586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN
2018-02-08 09:37:39 [INFO] Spring Security Debugger line: 39 -
************************************************************
Request received for GET '/':
org.apache.catalina.connector.RequestFacade@5e366601
servletPath:/
pathInfo:null
headers:
host: localhost:8443
user-agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0
accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/ *;q=0.8
accept-language: en-US,en;q=0.7,bn;q=0.3
accept-encoding: gzip, deflate, br
referer: https://localhost:8443/panel/spring_security_login
cookie: Idea-e04cc54f=d38290c3-dd3e-450f-b445-765ae8b09682; JSESSIONID=4DFA0CA25924C875A75D36369AC3B7D8
dnt: 1
connection: keep-alive
upgrade-insecure-requests: 1
Security filter chain: [
SecurityContextPersistenceFilter
WebAsyncManagerIntegrationFilter
CsrfFilter
UsernamePasswordAuthenticationFilter
DefaultLoginPageGeneratingFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2018-02-08 09:37:39 [INFO] Spring Security Debugger line: 39 -
************************************************************
New HTTP session created: 5a7bc5959c07bb1757b60ce4e3091b65bdecee60fae8302527be62c6894f5915
Call stack:
at org.springframework.security.web.debug.Logger.info(Logger.java:29)
at org.springframework.security.web.debug.DebugRequestWrapper.getSession(DebugFilter.java:144)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:240)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:240)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:240)
at org.springframework.security.web.savedrequest.HttpSessionRequestCache.saveRequest(HttpSessionRequestCache.java:40)
at org.springframework.security.web.access.ExceptionTranslationFilter.sendStartAuthentication(ExceptionTranslationFilter.java:184)
at org.springframework.security.web.access.ExceptionTranslationFilter.handleSpringSecurityException(ExceptionTranslationFilter.java:168)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:131)
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.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.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:155)
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.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:85)
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.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.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
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.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:70)
at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:59)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at ch.qos.logback.classic.helpers.MDCInsertingServletFilter.doFilter(MDCInsertingServletFilter.java:49)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:118)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:94)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:616)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:509)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1104)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:285)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
************************************************************
2018-02-08 09:37:39 [INFO] Spring Security Debugger line: 39 -
************************************************************
Request received for GET '/spring_security_login':
org.apache.catalina.connector.RequestFacade@5e366601
servletPath:/spring_security_login
pathInfo:null
headers:
host: localhost:8443
user-agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0
accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/ *;q=0.8
accept-language: en-US,en;q=0.7,bn;q=0.3
accept-encoding: gzip, deflate, br
referer: https://localhost:8443/panel/spring_security_login
cookie: Idea-e04cc54f=d38290c3-dd3e-450f-b445-765ae8b09682; JSESSIONID=4DFA0CA25924C875A75D36369AC3B7D8
dnt: 1
connection: keep-alive
upgrade-insecure-requests: 1
Security filter chain: [
SecurityContextPersistenceFilter
WebAsyncManagerIntegrationFilter
CsrfFilter
UsernamePasswordAuthenticationFilter
DefaultLoginPageGeneratingFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2018-02-08 10:25:03 [DEBUG] o.s.s.w.FilterChainProxy line: 337 - /spring_security_login at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2018-02-08 10:25:03 [DEBUG] o.s.s.w.c.HttpSessionSecurityContextRepository line: 152 - HttpSession returned null object for SPRING_SECURITY_CONTEXT
2018-02-08 10:25:03 [DEBUG] o.s.s.w.c.HttpSessionSecurityContextRepository line: 91 - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@3078ac38. A new one will be created.
2018-02-08 10:25:03 [DEBUG] o.s.s.w.FilterChainProxy line: 337 - /spring_security_login at position 2 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2018-02-08 10:25:03 [DEBUG] o.s.s.w.FilterChainProxy line: 337 - /spring_security_login at position 3 of 11 in additional filter chain; firing Filter: 'CsrfFilter'
2018-02-08 10:25:03 [DEBUG] o.s.s.w.FilterChainProxy line: 337 - /spring_security_login at position 4 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2018-02-08 10:25:03 [DEBUG] o.s.s.w.FilterChainProxy line: 337 - /spring_security_login at position 5 of 11 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
2018-02-08 10:25:03 [DEBUG] o.s.s.w.c.HttpSessionSecurityContextRepository line: 304 - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2018-02-08 10:25:03 [DEBUG] o.s.s.w.c.SecurityContextPersistenceFilter line: 97 - SecurityContextHolder now cleared, as request processing completed
2nd UPDATE
If I roll back to Spring security 3.1.2.Release as per this answer, it works successfully. But but but, 3.1.2 does not include csrf support. Hence, I am targetting to get it to work with Spring Security 3.2 (or greater, where there is csrf support by default).
3rd UPDATE
You can find the logs with both spring security versions 3.1.2 and and 3.2.5 in the gist here.
Since it was marked as duplicate
Spring security has many releases after 3.1 version. I would not want to believe that authentication did not work in all these updates (esp in none of the 3.2 versions), of course, they did. Now, the roll back shows my spring security xml is not exactly wrongly written. But rather, I would like to figure out what's causing this issue, and handle things accordingly. Of course rolling back is not the solution. The referenced question advises to roll back - a solution I'm NOT AT ALL looking for.
P.S. Please let me know if you need to look at or know any additional code/info.
4th UPDATE
I completely discarded all the remaining xml configs and put in Java based config. Everything works as expected now. Going through all this for a simple xml config is not at all worth it.