Logging out fails if some service providers no longer exist

Hello,

Let’s suppose we have three service providers: SP1, SP2 and SP3.

Let’s also pretend that we have opened SAML sessions on all three:
{
“Id”: “SamlSession_60a8cf31-e554-4d15-8e05-a39ec34c7d85”,
“Session”: {
“AssertionConsumerServiceURL”: null,
“LogoutReason”: null,
“SLOPendingResponseState”: null,
“PendingResponseState”: null,
“SSOSessions”: {
“SP1”: {
“PartnerName”: “SP1”,
“NameID”: {
“NameIdentifier”: “66c203e3-c54f-494b-8f79-dc1ea316e776”,
“NameQualifier”: null,
“SPNameQualifier”: null,
“Format”: “urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified”,
“SPProvidedID”: null
},
“SessionIndexes”: {
“_dd078b7d-a28c-4ff2-a56e-da60f9372969”: “_dd078b7d-a28c-4ff2-a56e-da60f9372969”
}
},
“SP2”: {
“PartnerName”: “SP2”,
“NameID”: {
“NameIdentifier”: “66c203e3-c54f-494b-8f79-dc1ea316e776”,
“NameQualifier”: null,
“SPNameQualifier”: null,
“Format”: “urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified”,
“SPProvidedID”: null
},
“SessionIndexes”: {
“_07055138-e365-418b-8ee1-2fa21b084642”: “_07055138-e365-418b-8ee1-2fa21b084642”
}
},
“SP3”: {
“PartnerName”: “SP3”,
“NameID”: {
“NameIdentifier”: “66c203e3-c54f-494b-8f79-dc1ea316e776”,
“NameQualifier”: null,
“SPNameQualifier”: null,
“Format”: “urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified”,
“SPProvidedID”: null
},
“SessionIndexes”: {
“_353ff1ba-1468-4a86-abf8-56f573492d3d”: “_353ff1ba-1468-4a86-abf8-56f573492d3d”
}
}
}
}
}

Now, let’s pretend that the service provider SP2 was removed and is no longer registered as a partner service provider.

Right now, we get a crash (understandably) when the user logs out:
ComponentSpace.SAML2.Exceptions.SAMLConfigurationException: The partner service provider SP2 is not configured.

The crash happens in our identity provider’s SLO endpoint on the SAMLIdentityProvider.SendSLO(Response, null) call:
// POST: Saml/SLO
public async Task SLO()
{
// Receive the SLO request or response.
bool isSpRequest, hasCompleted;
string logoutReason, partnerSp;
SAMLIdentityProvider.ReceiveSLO(
Request,
Response,
out isSpRequest,
out hasCompleted,
out logoutReason,
out partnerSp);

if (isSpRequest)
{
// A request has been received: SLO has been initiated by the service provider.
if (CurrentUser != null)
{
await ActionManager.LogUserLogoutAsync(CurrentUser.Id, null, partnerSp);
}
HttpContext.GetOwinContext().Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
SAMLIdentityProvider.SendSLO(Response, null);
}
else
{
// A response has been received: SLO has been initiated by the identity provider (Connect).
if (hasCompleted)
{
Response.Redirect(“~/”);
}
}

return new EmptyResult();
}


What is the proper way to deal with this situation? Should we simply catch exceptions of type ComponentSpace.SAML2.Exceptions.SAMLConfigurationException around that call? I have the feeling that doing that would break the chain of SLO calls…

Best,
Franz

Hi Franz
SAML logout is a best effort only. There are no guarantees it will complete successfully.
In your example, the flow failed because required configuration information was removed locally.
However, it’s also possible that one of the partner SPs will abort the flow.
Or the user shuts down the browser before SLO completes.
I don’t think it’s worth trying anything too complicated here.
Simply catch the exception and perhaps display a message suggesting the user close the browser to complete the logout.

[quote]
ComponentSpace - 9/7/2017
Hi Franz
SAML logout is a best effort only. There are no guarantees it will complete successfully.
In your example, the flow failed because required configuration information was removed locally.
However, it's also possible that one of the partner SPs will abort the flow.
Or the user shuts down the browser before SLO completes.
I don't think it's worth trying anything too complicated here.
Simply catch the exception and perhaps display a message suggesting the user close the browser to complete the logout.
[/quote]

Thanks for the answer, I guess this is indeed what we'll end up doing.

Franz

You’re welcome.