Uploaded image for project: 'WildFly Elytron'
  1. WildFly Elytron
  2. ELY-2589

Elytron SSO does not expire other application sessions for session invalidation like Undertow SSO promptly following sessionid change

      Previously using Undertow SSO as shown here, all sessions associated with an SSO id would be invalidated when one session associated with it is manually invalidated.

      This is quite different with Elytron SSO. It is trying to make a call back to attempt a logout of other participant sessions, but that does not work if that call back URI happens to be protected. For instance, this trace shows a logout call back being attempted but being given the FORM login page response:

      2023-09-05 13:39:39,871 DEBUG [io.undertow.request] (default I/O-4) Matched prefix path /app2 for path /app2/session.jsp
      2023-09-05 13:39:39,872 TRACE [io.undertow.server.handlers.resource.PathResourceManager] (default I/O-4) Found path resource session.jsp from path resource manager with base /home/aogburn/code/03598968/wildfly-29.0.1.Final/standalone/deployments/ssotest.ear/app2.war/
      2023-09-05 13:39:39,872 TRACE [org.wildfly.security.http.servlet] (default task-2) Created ServletSecurityContextImpl enableJapi=true, integratedJaspi=true, applicationContext=default-host /app2
      2023-09-05 13:39:39,872 DEBUG [io.undertow.request.security] (default task-2) Security constraints for request /app2/session.jsp are [SingleConstraintMatch{emptyRoleSemantic=PERMIT, requiredRoles=[user]}]
      2023-09-05 13:39:39,873 DEBUG [io.undertow.request.security] (default task-2) Authenticating required for request HttpServerExchange{ POST /app2/session.jsp}
      2023-09-05 13:39:39,873 DEBUG [io.undertow.request.security] (default task-2) Setting authentication required for exchange HttpServerExchange{ POST /app2/session.jsp}
      2023-09-05 13:39:39,873 TRACE [org.wildfly.security.http.servlet] (default task-2) No AuthConfigProvider for layer=HttpServlet, appContext=default-host /app2
      2023-09-05 13:39:39,873 TRACE [org.wildfly.security.http.servlet] (default task-2) JASPIC Unavailable, using HTTP authentication.
      2023-09-05 13:39:39,873 TRACE [org.wildfly.security] (default task-2) No CachedIdentity to restore.
      2023-09-05 13:39:39,873 TRACE [org.wildfly.security] (default task-2) Created HttpServerAuthenticationMechanism [org.wildfly.security.auth.server.SecurityIdentityServerMechanismFactory$1@4911d3ee] for mechanism [FORM]
      2023-09-05 13:39:39,873 TRACE [io.undertow.request] (default task-2) Created form encoded parser for HttpServerExchange{ POST /app2/session.jsp}
      2023-09-05 13:39:39,876 TRACE [org.wildfly.security] (default task-2) Handling SocketAddressCallback
      2023-09-05 13:39:39,878 TRACE [org.wildfly.security] (default task-2) Handling MechanismInformationCallback type='HTTP' name='FORM' host-name='localhost' protocol='http'
      2023-09-05 13:39:39,878 TRACE [org.wildfly.security.http.form] (default task-2) Trying to re-authenticate. There is no session attached to the following request. Request URI: [http://localhost:8080/app2/session.jsp], Context path: [/app2]
      2023-09-05 13:39:39,883 TRACE [org.wildfly.security] (default task-2) Handling CachedIdentityAuthorizeCallback: principal = null  authorizedIdentity = null
      2023-09-05 13:39:39,887 TRACE [io.undertow.session] (default task-2) Setting session cookie session id RSl5cd8acyAlWt0ctW16ZadKbxc1nqPQs_4WuzRr.aogburn on HttpServerExchange{ POST /app2/session.jsp}
      2023-09-05 13:39:39,888 TRACE [io.undertow.server.handlers.resource.PathResourceManager] (default task-2) Found path resource login.html from path resource manager with base /home/aogburn/code/03598968/wildfly-29.0.1.Final/standalone/deployments/ssotest.ear/app2.war/
      2023-09-05 13:39:39,891 TRACE [io.undertow.server.HttpServerExchange] (default task-2) Starting to write response for HttpServerExchange{ POST /app2/login.html}
      2023-09-05 13:39:39,901 DEBUG [org.wildfly.security] (default task-1) Destroying SSO [5aaZDwrjfhHkHzSjQrtxpf91NDx5rOzH8Gcb92Yf]. Participant list not empty.
      

            [ELY-2589] Elytron SSO does not expire other application sessions for session invalidation like Undertow SSO promptly following sessionid change

            Farah Juma added a comment -

            I have now submitted PRs for this:

            The test case now mimics the steps from the reproducer and confirms that when the ID of a session is changed, the SSO session cache is now updated accordingly. This ensures that when a session is invalidated, the other participants will be updated accordingly as well since the SSO session cache is now properly aware of these sessions.

            Farah Juma added a comment - I have now submitted PRs for this: Elytron PR with the fix: https://github.com/wildfly-security/wildfly-elytron/pull/2094 Elytron Web PR with a new test case for the fix: https://github.com/wildfly-security/elytron-web/pull/245 The test case now mimics the steps from the reproducer and confirms that when the ID of a session is changed, the SSO session cache is now updated accordingly. This ensures that when a session is invalidated, the other participants will be updated accordingly as well since the SSO session cache is now properly aware of these sessions.

            Farah Juma added a comment - - edited

            Thanks for the analysis rhn-support-aogburn!

            The changes for ELY-1945 ensure that if we are associating an identity with the session for the first time then we need to change the ID of the session.

            However, when the ID of the session is changed, the SSO session cache isn’t updated accordingly. This means that the corresponding logout handling for the session won’t get registered.

            If we look at the steps from the reproducer:

            a. http://localhost:8080/app1/session.jsp (login alice:alice)
            b. http://localhost:8080/app2/session.jsp
            c. http://localhost:8080/app1/invalidate.jsp
            d. http://localhost:8080/app1/session.jsp (login again)
            e. http://localhost:8080/app2/session.jsp (note this still accesses the same session as request b)

            The underlying issue is that in step b), when CachedIdentityAuthorizationCallback#setAuthorized is called, the super#setAuthorized call happens before the delegate#setAuthorized call. This means that the DefaultSingleSignOnSession#put method gets called first which adds a new participant to the SSO entry using the current session ID.

            Then, when delegate#setAuthorized is called, the put method from the delegate FORM mechanism’s IdentityCache will be called where the session ID is then changed.

            The SSO entry is not updated with the new session ID at this point so it still contains the old one.

            So after step c) where invalidate.jsp is called for app1, the new session ID associated with app2 won’t be invalidated because the SSO session cache doesn’t know about it.

            To fix this, it looks like we could change the order in which setAuthorized gets called in CachedIdentityAuthorizationCallback#setAuthorized.

            In particular, if the delegate#setAuthorized call happens first, then the put method from the delegate FORM mechanism’s IdentityCache will be called first and the session ID will be changed. Then, when super#setAuthorized is called, this will result in the DefaultSingleSignOnSession#put method being called which will then add a new participant to the SSO entry using the new session ID.

            Thus, the SSO session cache will contain the correct session information.

            pferraro@redhat.com Just wanted to check if this approach makes sense to you or if you see a different way to fix this?
             

            Farah Juma added a comment - - edited Thanks for the analysis rhn-support-aogburn ! The changes for ELY-1945 ensure that if we are associating an identity with the session for the first time then we need to change the ID of the session. However, when the ID of the session is changed, the SSO session cache isn’t updated accordingly. This means that the corresponding logout handling for the session won’t get registered. If we look at the steps from the reproducer: a. http://localhost:8080/app1/session.jsp (login alice:alice) b. http://localhost:8080/app2/session.jsp c. http://localhost:8080/app1/invalidate.jsp d. http://localhost:8080/app1/session.jsp (login again) e. http://localhost:8080/app2/session.jsp (note this still accesses the same session as request b) The underlying issue is that in step b), when CachedIdentityAuthorizationCallback#setAuthorized is called, the super#setAuthorized call happens before the delegate#setAuthorized call. This means that the DefaultSingleSignOnSession#put method gets called first which adds a new participant to the SSO entry using the current session ID. Then, when delegate#setAuthorized is called, the put method from the delegate FORM mechanism’s IdentityCache will be called where the session ID is then changed. The SSO entry is not updated with the new session ID at this point so it still contains the old one. So after step c) where invalidate.jsp is called for app1 , the new session ID associated with app2 won’t be invalidated because the SSO session cache doesn’t know about it. To fix this, it looks like we could change the order in which setAuthorized gets called in CachedIdentityAuthorizationCallback#setAuthorized . In particular, if the delegate#setAuthorized call happens first , then the put method from the delegate FORM mechanism’s IdentityCache will be called first and the session ID will be changed. Then, when super#setAuthorized is called, this will result in the DefaultSingleSignOnSession#put method being called which will then add a new participant to the SSO entry using the new session ID. Thus, the SSO session cache will contain the correct session information. pferraro@redhat.com Just wanted to check if this approach makes sense to you or if you see a different way to fix this?  

            Aaron Ogburn added a comment - - edited

            Looking a bit further, my initial assessment was incorrect as to the reason of the failure. The app2 logout callback fails in that flow because of a change in the session id. So the /app2/session.jsp request initially creates id session-2a and ties that to the SSO; upon authentication completion, it changes the the id to a new value (session-2b). That changed session id is not tied to the SSO yet so the logout callback from request c is attempted with id session-2a, which doesn't match to invalidate the session now with id session-2b; the request is then handled with an authentication attempt to cause that confusion.

            So if you request /app2/session.jsp twice, the post auth changed session id is associated with SSO and this then avoids the issue:

            a. http://localhost:8080/app1/session.jsp (login alice:alice)
            b. http://localhost:8080/app2/session.jsp
            c. http://localhost:8080/app2/session.jsp again
            d. http://localhost:8080/app1/invalidate.jsp
            e. http://localhost:8080/app1/session.jsp (login again)
            f. http://localhost:8080/app2/session.jsp (note this doesn't access the same session as request b/c)
            

            Ideally, we'd need Elytron SSO to be immediately aware of any sessionid change.

            Aaron Ogburn added a comment - - edited Looking a bit further, my initial assessment was incorrect as to the reason of the failure. The app2 logout callback fails in that flow because of a change in the session id. So the /app2/session.jsp request initially creates id session-2a and ties that to the SSO; upon authentication completion, it changes the the id to a new value (session-2b). That changed session id is not tied to the SSO yet so the logout callback from request c is attempted with id session-2a, which doesn't match to invalidate the session now with id session-2b; the request is then handled with an authentication attempt to cause that confusion. So if you request /app2/session.jsp twice, the post auth changed session id is associated with SSO and this then avoids the issue: a. http: //localhost:8080/app1/session.jsp (login alice:alice) b. http: //localhost:8080/app2/session.jsp c. http: //localhost:8080/app2/session.jsp again d. http: //localhost:8080/app1/invalidate.jsp e. http: //localhost:8080/app1/session.jsp (login again) f. http: //localhost:8080/app2/session.jsp (note this doesn't access the same session as request b/c) Ideally, we'd need Elytron SSO to be immediately aware of any sessionid change.

              fjuma1@redhat.com Farah Juma
              rhn-support-aogburn Aaron Ogburn
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

                Created:
                Updated:
                Resolved: