6 Replies Latest reply on Dec 3, 2010 4:58 PM by Marcel Kolsteren

    SingleLogout after LocalLogout failing.

    Nils Otto Johansen Newbie

      At our company, we are using picketlink to have federated identity management with the norwegian state-driven identity-service (altinn).

       

      We are experiencing problems with singleLogout initiated from the IDP.

       

      The problem arises when we do a local logout in our application (by calling identity.logout()).
      When the user then performs a singleLogout on the IDP, our application receives a logoutRequest and returning HTTP 400
      ( [ExternalAuthenticationFilter] Bad request received from <ip-address> (No active session to logout.) )

       

      It seems to me that picketlink is assuming that a session must be active at the time of the single logout.

       

      I wonder if this is a bug, a known limitation in picketlink or if I have misunderstood this scenario we have.

       

      To reproduce:

       

      1) Login on IDP, gets redirected to application
      2) perform localLogout in application
      3) return to IDP and perform singleLogout
      4) Picketlink recieves a request to SingleLogoutService, returning HTTP 400

       


      Kind regards

       

      Nils Otto Johansen

        • 1. Re: SingleLogout after LocalLogout failing.
          Marcel Kolsteren Apprentice

          Hi Nils Otto,

           

          Good to hear that the Norwegian government chose SAML, and that you chose PicketLink to connect your Seam application to the government's identity provider. :-)

           

          You brought up an interesting case. I've always found it very strange that the SAML spec only provides a single logout where the user is logged out from all service provider applications at once. If the user only wants to logout from one of the applications, there is no way of telling the identity provider (which acts as a session manager) about this. A result is that as soon as the user performs a global logout, the identity provider also sends single logout requests to the session participants that already have terminated their sessions. So I think that in fact your scenario is a limitation of the SAML spec. I quote from section 4.4 of the "Profiles for the OASIS SAML V2.0":

           

          Once a principal has authenticated to an identity provider, the authenticating entity may establish a session with the principal (typically by means of a cookie, URL re-writing, or some other implementation-specific means). The identity provider may subsequently issue assertions to service providers or other relying parties, based on this authentication event; a relying party may use this to establish its own session with the principal.


          In such a situation, the identity provider can act as a session authority and the relying parties as session participants. At some later time, the principal may wish to terminate his or her session either with an individual session participant, or with all session participants in a given session managed by the session authority. The former case is considered out of scope of this specification. The latter case, however, may be satisfied using this profile of the SAML Single Logout protocol ([SAMLCore] Section 3.7).

           

          The question is how a session participant should react when a single logout is received for a session that doesn't exist (any more). I cannot find any requirements in the spec about this error handling. So I think that the PicketLink Seam module is allowed to choose how to behave in this situation. Keeping in mind that the service provider has no way of informing the identity provider when the user logs out from the current application only, I think that PicketLink should just handle this as a successful logout instead of rejecting the request. So I'll create a bug in JIRA for that.

           

          Do you also think that this is in fact a workaround for a limitation of the SAML specification?

          • 3. Re: SingleLogout after LocalLogout failing.
            Nils Otto Johansen Newbie

            Great!

             

            I have been looking for a way to tell the IDP that we no longer want to listen for logoutrequests, but I understand now that there is no way to do that.

            I agree that the most sensible thing to do when the IDP tell us to log out someone we dont know is to simply say that she is logged out.

             

            We have actually already made exactly this change to the picketlink code and tested it locally.

            This solves the scenario where the user initiates singleLogout after the session has been terminated on our side.

             

            Whe do, however, have another variation of this problem to struggle with.

            The users are logging in with their social security number, and then choose at the IDP which company they are representing.

            People may represent several companies, but not at the same time.

             

            When the user wants to switch which company he represents, our application performs a local logout, and then redirects to the IDP at a URL allowing the user to select a new company from the list of companies he may represent.

             

            Coming back to our app, he is then logged inn representing the newly selected company.

             

            When doing a singleLogout after switching company one or several times, the conversation with the IDP goes like this ;:

             

            1) Single Logout Request   from app to IDP

            2) Single Logout Request   from IDP to app (the session is terminated)

            3) Single Logout Response from app to IDP

            5) Single Logout Response from IDP to app (in response to step 1)) - Fails with http 400

             

            ( step 2 and 3 repeats as many times as the user have switched company)

             

            What happens in this scenario is that the SamlMessageReceiver in Picketlink has injected a property of type Requests which manages a list of requests awaiting response.

            The Requests object is session scoped, thus being throwed away in step 2)

            When the IDP sends the logoutResponse in response to step 1) the code cant find the request this respones belongs to, and does


            throw new InvalidRequestException("No request that corresponds with the received response");

             

            I have tried implementing a application-scoped logoutRequests class, similar to the session scoped Requests class. scince this is app-scoped, we can find requests sent from terminated sessions. Modified SamlMessageReceiver to check both lists before throwing the exception

             

            With this change in place, everything seems to work fine.

             

            However, i feel that i am not capable of seeing all implications of this approach.

            One is that this list may increase in size and should probably ble cleaned up at some point.

             

            What do you think, Is this a viable solution to the problem?

             

            Nils Otto

             


            • 4. Re: SingleLogout after LocalLogout failing.
              Marcel Kolsteren Apprentice

              Hi Nils,

               

              I only understand parts of what you try to say. Some questions:

               

              • Suppose that a user is already logged in at the IDP, and has already selected a company over there. Now after some time she wants to represent another company. Does she need to re-login in the IDP again, or can she just choose another company in the IDP application, within the same IDP session?
              • The 4-step conversation with the IDP that you describe only contains single logout stuff. I'd expect that also some logins and local logouts happen in this scenario. Could you expand on that?
              • When the user logs in in your SP application, can you retrieve all companies that the user is allowed to represent? Is it part of the attributes that you receive from the IDP when you get an authentication response? I ask that because I find it strange that the user needs to re-login in the SP application in order to change the company she wants to represent. I have a similar practical situations in one of my Seam projects, where a user can login in the system, and then, during the session, she can switch between "personalities" that are allowed for her, so she can just say "regard me as a private person", and some time later "regard me as an employee of company A", without logging in again. In that case, no interaction with the IDP is required when the user wants to change who/what she likes to represent.
              • 5. Re: SingleLogout after LocalLogout failing.
                Nils Otto Johansen Newbie

                Hi, Marcel.

                 

                Thank you for trying to understand!

                 

                The Session at the IDP-application is the same even if she changes which company to represent.
                The user selects the company at the IDP, and only that one company id is sent to us (as an attribute to the login).

                 

                The conversation with the IDP in my example is what happens after the user (which has changed company) press logout in our application.
                The logout link in our application has #{externalAuthenticator.singleLogout} as action. (Picketlink SingleLogout)

                 

                The IDP sends us only one company at a time. To be able to change company we do a local logout and redirect to the "choose company to represent-page" at the IDP.

                 

                I dont think it is nessecary to keep the session in the sp-application when the user switches copmany to represent. The entire application depends on that company, and all data needs to be reloaded anyway.

                 


                After reading picketlink code and debugging http-conversations this is what I think is happening :

                 

                • The IDP keeps a list of all logins to SP applications
                • When we do a local logout, redirects to the IDP and logs in to the SP again, the IDP regards this as a new login to the SP and adds to the list.
                • When a single logout is issued, the IDP sends logoutRequest to all sessions in list (exept the one initiating SLO)
                • This leads to our application getting one logoutRequest for every time the user has changed company.
                • The Picketlink SamlSingleLogoutReceiver gets all the requests. After the fix you proposed, the first one logs the identity out, the rest returns success.

                 

                • The IDP then sends a logoutResponse to our application in response to the first request. This response is checked in SamlMessageReceiver against the requests in the injected Requests member.
                • Since the requests object is session scoped, it dies along with the first logoutrequest from the IDP (which from the IDP was ment for a session we logged out a long time ago)
                • The response from the IDP is therefore discarded and http 400 returned. (SamlMessageReceiver line ~275: throw new InvalidRequestException("No request that corresponds with the received response");)

                 


                I have made changes to picketlink locally such that all logoutrequests are put in an application scoped list and then checked and deletef from that list when we get the response.
                That solves this issue, but I am unsure if it is the right soloution, both according to specs and performance/scalability-wise.

                 

                 

                Nils Otto

                • 6. Re: SingleLogout after LocalLogout failing.
                  Marcel Kolsteren Apprentice

                  Ok, thanks for the extensive explanation. Your use case is becoming clear to me now. Some further remarks and questions:

                   

                  • When the user needs to change company, she is redirected to the IDP. After selecting another company, a login happens. How does this login happen? Not with a login that is requested by the SP through PicketLink, right? So after the company choice, I'd expect that the login is an "unsolicited login" initiated by the IDP. Is that correct?
                  • Currently PicketLink doesn't have support for multiple sessions of the same user. But that may be a solution direction, because the problem you bumped into has to do with multiple sessions of the same user. You know about the SAML sessionIndex attribute, which identifies one of multiple parallel sessions of the same user at the IDP? If you change the logging level of "org.picketlink" to DEBUG, you'll see the authentication requests and the logout requests coming by. Are there sessionIndex values in those messages? It depends on your IDP whether they are there. A quick test I just performed with OpenSSO showed that sessionIndex is included in the logout requests coming from the IDP, but unfortunately not in the authentication responses sent by the IDP.
                  • Just for your information: I'm also working on the successor of the PicketLink/Seam module. That successor will be part of the security module of Seam 3. This core of this module has some support for multiple parallel sessions for a single user. We choose to expose the core only with a single session API because the multi-session stuff is probably too complex for people that only start with external authentication. Your use case is the first real world use case that I saw, which needs to cope with multiple parallel sessions.