2

Related question: https://stackoverflow.com/questions/47293940/sp-initiated-single-logout-not-working-with-salesforce

I'm implementing single-sign-on service using Salesforce as identity provider. My app is now working well with single login. My goal is to make logout from my app (service provider) initiate log out in the identity provider (salesforce). For this purpose I send SAML2 request to Salesforce, however, I always get "We are unable to log you out." error. I searched logs of salesforce to find the cause of the error but didn't find any. In my app i use django, to generate saml I use pysaml2 lib. This is my code to generate logout request:

req_id, request = saml2_client.create_logout_request(
                destination,"<entity-id>",name_id=NameID(text=request.user.email, format=NAMEID_FORMAT_TRANSIENT), expire=soon)
        # request = saml2_client.sign(request)
        rstate = saml2_client._relay_state(req_id)
        msg = http_redirect_message(request, destination, rstate)
        headers = dict(msg['headers'])
        location = headers['Location']
        return HttpResponseRedirect(location)

Generated xml:

<ns0:LogoutRequest
Destination="<logout_endpoint>"
ID="<id>" IssueInstant="2019-08-21T06:44:29Z" NotOnOrAfter="2019-08- 
21T06:49:29Z"
Version="2.0" xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion">
<ns1:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid- 
format:entity">https://localhost:8000/saml2_logout/</ns1:Issuer>
<ns1:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid- 
format:transient">username</ns1:NameID>
</ns0:LogoutRequest>

I'm not sure if params I pass to create_logout_request are correct, but I couldn't find any guide on what they have to be, currently entityid value is the url of my salesforce identity provider.

1

TL;DR: Don't use Single Logout (SLO) in SAML. Terminate your app's local session and that's it.

Full story:

SLO might work under a number of carefully curated assumptions. In practice there are a number of issues with "single logout". Top two problems:

  • Asynchronous nature of the front-channel flavor of SLO. (Salesforce and virtually all other identity or service providers only implement front-channel SLO). In this flow there's no guarantee at the protocol level a service provider OR identity provider will fulfill your SLO request and you have no recourse.

  • "Ownership" of (what is essentially) a shared authentication context in a multi-SP scenario. This article does a good job of outlining some of these concerns.

These and other reasons are why SLO is rarely used and the recommended option for service providers is to manage their own session only without thinking about the IdP.

As to your specific problem, you need to sign your authentication request AND include SessionIndex. This is required by the SAML spec

4.4.4.1 Usage

The requester MUST authenticate itself to the responder and ensure message integrity, either by signing the message or using a binding-specific mechanism.

If the requester is a session participant, it MUST include at least one <SessionIndex> element in the request. (Note that the session participant always receives a SessionIndex attribute in the <saml:AuthnStatement> elements that it receives to initiate the session)

pysaml2's client.py.do_logout(...) shows the steps involved to generate a signed request with a SessionIndex; your question on github might yield more details. Your app will need to extract and store the value of SessionIndex in your app's own session when your app's session is initiated from Salesforce via SAML, then use that when constructing the logout request.

| improve this answer | |
  • Thank you so much for your answer, I do appreciate it. I will try to add session index to logout request, however I'm not sure if I have to sign it, according to SAML core specs, request should be either signed or protected with the protocol (in my case https), also there is a piece of code in pysaml2 do_logout function that signs reuest only if the destination url starts with the "http://" – Pavlo Kovalov Aug 21 '19 at 18:31
  • pysaml2 is violating the spec here because there are two parts: requester MUST authenticate and requester MUST ensure message integrity. https meets the requirements of the latter but not the former, at least not the usual server-side https. Mutual-auth SSL would work but pysaml2 is not verifying that. Salesforce may consume this without a signature (also a spec violation). There's an ongoing thread on Trailblazer Success with similar semantics but no resolution. – identigral Aug 21 '19 at 18:46
  • Adding only session index didn't help, probably I really need the certificate. For now, I came up with another solution. Anyway, huge thanks to you, as there is so little info about salesforce slo on the web – Pavlo Kovalov Aug 22 '19 at 9:53
  • Well, I signed the request but still no result. Maybe I have to setup salesforce somehow so it could decode my request? I have set up Idp certificate in "SAML Service Provider Settings" section, then downloaded it, got private key and cert itself and signed my LogoutRequest with it – Pavlo Kovalov Aug 22 '19 at 12:13
  • Your app as a service provider is represented in SF by an object called connected app.. When you create a connected app and configure it for SAML, there's an option for SLO (from SF to your app) and there's a Verify Request Signature option. This second option when checked allows you to upload your certificate from your public/private keypair. You're signing with your private key, SF is verifying the signature with your public key. If you never set up a connected app, this might be your issue, it's required. – identigral Aug 23 '19 at 2:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.