The problem
There is one weird issue in our application that sometimes after login, it redirects to index.html but it failed to load.
The problem only happens occasionally.
Troubleshooting Process
Use chrome devtool to check requests in network panel, some protected api works fine, but some fails and sends redirect to login page due to 302 Found.
-- This is weird. Usually it should fail/succeed for all. This leads me to check the difference between succeeded and failed requests.
Then I check the cookie settings in chrome://settings/cookies
I saw there are 2 JSESSIONID, one in path /, one in path /v1/data
Reproduce the issue
Next I tried to find a way to reliably and conveniently reproduce the issue, then found out that:
The problem happens if I first visits apis like v1/data/products. No problem if I first visits /login or /index.html.
Then I check more detail at the request and response in network panel.
Found that when first access v1/data/products, the response is 302, and redirect to login page, the cookie is:
Set-Cookie:JSESSIONID=8C70B083FB7FEAD57F6B6ADF9817E48C; Path=http://localhost/myapp_jbuild_number/; Secure; HttpOnly
Spring created one session for this anonymous user so later it can redirect to original page after login. The session 8C70B083FB7FEAD57F6B6ADF9817E48C is anonymous user.
After login, for api that succeeded, such as v1/xxx, it uses right JSESSIONID.
But for apis failed like v1/data/xx, there are 2 JSESSIONID, in the request headers.
Cookie:JSESSIONID=8C70B083FB7FEAD57F6B6ADF9817E48C; JSESSIONID=1BE7FFCA12C3882AE6F651DBA3759964
As the anonymous user session 8C70B083FB7FEAD57F6B6ADF9817E48C is for path v1/data
the logined user session 1BE7FFCA12C3882AE6F651DBA3759964 is for /, so the server uses the anonymous user session 8C70B083FB7FEAD57F6B6ADF9817E48C.
This is why the request to v1/data/xx failes and returns 302 and redirect to login page.
2016-10-13 00:09:56:0934 INFO 2268116 [ajp-nio-8009-exec-2] Spring Security Debugger -
New HTTP session created: 8C70B083FB7FEAD57F6B6ADF9817E48C
Request received for GET '/v1/data/xxxx':
cookie: JSESSIONID=8C70B083FB7FEAD57F6B6ADF9817E48C; JSESSIONID=1BE7FFCA12C3882AE6F651DBA3759964;
2016-10-13 00:10:10:0330 DEBUG 2281512 [ajp-nio-8009-exec-4] o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6faa6108: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff10d0: RemoteIpAddress: 173.230.196.25; SessionId: 8C70B083FB7FEAD57F6B6ADF9817E48C; Granted Authorities: ROLE_ANONYMOUS'
But Why created one cookie JSESSIONID at path v1/data?
At first, I thought it's because of spring.
But after several hours, I check the request and response again, and wonder why the path is like: Path=http://localhost/myapp_jbuild_number/
This leads me to check apache httpd configuration, and found out the root cause:
ProxyPassReverseCookiePath / http://localhost/myapp-version_jbuild_number/
This is not right and cause wrong path in response header: Set-Cookie: Path=http://localhost/myapp_jbuild_number/
After removed it, it works.
the path in response header is Set-Cookie: ... Path=/;
Misc: WebSecurityConfigurerAdapter
To enable the DebugFilter in spring security, configure WebSecurity in WebSecurityConfigurerAdapter subclass. It will log information (such as session creation) to help the user understand how requests are being handled by Spring Security - But never do this in production.
public void configure(WebSecurity web) throws Exception {
web.debug(true);
}
ProxyPassReverseCookiePath internal-path public-path
Happy Troubleshooting.
There is one weird issue in our application that sometimes after login, it redirects to index.html but it failed to load.
The problem only happens occasionally.
Troubleshooting Process
Use chrome devtool to check requests in network panel, some protected api works fine, but some fails and sends redirect to login page due to 302 Found.
-- This is weird. Usually it should fail/succeed for all. This leads me to check the difference between succeeded and failed requests.
Then I check the cookie settings in chrome://settings/cookies
I saw there are 2 JSESSIONID, one in path /, one in path /v1/data
Reproduce the issue
Next I tried to find a way to reliably and conveniently reproduce the issue, then found out that:
The problem happens if I first visits apis like v1/data/products. No problem if I first visits /login or /index.html.
Then I check more detail at the request and response in network panel.
Found that when first access v1/data/products, the response is 302, and redirect to login page, the cookie is:
Set-Cookie:JSESSIONID=8C70B083FB7FEAD57F6B6ADF9817E48C; Path=http://localhost/myapp_jbuild_number/; Secure; HttpOnly
Spring created one session for this anonymous user so later it can redirect to original page after login. The session 8C70B083FB7FEAD57F6B6ADF9817E48C is anonymous user.
After login, for api that succeeded, such as v1/xxx, it uses right JSESSIONID.
But for apis failed like v1/data/xx, there are 2 JSESSIONID, in the request headers.
Cookie:JSESSIONID=8C70B083FB7FEAD57F6B6ADF9817E48C; JSESSIONID=1BE7FFCA12C3882AE6F651DBA3759964
As the anonymous user session 8C70B083FB7FEAD57F6B6ADF9817E48C is for path v1/data
the logined user session 1BE7FFCA12C3882AE6F651DBA3759964 is for /, so the server uses the anonymous user session 8C70B083FB7FEAD57F6B6ADF9817E48C.
This is why the request to v1/data/xx failes and returns 302 and redirect to login page.
2016-10-13 00:09:56:0934 INFO 2268116 [ajp-nio-8009-exec-2] Spring Security Debugger -
New HTTP session created: 8C70B083FB7FEAD57F6B6ADF9817E48C
Request received for GET '/v1/data/xxxx':
cookie: JSESSIONID=8C70B083FB7FEAD57F6B6ADF9817E48C; JSESSIONID=1BE7FFCA12C3882AE6F651DBA3759964;
2016-10-13 00:10:10:0330 DEBUG 2281512 [ajp-nio-8009-exec-4] o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6faa6108: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff10d0: RemoteIpAddress: 173.230.196.25; SessionId: 8C70B083FB7FEAD57F6B6ADF9817E48C; Granted Authorities: ROLE_ANONYMOUS'
But Why created one cookie JSESSIONID at path v1/data?
At first, I thought it's because of spring.
But after several hours, I check the request and response again, and wonder why the path is like: Path=http://localhost/myapp_jbuild_number/
This leads me to check apache httpd configuration, and found out the root cause:
ProxyPassReverseCookiePath / http://localhost/myapp-version_jbuild_number/
This is not right and cause wrong path in response header: Set-Cookie: Path=http://localhost/myapp_jbuild_number/
After removed it, it works.
the path in response header is Set-Cookie: ... Path=/;
Misc: WebSecurityConfigurerAdapter
To enable the DebugFilter in spring security, configure WebSecurity in WebSecurityConfigurerAdapter subclass. It will log information (such as session creation) to help the user understand how requests are being handled by Spring Security - But never do this in production.
public void configure(WebSecurity web) throws Exception {
web.debug(true);
}
ProxyPassReverseCookiePath internal-path public-path
- Rewrite the path string in Set-Cookie headers. If the beginning of the cookie path matches internal-path, the cookie path will be replaced with public-path.