终于找到使用 OAuth 和 SAML 将 Windows Live 与 SharePoint 2010 建立联盟的有用方法
原文发布于 2012 年 3 月 1 日(星期四)
之前,许多人跟我谈论过有关将 SharePoint 与 Windows Live 结成联盟的事情。表面上看起来这似乎是一个不错的主意,Windows Live 拥有数百万用户,每位用户均使用各自的电子邮件地址进行登录,我们通常将电子邮件地址用作标识声明,这是一个庞大的可伸缩服务,我们提供了有关如何操作的各种说明 – 直接或通过 ACS(访问控制服务)。那么,为什么在将其与 SharePoint 结合使用时我怨声载道呢?如果您之前尝试过这么做,您就会知道,在与 Windows Live 建立联盟时,您永远不会获取以声明形式返回的用户电子邮件地址。您得到的是一个称为 PUID 的特殊 Windows Live 标识符。就我所知,“PUID”应该代表“Practically GUID”(实际上的 GUID),因为这基本上就是它字面上所透露的含义以及它的用途。
例如,如果您确实与 Windows Live 建立联盟,那么您如何将某个人添加到网站呢?您必须先获取其 PUID,然后将该 PUID 添加到 SharePoint 组或权限级别。您认识的人当中真的有人知道其 PUID 是什么吗(如果您就是这样一个人,是时候在空闲时间找点其他别的事情做了)。即使您奇迹般地碰巧知道您的 PUID,在您尝试为用户授予不同网站集的访问权限时,您觉得它能有多大作用呢?您真的认为会有其他任何人将您从 PUID 队列(或人员选取器,视情况而定)中挑选出来?当然不会!这正是我感到挫败的原因所在。
实际上,我本来觉得我们可以在此试一试采用 ACS 的更加理想化的解决方案。在提供与多个身份提供程序(如 Windows Live、Google、Yahoo 和 Facebook)的现成挂钩方面,ACS 真的很棒。就 Facebook 而言,它们甚至对其实现了神奇的功能,实际上是采用 OAuth 进行身份验证,然后返回一组 SAML 声明。实在是太酷了!那么,为什么它们不对 Windows Live 也这样做呢?Windows Live 现在支持 OAuth,所以很可能有机会最终发生一些重要的事情。然而,虽然希望如此,但 ACS 人士还没有过来施以援手。这就是本序言的要点 – 我最终决定由我自己来写序言,这就是本文的观点。
那么,我们为什么要关心 OAuth 呢?与您直接和 Windows Live 建立联盟时获取的 PUID 不同,Windows Live 中的 OAuth 支持允许您获取有关用户的更多信息,包括其电子邮件地址。因此,此处的解决计划基本上如下所述:
- 使用 Windows Identity Foundation (WIF) 编写自定义身份提供程序。
- 当某人被重定向到 STS 时,如果他们尚未进行身份验证,则我们会将其再次重定向到 Windows Live。您必须使用 Windows Live 创建“一个应用程序”才能执行此操作,稍后我将对此进行详细说明。
- 通过身份验证后,他们会重定向回自定义 STS。当他们返回时,查询字符串包括一个登录令牌;该登录令牌可换为访问令牌。
- 然后,STS 会使用该登录代码向 Windows Live 发出另一个请求,要求提供访问令牌。
- 在获得访问令牌后,它会使用该访问令牌向 Windows Live 进行最后一次请求,要求提供一些有关用户的基本信息(稍后我会对返回的内容进行详细说明)。
- 从 Windows Live 获取用户信息后,我们使用自定义 STS 为用户创建一组 SAML 声明并使用用户信息进行填充。然后,重定向回要求我们首先进行身份验证的任一应用程序,让它使用 SAML 令牌进行它想要的操作。在该特定情况下,我使用标准 ASP.NET 应用程序以及 SharePoint 2010 Web 应用程序测试了我的 STS。
虽然本文随附了所有源代码,但仍需要进行一些配置,您必须使用应用程序 ID 以及从 Windows Live 获取的密钥重新编译该应用程序。但除了执行复制与粘贴外,您确实不需要再编写任何代码。现在,让我带领您完成所需的任何步骤。
创建令牌签名证书
您需要创建一个要用于签署 SAML 令牌的证书。用于签署证书的证书没有什么特别之处,您只需要确保您具有其私钥即可。就我而言,我在域中安装了证书服务,因此,我只需打开 IIS 管理器并选择用来创建域证书的选项即可。我根据向导中的说明进行操作,很快我便用私钥完成了一个新证书。对于这个项目,我创建了一个名为 livevbtoys 的证书。
正如我将在下一部分中介绍的那样,当请求最初进入 STS 时,用户是匿名用户。为了使用该证书来签署 SAML 令牌,我们需要授予 IIS 进程访问该证书私钥的权限。当匿名请求进入 IIS 时,进程标识是“网络服务”。要授予其访问密钥的权限,您需要执行以下操作:
- 启动 MMC
- 添加证书管理单元。为本地计算机选择计算机存储。
- 打开“个人证书”存储,找到为了签署 SAML 令牌而创建的证书。如果您用的是我刚刚介绍的创建方法,则默认情况下,证书已在其中。如果您用的是其他创建方法,则可能需要将其添加到该存储中。
- 右键单击证书并选择“管理私钥”选项。
- 在拥有密钥权限的用户列表中,添加“网络服务”并授予它读取权限。
请注意,如果不正确执行此操作,在您尝试运行应用程序时,您可能收到一条错误消息,告诉您“密钥集不存在”或类似信息。这意味着 IIS 进程对私钥没有足够的权限,因此无法使用密钥来签署 SAML 令牌。
安装应用程序和所需程序集
从这一意义上说,安装应用程序只意味着在 IIS 中创建 ASP.NET 应用程序、复制位以及确保安装最新版本的 WIF。配置完成并在一台服务器上运行后,您可能希望添加一台或更多台服务器,以确保您具有容错解决方案。但我只介绍在一台服务器上的配置过程。
我不会详细介绍如何在 IIS 中创建 ASP.NET 应用程序。您可以采用 Visual Studio、IIS 管理器等工具。
注意: 如果您使用的是此处提供的代码并在 Visual Studio 中打开项目,则它会提示主机或网站不存在。那是因为它使用的是我的服务器的名称。修复此问题最简单的方法就是手动编辑 WindowsLiveOauthSts.sln 文件,将其中的 https 值更改为您环境中实际存在的值。
实际创建后,确保您执行以下操作:
- 在 IIS 管理器中,将 PassiveSTS.aspx 添加为 STS 网站的默认文档。
- 在 IIS 中,更改应用程序的身份验证设置,以便禁用除匿名身份验证之外的所有身份验证类型。
- STS 需要在 SSL 上运行,因此您需要为其获取相应的证书,并确保更新其中使用自定义 STS 应用程序的 IIS 虚拟服务器上的绑定。
- 确保将令牌签名证书的指纹置于您的信赖方 web.config 的 trustedIssuers 部分的 add 元素的 thumbprint 属性中(如果没有使用 SharePoint 进行测试)。如果您在 Visual Studio 中使用“添加 STS 引用”向导,则它会为您执行此操作。
这应该是 IIS 中所需的全部配置。
更新和生成自定义 STS 项目
随附的 zip 文件包含一个名为 WindowsLiveOauthSts 的 Visual Studio 2010 项目。配置完 IIS 并按照上述说明更新 WindowsLiveOauthSts.sln 文件后,您应该能够在 Visual Studio 中成功打开项目。您需要做的第一件事就是更新 PassiveSTS.aspx.cs 类中的 CLIENT_ID 和 CLIENT_SECRET 常量。在新建 Windows Live 应用程序时将会获取这些变量。我不打算分步介绍此操作(因为 Windows Live 中会有人帮助您),我只指出您可在其中创建 Windows Live 应用程序的位置:https://manage.dev.live.com/Applications/Index?wa=wsignin1.0(该链接可能指向英文页面)。此外,在创建应用程序时,请确保将重定向域设置为承载自定义 STS 的位置,例如 https://myserver.foo.com。
现在您已拥有 ID 和密钥,还需要在应用程序中进行以下更新:
- 更新 PassiveSTS.aspx.cs 类中的 CLIENT_ID 和 CLIENT_SECRET 常量。
- 在 web.config 文件中,更新 appSettings 部分中的 SigningCertificateName。请注意,您不必更改 IssuerName 设置,但如果您希望更改,显然是可以的。
- 更新 STS 项目中 FederationMetadata.xml 文档的令牌签名证书。选择要使用的证书后,您可以使用本文随附的 test.exe 应用程序为证书获取字符串值。需要复制该值以替换 federationmetadata.xml 中的两个 X509Certificate 元素值。
还有另一件事需要在此处指出,那就是,在 CustomSecurityTokenService.cs 文件中,您可以选择将名为 enableAppliesToValidation 的变量设置为 true,然后提供可使用此自定义 STS 的 URL 列表。就我而言,我选择了不以任何方式对其进行限制,因此变量为 false。如果您希望锁定自定义 STS,则应立即进行更改。完成全部更改后,即可重新编译应用程序,一切准备就绪。
还有一个地方需要注意 – 我还随附了在构建应用程序时用于测试的示例 ASP.NET 应用程序。它位于名为 LiveRP 的项目中。我不准备在这里进行详细说明;我只想说如果您要尝试进行测试,不妨使用该示例应用程序。只是别忘了按如上所述更改 STS 令牌签名证书的指纹。
SharePoint 配置
此时,一切都配置完毕,可以用于自定义 STS 了。剩下要做的唯一一件事实际上是在 SharePoint 中新建 SPTrustedIdentityToken 颁发者和配置新的或现有 Web 应用程序来使用它。您应当知道有关配置 SPTrustedIdentityTokenIssuer 的一些事宜;我将为您提供创建我自己的颁发者时使用的 PowerShell 并加以说明:
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("c:\livevbtoys.cer")
New-SPTrustedRootAuthority -Name "SPS Live Token Signing Certificate" -Certificate $cert
$map = New-SPClaimTypeMapping -IncomingClaimType "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" -IncomingClaimTypeDisplayName "EmailAddress" -SameAsIncoming
$map2 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/id" -IncomingClaimTypeDisplayName "WindowsLiveID" -SameAsIncoming
$map3 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/full_name" -IncomingClaimTypeDisplayName "FullName" -SameAsIncoming
$map4 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/first_name" -IncomingClaimTypeDisplayName "FirstName" -SameAsIncoming
$map5 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/last_name" -IncomingClaimTypeDisplayName "LastName" -SameAsIncoming
$map6 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/link" -IncomingClaimTypeDisplayName "Link" -SameAsIncoming
$map7 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/gender" -IncomingClaimTypeDisplayName "Gender" -SameAsIncoming
$map8 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/locale" -IncomingClaimTypeDisplayName "Locale" -SameAsIncoming
$map9 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/updated_time" -IncomingClaimTypeDisplayName "WindowsLiveLastUpdatedTime" -SameAsIncoming
$map10 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/account" -IncomingClaimTypeDisplayName "AccountName" -SameAsIncoming
$map11 = New-SPClaimTypeMapping -IncomingClaimType "https://blogs.technet.com/b/speschka/claims/accesstoken" -IncomingClaimTypeDisplayName "WindowsLiveAccessToken" -SameAsIncoming
$realm = "https://spslive.vbtoys.com/_trust/"
$ap = New-SPTrustedIdentityTokenIssuer -Name "SpsLive" -Description "Window Live oAuth Identity Provider for SAML" -realm $realm -ImportTrustCertificate $cert -ClaimsMappings $map,$map2,$map3,$map4,$map5,$map6,$map7,$map8,$map9,$map10,$map11 -SignInUrl "https://spr200.vbtoys.com/WindowsLiveOauthSts/PassiveSTS.aspx" -IdentifierClaim "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
下面是一些值得注意的事项:
- 正如我上面所述,我创建了一个名为 livevbtoys.cer 的证书以用于签署令牌,因此我将其添加到我的 SPTrustedRootAuthority 列表中,然后将它与我的令牌颁发者关联。
- 我为自定义 STS 返回的所有声明创建了声明映射。显而易见,这明显多于且优于 您直接与 Windows Live 建立联盟时所获取的声明。另一件需要注意的事情是,在此处我以声明的形式随附了从 Windows Live 获取的访问令牌。虽然该令牌适用于 Facebook,但是我尚未进行测试,因此不太确定 Windows Live 是否允许您重用它。但这可能会成为以后文章的主题。
- $realm 值非常重要。它必须指向 Web 应用程序的根网站,且包括 /_trust/ 目录。如果操作不当,当您在身份验证后再次进行重定向时,会从 SharePoint 获得 500 错误。
- 创建令牌颁发者时的 –SignInUrl 参数是指向自定义 STS 的 PassiveSTS.aspx 页面的绝对 URL。
差不多就是这样了 – 设置完后,您仍然使用现成的人员选取器和声明提供程序,因此正如您可以想到的那样,您不具有任何查找功能。您授予用户访问其各自用于登录 Windows Live 的电子邮件地址的权限。实际上,您可以扩展此示例,还可以使用 Azure 声明提供程序,有关该提供程序的信息,请访问我的博客:https://blogs.msdn.com/b/sharepoint_chs/archive/2012/03/07/the-azure-custom-claim-provider-for-sharepoint-project-part-1.aspx。这意味着您可以使用此 STS 向 Windows Live 进行身份验证,并获得一些真正的 SAML 声明,然后使用 Azure 自定义声明提供程序项目将这些经过身份验证的用户添加到您的 Azure 目录存储和人员选取器中以供选择。
一图胜万言,下面就是您首次登录 SharePoint 网站和向 Windows Live 进行身份验证的情形:
当您首次登录时,它会询问您是否要与自定义 STS 应用程序分享您的信息。不必顾虑什么 – 这只是标准 OAuth 权限。所下图所示;注意,这里显示的是我在 STS 中要求的数据 – 您可以根据需要要求一组完全不同的数据。您只需要查看 Window Live OAuth SDK 以确定要更改的内容以及如何更改:
在接受后,您会重定向回 SharePoint 网站。在此示例中,我使用的是我在以下博客中介绍的 SharePoint 声明 Web 部件:https://blogs.technet.com/b/speschka/archive/2010/02/13/figuring-out-what-claims-you-have-in-sharepoint-2010.aspx(该链接可能指向英文页面)。您可以看到我通过 OAuth 从 Windows Live 获取的所有声明(多亏有了自定义 STS,现在这些声明的形式为 SAML 声明),以及我使用为该项目创建的 Windows Live 电子邮件地址登录(从右上角的登录控件)这一事实:
这是一篇本地化的博客文章。请访问 Finally A USEFUL Way to Federate With Windows Live and SharePoint 2010 Using OAuth and SAML 以查看原文