Spring webflow externalRedirect restarting same flow

倖福魔咒の 提交于 2019-12-13 06:27:21

问题


I am using CAS and just updated to 3.5.1 from 3.4.8. There have been a thousand changes that I think I have handled most of. However, the externalRedirect upon completion seems to be broken somehow. It just loops back to the start of the login-webflow. How could this happen?

This is the end state that is getting reached:

  <!-- The "redirect" end state allows CAS to properly end the workflow while 
    still redirecting the user back to the service required. -->
  <end-state id="redirectView"
    view="externalRedirect:${requestScope.response.url}" />

I know it is getting reached because i set a breakpoint in this method (of org.springframework.webflow.action.ExternalRedirectAction):

protected Event doExecute(RequestContext context) throws Exception {
    String resourceUri = (String) this.resourceUri.getValue(context);
    context.getExternalContext().requestExternalRedirect(resourceUri);
    return success();
}

If i inspect the value of resourceUri before this method returns, I see the uri that this request should be redirected to:

http://mycompany.com:8080/c/portal/login?redirect=%2Fweb%2Fguest%2Fhome&ticket=ST-4-jVOtEEZcy9bXdb4xiV3l-cas

However, if I just run from that breakpoint, instead of being redirected to that page, the same login-webflow starts over. What is happening here? Where should I look? Any hints o n debugging?

--------------- UPDATE ---------------

So after making 0 modifications to the code, just adding some additional breakpoints, it now works as expected. I have no idea what was going on here, but I did finally find the place where the actual redirect happens. For those who are interested, redirects happen in:

org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handleFlowExecutionResult(
        FlowExecutionResult result, ServletExternalContext context,
        HttpServletRequest request, HttpServletResponse response, FlowHandler handler)

回答1:


Looks like this thread has been dormant for a while, but I wanted to throw some info out for anybody who may come along in the future. The following explanation is derived from my experience with CAS 4.0.1. I would be stunned if this did not apply to older versions as well...

The first thing to check here is whether your authentication process happens relatively slowly. For example, if you're a developer who is accessing the authentication database across a VPN link or something. Or if your authentication queries (and ticket storage) are just relatively slow...

If this applies to you, I have found an issue in CAS which interacts with Tomcat in a weird way which exhibits the behavior described above.

The problem in CAS is in a web flow listener called TerminateWebSessionListener. It appears to be an attempt to keep memory usage low by quickly expiring sessions after the flow completes. Problem is, it is implemented pretty naively. It simply grabs the session and sets a "max inactive interval" of 2 seconds on it (by default--you can change this with the timeToDieInSeconds property of TerminateWebSessionListener in cas-servlet.xml.)

The interaction with Tomcat is like this: Tomcat stamps the "last access" time for a session only the first time it is accessed within a request. Each and every time the session is retrieved, however, the last access time is checked against the current time to determine whether the invalidation interval has elapsed.

So what is happening is that TerminateWebSessionListener is expecting HttpSession.setMaxInactiveInterval(2) to cause the session to invalidate 2 seconds after that moment. What it is really telling Tomcat to do is to invalidate the session 2 seconds after the first time it was accessed within the current request. If your authentication/login request happened to take longer than 2 seconds, BOOM!--your session is invalidated the next time somebody asks for it within the same request. Unfortunately, this DOES happen within Spring WebFlow itself. So you've got a race condition here.

I am going to think about this some more, and hopefully suggest a fix to the CAS team. In the meantime, you can either disable the TerminateWebSessionListener in cas-servlet.xml, or you can pump its timeToDieInSeconds up to a value that you expect to be longer than it'll ever take an authentication request to complete. 30 seconds maybe? It seems reasonable to do this. It doesn't appear to be a security measure, just a memory-saving measure.

Code references:

  • CAS 4.0.1
    • TerminateWebSessionListener.java:33 (sessionEnded())
      • CAS sets the session invalidation interval here.
  • Tomcat 7.0.55:
    • Request.java:338 (session instance variable.)
      • Tomcat stores the session on the Request for its duration.
    • Request.java:2899 (doGetSession())
      • Session early-returned without access() if already cached on the request.
    • Request.java:2921 (doGetSession())
      • On first access in the request, session is looked up, access() called, and cached on the request.

(Note: StandardSession.access() simply stamps the session with a last accessed time of System.currentTimeMillis().)




回答2:


I found something useful. May or may not apply to your specific issue. But if you call this flow as a sub-flow, the view argument of end-states will be ignored.

However if you just call this flow normally, it will do the redirect. What you can do to fix this is to use a view-state instead of a end-state. but this will keep you flow and parent flow open.



来源:https://stackoverflow.com/questions/13145132/spring-webflow-externalredirect-restarting-same-flow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!