0
votes

I'm implementing my own identity provider based on Thinktecture code. Here is a strange behaviour of Azure ACS while using a single sign-out feature, it differ for google/live and for my own identity provider.

URL for sign-out (realm is really same as a site name):

mysite.accesscontrol.windows.net/v2/wsfederation?wa=wsignout1.0&wreply=http%3a%2f%2flocalhost%2fAdministration.Frontend.Web%2f&wtrealm=http%3a%2f%2flocalhost%2fAdministration.Frontend.Web%2f

Here is a pseudo-code for logout:

//clear FedAuth cookies
FormsAuthentication.SignOut();
FederatedAuthentication.WSFederationAuthenticationModule.SignOut(true);

//call Single SignOut
var signoutRequestMessage = new SignOutRequestMessage(new Uri(signOutUrl));
return Redirect(signoutRequestMessage.WriteQueryString());

Here is sample flow (i'm using private browsing plus Fiddler to see everything):

1) I'm logging into my application with google account.

2) click a logout, in result i get a page on ACS with a this code:

function on_completion() 
  {window.location = 'http://localhost/Administration.Frontend.Web/';}

<iframe src="https://www.google.com/accounts/Logout" style="visibility: hidden"">/iframe>
<iframe src="http://localhost/Administration.Frontend.Web/?wa=wsignoutcleanup1.0" style="visibility: hidden"></iframe>

Result: i'm logged out from my application and google.

3) Log to my identity provider, click logout, redirected to same URL on ACS as on previous step but now i get 302 result with redirecting to

https://localhost/IdentityProvider/issue/wsfed?wa=wsignout1.0&amp;wreply=https%3a%2f%2fmysite.accesscontrol.windows.net%2fv2%2fwsfederation%3fredirectUrl%3dhttp%3a%2f%2flocalhost%2fAdministration.Frontend.Web%2f

Result: i'm logged out from my application and my identity provider.

4) try to use google again, sucessfully login by entering credential, but logout if failed. I'm logged out from application but not logged from google. And also i see that i don't get page with iframe but instead ACS again try to redirect me to

https://localhost/IdentityProvider/issue/wsfed?wa=wsignout1.0 

(and then back to mysite.accesscontrol.windows.net and finally to my application)

Two main question:

  1. Why calling ACS logout give me iframe page with additional wa=wsignoutcleanup1.0 for google/live but 302 redirect to my identity provider, may be i miss something in FederationMetadata.xml?
  2. It looks like ACS after step 3 don't understand that i successfully logged out from my identity provider and from this moment try to do it again and again, how to tell them to stop it?
1
could you provide the ACS page (just path, after .accesscontrol.windows.net/???) which you are being redirected and which acts ambiguous - the one that first renders some JS + iframes, but next only renders 302 responses.astaykov
also, are you using ACS hosted realm discovery login page, or your own login page? I assume it is the ACS hosted one. Please move to self hosted login page and try again.astaykov
The answers provided here stackoverflow.com/questions/14932241/… gives more precise informationFrode Nilsen

1 Answers

3
votes

Here is what you have to do.

First of all, when working with federated authentication always use HTTPS! Sometime protocol negotiations will fail just because it is plain HTTP. Sometimes browsers will block non-secure traffic, which is crucial for the sign-out process. So, always use HTTPS!

Now, to implement the form of single sign out you want you have do some more work.

Your URL for sign-out:

mysite.accesscontrol.windows.net/v2/wsfederation?wa=wsignout1.0&wreply=http%3a%2f%2flocalhost%2fAdministration.Frontend.Web%2f&wtrealm=http%3a%2f%2flocalhost%2fAdministration.Frontend.Web%2f

Do not use it as a parameter to construct SignOutRequestMessage. Use it to directly return Redirect(signOutUrl)!

You have to implement sign-out in two major places!

First place is your general logOff action method (given you are using MVC) Something similar to what you already have but with an important change:

FormsAuthentication.SignOut();
var signoutProtocolLocation = "https://[your_acs_namespace].accesscontrol.windows.net:443/v2/wsfederation?wa=wsignout1.0&wtrealm=[realm]&wreply=[reply]";
FederatedAuthentication.WSFederationAuthenticationModule.SignOut(signoutProtocolLocation);

Note that here I use the overload with string paramer` to redirect result to ACS SSO location!

Now that very ACS SSO location will generate the above mentioned HTML page with JS and couple of iframe elements. One of them will be something like:

<iframe src="http://localhost/Administration.Frontend.Web/?wa=wsignoutcleanup1.0" style="visibility: hidden"></iframe>

Now that particular location http://localhost/Administration.Frontend.Web/?wa=wsignoutcleanup1.0 is the second place in your code where you have implement the SSO. This request must not redirect to a login page, but must instead process correctly and return 200 or 301 response (which in turn will return 200!)! For the sake of simplicity I will only paste the code used here:

 if(Request.QueryString.AllKeys.Contains("wa")
                && Request.QueryString["wa"].Equals("wsignoutcleanup1.0"))
            {
                FederatedAuthentication.WSFederationAuthenticationModule.SignOut(true);
                return RedirectToAction("Index");
            }

It is really important that you only call the SignOut(true) overload with true when it is request for wsignoutcleanup action. And not when you do general log-off of users.

Please try all mentioned changes and let me know if it solves your issue!