0
votes

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:

enter image description here

Redirection Format:

https://APP1_HOST:PORT/auth/j_spring_security_logout?redirectUrl=https://APP2_HOST/abc/AccessServlet?ac=astqcssq-Z-3R2LOFjy-&un=12345

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:

  1. 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.
  2. 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
  3. As such ELB don’t modify any HTTP Header details other than X-Forwarded-* headers is my understanding
  4. 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.

1

1 Answers

0
votes

We have defined custom logout success handler as shown below

<sec:logout success-handler-ref="logoutSuccessHandler" invalidate-session="true" delete-cookies="JSESSIONID" />
  • logoutSuccessHandler class extends SimpleUrlLogoutSuccessHandler class which in turn extends AbstractAuthenticationTargetUrlRequestHandler.
  • SimpleUrlLogoutSuccessHandler and AbstractAuthenticationTargetUrlRequestHandler are part Spring class
  • In my case logoutSuccessHandler is singleton and so are the super class
  • The override method onLogoutSuccess in my logoutSuccessHandler updates the DefaultTargetUrl value from the request and calls the super.handle method

    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
        Authentication authentication) throws IOException, ServletException {
    
    super.setDefaultTargetUrl(request.getParameter("redirectUrl"));
    
    super.onLogoutSuccess(request, response, authentication);
    

    }

DefaultTargetUrl is an instance variable of AbstractAuthenticationTargetUrlRequestHandler.class.

In my issue scenario both the users(USER1, USER2) were handled/processed in same instance and the request received at the same time. Since the custom handler, spring components are singleton and the above 2 steps are not atomic there is a possibility for a thread(t01) to override the DefaultTargetUrl set by another thread (t02).