0

我正在基于 Thinktecture 代码实现我自己的身份提供者。这是 Azure ACS 在使用单点注销功能时的一种奇怪行为,它对于 google/live 和我自己的身份提供者有所不同。

退出 URL(领域实际上与站点名称相同):

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

这是注销的伪代码:

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

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

这是示例流程(我正在使用隐私浏览和 Fiddler 来查看所有内容):

1)我正在使用谷歌帐户登录我的应用程序。

2)单击注销,结果我在 ACS 上获得一个带有此代码的页面:

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>

结果:我从我的应用程序和谷歌中注销。

3)登录到我的身份提供者,单击注销,重定向到 ACS 上与上一步相同的 URL,但现在我得到 302 结果并重定向到

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

结果:我已从我的应用程序和身份提供者中注销。

4)再次尝试使用google,输入凭据成功登录,但如果失败则注销。我已从应用程序中注销,但未从谷歌登录。而且我还看到我没有使用 iframe 获取页面,而是 ACS 再次尝试将我重定向到

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

(然后回到 mysite.accesscontrol.windows.net 最后回到我的应用程序)

两个主要问题:

  1. 为什么调用 ACS 注销会给我 iframe 页面,其中包含用于 google/live 的额外 wa=wsignoutcleanup1.0 但 302 重定向到我的身份提供者,我可能会错过 FederationMetadata.xml 中的某些内容吗?
  2. 看起来第 3 步之后的 ACS 不明白我已成功从身份提供商注销,并且从此刻开始一次又一次地尝试这样做,如何告诉他们停止它?
4

1 回答 1

3

这是你必须做的。

首先,在使用联合身份验证时,请始终使用 HTTPS!有时协议协商会因为它是纯 HTTP 而失败。有时浏览器会阻止非安全流量,这对于注销过程至关重要。所以,请始终使用 HTTPS!

现在,要实现单点注销的形式,您需要做更多的工作。

您的登出网址:

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

不要将其用作构造 SignOutRequestMessage 的参数。直接用它return Redirect(signOutUrl)

您必须在两个主要地方实施注销!

首先是您的一般注销操作方法(假设您使用的是 MVC)类似于您已经拥有的东西,但有一个重要的变化:

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);

请注意,这里我使用带参数的重载string将结果重定向到 ACS SSO 位置!

现在这个ACS SSO位置将生成上面提到的带有 JS 和几个iframe元素的 HTML 页面。其中之一将类似于:

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

现在,该特定位置http://localhost/Administration.Frontend.Web/?wa=wsignoutcleanup1.0是您的代码中实现 SSO 的第二个位置。此请求不得重定向到登录页面,而是必须正确处理并返回 200 或 301 响应(这反过来将返回 200!)!为简单起见,我将仅粘贴此处使用的代码:

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

仅在请求操作时才使用true调用SignOut(true)重载,这一点非常重要。而不是当您对用户进行一般注销时。wsignoutcleanup

请尝试所有提到的更改,如果它解决了您的问题,请告诉我!

于 2013-05-15T10:53:29.823 回答