Cannot SLO from SP

Hello, I am trying to perform an SLO for an SP site with TWO IdP’s. Right now, the person gets logged out but when they click log in on the SP site it just logs them in. My understanding is they should be required to log back in on the IdP first. So clearly something is not working.

C# Code for activating SLO:

		public ActionResult LogOff()
		{
            try
            {
                var user = userManager.FindByName(User.Identity.Name);
                if (!string.IsNullOrWhiteSpace(user.ExternalId))
                {
                    Log.Info("Logging out for user {user} with external id {external}", user.UserName, user.ExternalId);
                    if (SAMLServiceProvider.CanSLO())
                    {
                        Log.Info("I can SLO.");
                        // Request logout at the identity provider.
                        SAMLServiceProvider.InitiateSLO(Response, $"User {user.UserName} logging out.", null);
                        Log.Info("SLO Complete");
                        //return new EmptyResult();
                    }
                }
                Session.Clear();
                Session.Abandon();

                Response.Cookies["CartToken"].Value = string.Empty;
                Response.Cookies["CartToken"].Expires = DateTime.Now.AddDays(-1);

                AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
                return RedirectToAction("Index", "Home");
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error trying to log out.");
                return RedirectToAction("Index", "Home").WithError("Problem logging out. Please contact support.");
            }
		}

SAML config:

<?xml version="1.0"?>
<SAMLConfiguration xmlns="urn:componentspace:SAML:2.0:configuration">
  <ServiceProvider Name="MIR_DeereTBS_SP_UAT"
      AssertionConsumerServiceUrl="~/SAML/AssertionConsumerService" />

  <PartnerIdentityProviders>
    <PartnerIdentityProvider Name="http://www.okta.com/foo" 
                             PartnerCertificateFile="Certificates\Contoso_IdP.demo.cer" 
                             SingleSignOnServiceUrl="SSO URL"
                             SingleLogoutServiceUrl="SLO URLl" />
    <PartnerIdentityProvider Name="http://www.okta.com/bar" 
                             PartnerCertificateFile="Certificates\contoso_idp.internal.demo.cer"
                             SingleSignOnServiceUrl="SSO URL"
                             SingleLogoutServiceUrl="SLO URL" />
  </PartnerIdentityProviders>
</SAMLConfiguration>

SAMLServiceProvider.InitiateSLO initiates SLO to one IdP only. You would need to call this API for each IdP you wish to logout. This must be done sequentially.

Regarding your code, our recommendation is to perform any local logout first before calling SAMLServiceProvider.InitiateSLO. This ensure the user is logged out locally at least in case there’s some sort of error in the SAML SLO flow.

SAMLServiceProvider.InitiateSLO creates and sends a SAML logout request to the IdP. This is done by returning an HTTP Redirect 302 response to the browser . You shouldn’t write to the HTTP response after making this call as it could override the 302 response. Typically this means returning a new EmptyResult() immediately after the call. Your code has this commented out and the return RedirectToAction will override the sending of the SAML logout request.

SAMLServiceProvider.InitiateSLO includes an overload that takes a partnerIdP parameter that specifies which IdP to initiate SLO to. If this isn’t specified, SLO is initiated to the first IdP with an SSO session.

The ExampleServiceProvider project’s SAML/SLOService.aspx page includes the following code to handle the SLO flow.

// Receive the single logout request or response.
// If a request is received then single logout is being initiated by the identity provider.
// If a response is received then this is in response to single logout having been initiated by the service provider.
bool isRequest = false;
string logoutReason = null;
string partnerIdP = null;
string relayState = null;

SAMLServiceProvider.ReceiveSLO(Request, out isRequest, out logoutReason, out partnerIdP, out relayState);

if (isRequest)
{
    // Logout locally.
    FormsAuthentication.SignOut();

    // Respond to the IdP-initiated SLO request indicating successful logout.
    SAMLServiceProvider.SendSLO(Response, null);
}
else
{
    // SP-initiated SLO has completed.
    Response.Redirect("~/");
}

This handles SLO for a single IdP.

To handle all IdPs, this could be modified as follows.

// Receive the single logout request or response.
// If a request is received then single logout is being initiated by the identity provider.
// If a response is received then this is in response to single logout having been initiated by the service provider.
bool isRequest = false;
string logoutReason = null;
string partnerIdP = null;
string relayState = null;

SAMLServiceProvider.ReceiveSLO(Request, out isRequest, out logoutReason, out partnerIdP, out relayState);

if (isRequest)
{
    // Logout locally.
    FormsAuthentication.SignOut();

    // Respond to the IdP-initiated SLO request indicating successful logout.
    SAMLServiceProvider.SendSLO(Response, null);
}
else
{
    // SP-initiated SLO has completed.
    // Check if there's another IdP to logout.
    // If there is, initiate SLO to it.
    // Otherwise, redirect to the home page.
    if (SAMLServiceProvider.CanSLO())
    {
        SAMLServiceProvider.InitiateSLO(Response, null, null);
    }
    else
    {
        Response.Redirect("~/");
    }
}

Once SP-initiated SLO completes for one IdP, it calls SAMLServiceProvider.CanSLO() to see if there’s another IdP to initiate SLO to. If there is, it calls SAMLServiceProvider.InitiateSLO.