We have a web application(5+ years old) which uses Spring Security (3.1) feature for authentication and authorization of a user.
- As part of the authentication process we create a random 20 characters access code(ac) and 5 character user number(un)
- Post successful authentication we redirect to another application passing the access code, user number as query params
Based on the access code APP2 displays the information to respective users
Below is a sample flow and the sample format of the spring security redirection:
Redirection Format:
Code flow of the Authentication
@RequestMapping(value="/Authentication.do")
public String doWAuthentication(ModelMap model) {
User user = super.getUser();
String url = app2Baseroot; // instance variable - APP2 Host name
//generate parameters - static methods
String accessCode = Utils.generateString(20);
String userNo = Utils.generateUserNumber(5);
//write authentication details for APP2 to retrieve
userDao.saveAuthenticationDetails(user, accessCode, userNo);
//Add redirection specifics - servlet name & query params
try {
url += java.net.URLEncoder.encode("AccessServlet?ac="+accessCode+"&un="+userNo, "UTF-8");
} catch (UnsupportedEncodingException uee) {
LOG.error("Unable to encode redirect URL: "+uee.toString());
}
//redirect via spring security logout
// AuthBaseroot - Instance variable - APP1 host name
return "redirect:"+AuthBaseroot+"j_spring_security_logout?redirectUrl="+url;
}
We recently faced with an issue where USER 1 was able to view USER 2 details since the redirection URL was mixed up. Both the users accessed the authentication application at the same time i.e. same hour, mins, seconds.
We have defined custom form-login with always-use-default-target property set to "true" and also configured a custom logout handler within the spring security XML file:
<sec:logout success-handler-ref="logoutSuccessHandler" invalidate-session="true" delete-cookies="JSESSIONID" />
LogoutSuccessHandler Extends SimpleUrlLogoutSuccessHandler and overrides onLogoutSuccess. All the method does is to fetch the redirect url from the HttpServletRequest and set it to
AbstractAuthenticationTargetUrlRequestHandler. setDefaultTargetUrl(URL) and call the super method (super.onLogoutSuccess).
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
//Set redirection to APP2 url containing security params
super.setDefaultTargetUrl(request.getParameter("redirectUrl"));
super.onLogoutSuccess(request, response, authentication);
}
- Our Application is hosted in AWS and uses classic ELB and as part of the security all request flow via incapsula imperva
- The ELB has Stickiness enabled to “application generated cookie stickiness”
- We have also enabled access logs at the ELB layer and checking the access logs we could see the redirect URL being mixed up for USER1, USER2
Below is a sample access logs for reference for USER1, USER 2
USER 2:
2019-04-20T09:34:11.328056Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000171 0.050725 0.0001 302 302 0 321
"GET https://APP1_HOST:PORT/auth/j_spring_security_logout?redirectUrl=https://APP2_HOST/link/AccessServlet%3Fac%3DWA-FF7WlNowjyu2R-XaU%26un%3D12345
HTTP/1.1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2
2019-04-20T09:34:11.413849Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000074 0.003343 0.000073 200 200 0 799
"GET https://APP2_HOST/link/AccessServlet%3Fac%3DWA-FF7WlNowjyu2R-XaU%26un%3D12345
HTTP/1.1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2
USER 2 access logs proves the redirection url from the spring security logout j_spring_security_logout matches with the actual redirection.
USER 1
2019-03-26T09:34:11.349198Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000137 0.030374 0.00011 302 302 0 321
"GET https://APP1_HOST:PORT/auth/j_spring_security_logout?redirectUrl=https://APP2_HOST/link/AccessServlet%3Fac%3Dn--qcvnq-Z-3R2LOFjy-%26un%3D13267
HTTP/1.1" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2
2019-03-26T09:34:11.408386Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000066 0.007958 0.000077 200 200 0 1365
"GET https://APP2_HOST/link/AccessServlet%3Fac%3DWA-FF7WlNowjyu2R-XaU%26un%3D12345
HTTP/1.1" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2
The first statement shows the j_spring_security_logout with the right redirection URL for USER 1 but the but the subsequent call to the redirection URL seems to have got mixed up with USER 2. Since the user details are based on the access code USER 1 was able to view USER 2 details.
Few things we have noticed so far:
- USER1, USER2 send the request at the same time i.e. i.e. same hour, mins, seconds. From the access log we see USER 2 request goes first but in terms of response USER 1 gets the response first with USER 2 redirection URL.
- Don't see much of an issue with the access code generation since we see for both USER1, USER2 the initial spring security logout redirection seems to have the right details
- As such ELB don’t modify any HTTP Header details other than X-Forwarded-* headers is my understanding
- Both USER1, USER2 request was handled by same EC2 instance. Default behaviour of classic ELB is to route each request independently to the registered instance with the smallest load. Since we have configured to sticky session feature, which enables the load balancer to bind a user's session to a specific instance. This ensures that all requests from the user during the session are sent to the same instance REF: https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-sticky-sessions.html
Below are the technology used in Authentication module
- Java – 1.6
- Spring MVC, Spring Security (Version 3.1)
- Servlet API – 2.4
- OC4J Server (10.1.3.5)
- Deployed in AWS – uses classic ELB
I am wondering if the issue is at the spring security layer(possibly logout handler) where we fetch the redirection URL from the HttpServletRequest object and pass it in response but haven’t been able to re-produce the issue.
Any inputs or suggestion will be helpful.