I have a service provider and I’m implementing single logout and testing it with the ExampleIdentityProvider.
I have two questions.
When I log out of the identity provider and the identity provider does not have a single logout url configured, is it ok to not call _samlServiceProvider.SendSloAsync(); We wanted to use the fact that a single logout url was not configured to tell us that the Identity provider does not want us to log them out when users log out of the service provider system. Is that terrible?
Next question is about SP initiated logout. I’m calling _samlServiceProvider.InitiateSloAsync(); in the middle of a logout method. I’d like the logout method to finish and it just go to the sign out page but as soon as I get a response from the IdP that they received the request the browser wants to go to the SingleLogout url on the SP. I can’t return an empty result from that method because I just get a blank page. I don’t really have a relay state to send and besides, it happens in the middle of the logout method I called originally. Maybe I don’t understand the inner workings of the way microsoft handles these or why the redirect needs to happen. Is there a way to just initiate the single logout and make it more of a fire and forget kind of deal? I kinda don’t care if the IdP sends me back a response. Does the browser need to make all these calls?
Thanks!
Also it’s been a great library to work with!
Typically when the user logs out from the service provider you also want them to be logged out from the identity provider. However, this doesn’t have to be the case. If your business case is that the user stays logged in at the identity provider that’s fine. Just be aware that they’re still logged in and consider if this presents any security risks. In a corporate environment with other security measures in place it may be perfectly valid.
I recommend calling ssoState.CanSloAsync() to determine whether SAML logout is supported. CanSloAsync will return false if no SingleLogoutServiceUrl is configured for the partner IdP.
var ssoState = await _samlServiceProvider.GetStatusAsync();
if (await ssoState.CanSloAsync())
{
// Can initiate SLO.
}
The majority of the SAML protocols are browser based. What this means is that messages sent between the SP and IdP sites are sent via the browser. When you call _samlServiceProvider.InitiateSloAsync(), a 302 redirect HTTP response is returned to the browser. The browser then redirects to the IdP with the SAML logout request encoded as a query string parameter. At this moment, control is now at the IdP site. The IdP logs the user out and sends a SAML logout response to your SP via the browser. This is received at your SAML logout service endpoint where you call _samlServiceProvider.ReceiveSloAsync to receive and process the logout response. Now that the SAML logout flow has completed, your application may redirect the user to the appropriate page. This is demonstrated by the ExampleServiceProvider project we ship. SAML doesn’t support the concept of a fire and forget message.
Thank you for your kind words!
Thanks for the response!
So if the Partner IdP hits our logout endpoint and they’re not configured for SLO (no url specified) control goes back to me. I can’t call _samlServiceProvider.SendSloAsync(); because there’s no URL defined and I may not have a relaystate to redirect to. Returning an empty result from the endpoint doesn’t display anything? Is it up to the idp to handle something like that? Would they be just calling our endpoint in some iframe normally so that it’s ok to return nothing?
Speaking of iframes, in an SP initiated logout, does component space provide some way to get a iframe saml logout url that I can use instead of directly calling _samlServiceProvider.InitiateSloAsync(); within our logout method? I want to make the idp logout in the background and not hold up our logout method. When the IdP responds I don’t want the browser to do anything.
So if the Partner IdP hits our logout endpoint and they're not configured for SLO (no url specified) control goes back to me. I can't call _samlServiceProvider.SendSloAsync(); because there's no URL defined and I may not have a relaystate to redirect to. Returning an empty result from the endpoint doesn't display anything? Is it up to the idp to handle something like that? Would they be just calling our endpoint in some iframe normally so that it's ok to return nothing?
Speaking of iframes, in an SP initiated logout, does component space provide some way to get a iframe saml logout url that I can use instead of directly calling _samlServiceProvider.InitiateSloAsync(); within our logout method? I want to make the idp logout in the background and not hold up our logout method. When the IdP responds I don't want the browser to do anything.
One more thing, if I don't call SendSloAsync, does that barf up the state of the sso? I started to see "The SAML message doesn't contain an InResponseTo attribute" after logging out with the idp project which doesn't have an SLO url configured with the service provider.
So if the Partner IdP hits our logout endpoint and they're not configured for SLO (no url specified) control goes back to me. I can't call _samlServiceProvider.SendSloAsync(); because there's no URL defined and I may not have a relaystate to redirect to. Returning an empty result from the endpoint doesn't display anything? Is it up to the idp to handle something like that? Would they be just calling our endpoint in some iframe normally so that it's ok to return nothing?
Speaking of iframes, in an SP initiated logout, does component space provide some way to get a iframe saml logout url that I can use instead of directly calling _samlServiceProvider.InitiateSloAsync(); within our logout method? I want to make the idp logout in the background and not hold up our logout method. When the IdP responds I don't want the browser to do anything.
If the partner IdP sends a SAML logout request to your logout endpoint, the IdP will be expecting a SAML logout response to be returned. If a logout endpoint hasn't been configured for the IdP this cannot be done. It's much better to negotiate with the IdP whether SAML logout is to be supported. If it is, then your SP should send a logout response to the IdP. If it isn't, the IdP shouldn't send you a SAML logout request. If something goes wrong when calling _samlServiceProvider.SendSloAsync, we recommend you catch the exception, log the error and redirect the user to a generic error page.
We don't directly manipulate iFrames. This is something your application would have to handle. Usually the SLO process is very fast and there shouldn't be any hold up. We recommend logging the user out locally before calling _samlServiceProvider.InitiateSloAsync to create and send a SAML logout request to the IdP. After calling _samlServiceProvider.ReceiceSloAsync to receive and process the SAML logout response from the IdP, the logout process is complete and you can redirect the user to the home page etc.
So if the Partner IdP hits our logout endpoint and they're not configured for SLO (no url specified) control goes back to me. I can't call _samlServiceProvider.SendSloAsync(); because there's no URL defined and I may not have a relaystate to redirect to. Returning an empty result from the endpoint doesn't display anything? Is it up to the idp to handle something like that? Would they be just calling our endpoint in some iframe normally so that it's ok to return nothing?
Speaking of iframes, in an SP initiated logout, does component space provide some way to get a iframe saml logout url that I can use instead of directly calling _samlServiceProvider.InitiateSloAsync(); within our logout method? I want to make the idp logout in the background and not hold up our logout method. When the IdP responds I don't want the browser to do anything.
One more thing, if I don't call SendSloAsync, does that barf up the state of the sso? I started to see "The SAML message doesn't contain an InResponseTo attribute" after logging out with the idp project which doesn't have an SLO url configured with the service provider.[/quote]
If you're receiving a SAML logout request but not sending a SAML logout response that may cause issues.
If you'd like us to take a closer look, please enable SAML trace and send the generated log file as an email attachment to support@componentspace.com and mention your forum post.
https://www.componentspace.com/Forums/7936/Enabling-SAML-Trace
I think we’re just going to force the IdP’s to provide a logout URL if they plan on using SLO
Thanks for all the help!
That’s a good idea.
You’re welcome.
I recommend calling ssoState.CanSloAsync() to determine whether SAML logout is supported. CanSloAsync will return false if no SingleLogoutServiceUrl is configured for the partner IdP.
var ssoState = await _samlServiceProvider.GetStatusAsync();
if (await ssoState.CanSloAsync())
{
// Can initiate SLO.
}
The majority of the SAML protocols are browser based. What this means is that messages sent between the SP and IdP sites are sent via the browser. When you call _samlServiceProvider.InitiateSloAsync(), a 302 redirect HTTP response is returned to the browser. The browser then redirects to the IdP with the SAML logout request encoded as a query string parameter. At this moment, control is now at the IdP site. The IdP logs the user out and sends a SAML logout response to your SP via the browser. This is received at your SAML logout service endpoint where you call _samlServiceProvider.ReceiveSloAsync to receive and process the logout response. Now that the SAML logout flow has completed, your application may redirect the user to the appropriate page. This is demonstrated by the ExampleServiceProvider project we ship. SAML doesn't support the concept of a fire and forget message.
Thank you for your kind words!
Hi ComponentSpace,
I am also trying to initiate logout request at the IDP. I have the above code inside a try catch , everything seems fine at the SP but idp does not get the request. what could be the issue.
Here is my Workflow
1. login is initiated at idp
2. Sp process the respone - login works fine
3. user logouts out at SP and CanSloAsync is true and initiateSLOasync works without exception
Here comes the issue, the idp never gets the request. Idp is web form and slologouturl works when put in browser.
I am also debugging both idp and sp locally and my idp slo never gets stepped into. looking at saml trace there is no sent request
Here is my configuration
public override Task GetPartnerIdentityProviderConfigurationAsync(
string configurationId, string partnerName)
{
var logoutLink = getslolink();
var partnerIdentityProviderConfiguration = new PartnerIdentityProviderConfiguration
{
Name = partnerName.TrimEnd('/'),
Description = "Example Identity Provider",
PartnerCertificates = new List
{
new Certificate {FileName = "idp.cer"}
},
SingleLogoutServiceUrl = logoutlink,
SingleLogoutServiceBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
WantAssertionOrResponseSigned = true,
DisableDestinationCheck = true,
DisableRecipientCheck = true,
DisableAudienceRestrictionCheck = true
};
return Task.FromResult(partnerIdentityProviderConfiguration);
}
There is no error - every other thing works. what am i missing
Is the method where you’re calling ISamlServiceProvider.InitiateSloAsync returning an EmptyResult?
For example:
public async Task InitiateSingleLogout(string returnUrl = null)
{
// Request logout at the identity provider.
await _samlServiceProvider.InitiateSloAsync(relayState: returnUrl);
return new EmptyResult();
}
What page do you end up on in the browser? This should provide a clue as to what’s going wrong.
For example:
public async Task InitiateSingleLogout(string returnUrl = null)
{
// Request logout at the identity provider.
await _samlServiceProvider.InitiateSloAsync(relayState: returnUrl);
return new EmptyResult();
}
What page do you end up on in the browser? This should provide a clue as to what's going wrong.
No. Here is my method
public async void SendLogoutRequestToIdp()
{
try
{
var ssoState = await SamlServiceProvider.GetStatusAsync();
if (await ssoState.CanSloAsync())
{
await SamlServiceProvider.InitiateSloAsync();
}
}
catch (Exception e)
{
//log error
}
}
This method is called by the sp's logout method.
Also I will like to point out that the Idp Servicelogout method which will be receiving the request is not of type Task
What page do you end up on in the browser?
The call to InitiateSloAsync will return a 302 redirect HTTP response to the browser. The URL will be the IdP’s logout service with the logout request encoded as a SAMLRequest query string parameter.
I suggest using the browser developer tools (F12) to capture the network traffic to see what’s happening.
The call to InitiateSloAsync will return a 302 redirect HTTP response to the browser. The URL will be the IdP's logout service with the logout request encoded as a SAMLRequest query string parameter.
I suggest using the browser developer tools (F12) to capture the network traffic to see what's happening.
I am using the dev tool and also saml trace nothing is sent.
I will like to point out that i have 2 applications one in .Net Core and the other in .Net
instead of using your .Net Core idp example , i am trying to reuse your idp web form project in order to support the 2 applications.
Is this possible?
Does I have to use the .Net Core Idp Example Project for my .Net Core application?
I am new to .Net Core pls bear with me. Any suggestion can help
There are no issues with an ASP.NET Core SP application interoperating with an ASP.NET IdP application.
Please send the SAML log file to support@componentspace.com mentioning your forum post.
Also, save the browser developer tools network traffic to an HAR file and include that in the email.
Please send the SAML log file to support@componentspace.com mentioning your forum post.
Also, save the browser developer tools network traffic to an HAR file and include that in the email.
Thank you again for your resoponse. I have send the HAR file saml tracer log .
Thanks. I’ll reply to your email.