65.9K
CodeProject 正在变化。 阅读更多。
Home

了解 Windows Identity Foundation (WIF) 4.5

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.99/5 (65投票s)

2012 年 12 月 6 日

CPOL

33分钟阅读

viewsIcon

246795

解释了声明式架构、支持的协议和 WIF。

目录

首先

如果您正在寻找一篇展示大量代码并深入分析新 WIF 4.5 API 的文章,那么您在这里找不到您需要的东西。

我在这篇文章中的目的是解释“为什么”和“是什么”,而不是“怎么做”。一旦您明白了这些,那么“怎么做”就会变得非常简单。本文不假设您预先了解联合、声明和 WIF 的主题,因此适合初学者。然而,我认为中级水平的读者也会从中受益。如果您是超级专家,那么请联系我,帮助我完成我目前正在进行的项目。

到底是什么问题?

身份验证(和授权)是大多数应用程序一直面临的挑战。这些应用程序面临的挑战是相同的:身份验证逻辑会侵入应用程序代码并与之耦合;身份验证要求的任何更改都会导致应用程序本身发生更改。

例如,假设您的用户存储是 SQL Server,而新的业务要求是在用户列表中添加一个现有的基于 Oracle 的用户存储,或者您想混合使用您的身份验证,同时支持自定义用户存储(SQL Server 或 Oracle)和 Active Directory 用户存储。那么社交媒体呢?如今,应用程序通过 Google 和 Facebook 等服务进行身份验证越来越普遍。

这里有另一个棘手的情况:假设您过去要求用户输入用户名/密码组合进行登录。现在,基于某些需求,您希望他们还提供附加信息,例如一次性代码。这肯定会导致登录页面的 UI 更改以及代码更改。

在所有这些情况下,您的代码都必须有所更改。当然,拥有良好的架构并妥善分离关注点将简化更改。但是,关键在于您仍然需要管理此身份验证逻辑,而不是专注于应用程序的业务方面。

声明式身份验证是一种可以解决此问题的架构。

声明式身份验证

声明式架构允许您将身份验证逻辑委托给另一个实体。这个实体是一个“某个”层,它抽象了所有与身份验证相关的编码,并为您的应用程序提供它所需的东西:用户是否已通过身份验证,以及关于用户的某些信息(称为声明或断言),这些信息使您的应用程序能够做出授权决策。

声明式架构定义了以下参与者:

  • 主体:需要进行身份验证的实体。它可以是想要登录到您的应用程序的用户,也可以是想要访问 Web 服务的应用程序代码片段。
  • 信赖方 (RP):需要委托身份验证逻辑的应用程序(如果主体是用户)或 Web 服务(如果主体是应用程序代码)。
  • 身份提供者 (IP):实际拥有身份验证逻辑的实体(前面提到的“某个”层)。IP 会与用户存储进行适当的通信并执行实际的身份验证。
  • 声明:当 IP 成功完成身份验证后,它会向 RP 返回一组声明。声明是关于已通过身份验证的实体的陈述——例如出生日期、部门、角色等——这些信息使 RP 能够做出授权决策。
  • 令牌:声明在令牌中传输。虽然令牌可以是用户名/密码组合,甚至是像 OAuth 2.0 中的持有者令牌这样的简单字符串;在此上下文中,令牌可以是基于 XML 的(如 SAML 令牌)或基于二进制的(如 X.509 证书)。

除了上述定义之外,WS-Federation 和 WS-Trust 协议还定义了另一个术语,称为安全令牌服务 (STS)。STS 是由 IP 公开的 Web 服务,它提供身份验证服务。

在声明式流开始之前,RP 和 IP 需要发布它们的策略。抽象地说,策略是由一个实体发布的契约,它规定了在建立通信之前其他实体必须遵守的条款和条件。

在此上下文中,IP 发布策略会指定支持的协议和安全要求以及支持的声明类型。类似地,RP 发布策略会指定其自身的协议、安全和声明要求,以及它信任的用于委托身份验证的 IP 列表。

本文的其余部分将讨论 WS-Federation(及相关的 WS 标准)及其在 WIF 中的实现,同时我也会简要讨论 SAML 2.0。

WS-* 狂热

对某些人来说,WS-* 标准是应该避免的。它们往往让开发人员觉得过于复杂。确实很复杂。然而,随着开发人员库的出现和不断增强,大多数时候处理 WS-* 标准只不过是配置调整。当然,如果您真的想理解架构,您总是需要了解幕后发生的事情。

本节将简要讨论一些与 WS-Federation 相关的核心 WS-* 标准。

WS-Security

WS-Security 是一个 SOAP 扩展,它为 SOAP 消息添加了身份验证/授权、消息保护和消息完整性。

  • 身份验证/授权:身份验证使用安全令牌实现,而安全令牌内部携带的声明有助于授权。虽然可以扩展,但您通常会看到的令牌类型有用户名、二进制和基于 XML 的令牌。
    • 用户名令牌:这些是在 SOAP 头中发送的旧式用户名/密码组合。可以通过哈希密码或应用数字签名来实现身份验证。
    • 二进制令牌:这些通常有两种形式:X.509 证书和 Kerberos 票证。
      • X.509 证书:X.509 证书是公钥/私钥对的公钥容器。显然,由于它包含公钥,因此它本身不能用于身份验证。证书是用发送方的私钥部分签名的。接收方使用公钥来验证签名。由于私钥对发送方是唯一的,签名验证证明了身份。
      • Kerberos 票证:如果已存在 Kerberos 基础结构,WS-Security 会将 Kerberos 票证识别为有效的安全令牌类型。
    • 基于 XML 的令牌:XML 令牌作为 WS-Security 的附加规范发布。XML 令牌包含有关发送方的声明集。与 X.509 证书令牌类似,XML 令牌必须附带发送方生成的签名,以便接收方可以验证其身份。可能是最占主导地位的 XML 令牌形式是 SAML 令牌。
  • 消息保护:虽然在传输层使用 SSL 建立消息保护,但在消息级别,这是通过 XML 签名完成的。根据配置,WS-Security 使用对称共享密钥或非对称公钥/私钥对来加密所需的消息内容。在对称方法中,必须在通信之前安全地交换共享密钥。在非对称方法中,发送方使用接收方的公钥加密(所需)消息内容,接收方使用其私钥解密。然而,在大多数情况下,由于非对称方法的计算成本很高,因此通常使用两者的组合。在这种混合方法中,使用非对称加密来交换共享密钥,然后该共享密钥用于会话通信的其余部分的加密。
  • 消息完整性:如身份验证部分所述,XML 签名用于建立用户身份。它也用于建立消息完整性;即消息未被篡改。通过附加消息签名,接收方会重新计算签名并验证完整性(如果两个签名匹配)。与加密类似,通常使用混合方法来降低基于非对称签名的成本。

WS-Policy

WSDL 在描述基本 Web 服务需求(如消息架构和身份验证头)方面做得很好。然而,WSDL 无法描述合同要求,如安全性。例如,回想一下声明式架构的前一节,RP-IP 交互受一组安全策略的约束。这些策略无法使用 WSDL 描述;而是使用 WS-Policy 及其相关规范 WS-SecurityPolicy 来描述。

一般来说,WS-Policy 断言可用于安全性、可靠消息、会话、事务、可靠消息等。在 WCF 中,这些策略被指定为代码属性或配置节。

  • WS-Policy:一种定义策略断言描述框架的规范。断言是服务的需求或偏好。该规范定义了一种通用语言,与断言域(安全性、事务、可靠消息等)无关。
  • WS-PolicyAssertion:一种为 WS-Policy 定义通用消息相关断言的规范。不同域存在独立的断言;例如,WS-SecurityPolicy、WS-AtomicTransactions 和 WS-ReliableMessaging。
  • WS-PolicyAttachment:一种描述策略如何附加到 WSDL(和 UDDI)的规范。

WS-Addressing

WS-Addressing 规范提供了能够实现端到端传输无关的消息传输的元素。例如,这允许您实现消息路由(以前是 WS-Routing),您可以基于某些消息标准显式指定消息路由中的下一跳。还可以执行其他一些操作,例如为消息指定不同的响应或错误返回 URL,从而将响应发送到与原始发件人不同的端点。

WS-Trust

如声明式架构中所述,您可以将应用程序的身份验证逻辑委托给另一个实体,该实体会颁发您的应用程序所信赖的声明。我跳过的那部分是如何让您的应用程序“信任”这些声明?是什么阻止了虚假的 IP 生成声明并将其发送到您的应用程序,然后该应用程序授予其访问权限?

让我们更进一步:假设两家公司 A 和 B 希望进行业务往来。公司 A 希望 B 用户能够访问其应用程序。如何实现?一种方法是 A 配置 B 用户;然而,这显然是一个麻烦的解决方案,因为 A 将不得不管理和控制 B 用户。如果我们让 A“信任”B 用户而不实际管理他们,那不是一个更好的解决方案吗?

WS-Trust 是一种解决上述两种场景的规范。WS-Trust 引入了安全令牌服务 (STS) 的概念,它是一个 Web 服务,负责生成消费者信任的声明。在第一种场景(身份验证委托)中,您的应用程序与 IP 的 STS 服务建立 WS-Trust 关系。在第二种场景(公司 A 和 B)中,双方都建立 WS-Trust,其中 A 信任 B IP 的 STS;这样 B 用户就可以携带其 IP-STS 颁发的令牌并将其呈现给 A,A 信任 STS,从而授予访问权限。

WS-Trust 定义了一个名为 RequestSecurityToken (RST) 的消息请求,该请求发送到 STS。STS 则通过名为 RequestSecurityTokenResponse (RSTR) 的响应进行回复,该响应包含用于授予访问权限的安全令牌。WS-Trust 描述了通过 RST 请求令牌并通过 RSTR 颁发令牌的协议。

WS-SecureConversation

WS-SecureConversation 规范提供了一种机制,可以在客户端与该服务进行长时间通信时提高服务响应时间。

当客户端向安全服务发送消息时,请求的一部分将用于凭据协商和身份验证。在传输级别,这在 SSL 握手过程中完成,因此任何后续请求都使用已建立的安全会话。WS-SecureConversation 在消息级别实现了相同的功能。

WS-SecureConversation 规范指出,客户端首先向服务发送 RST(来自 WS-Trust 规范)。服务验证 RST 中的凭据,并以安全上下文令牌 (SCT) 的形式返回一个令牌,其中包含一个对称密钥,用于处理剩余通信的加密操作。

这些令牌由 WS-Security 用于身份验证和完整性,并在 IP 和 RP 两端使用 WS-SecurityPolicy 断言进行描述。

WS-Federation

我们终于来到了 WS-Federation 部分!前面讨论的所有规范都导向这里。

让我们从定义联合开始:联合是指多个安全域(也称为领域)——通常是 B2B 场景中的多个组织——建立信任以授予对资源的访问权限。继续使用我们一直在使用的术语,域 A 中的 RP 可以信任域 B 中的 STS IP,以便 B 用户可以访问 A 的资源。

WS-Federation 建立在 WS-Trust 之上,通过定义一个通用基础结构来实现 Web 服务(称为活动客户端)和 Web 浏览器(称为被动客户端)的联合身份,从而简化了此类联合场景的创建。

WS-Federation 规定,参与联合的组织应在联合元数据中发布通信和安全要求。这些元数据在前面描述的 WS-Policy(和 WS-SecurityPolicy)元数据之上添加了联合特定的通信要求。例如,令牌类型和单一注销要求是联邦元数据中定义的内容示例。

WS-Federation 不强制使用特定的令牌格式,尽管我们稍后会看到,SAML 令牌被大量使用。

.NET 4.5 中的身份和访问控制

.NET 4.5 之前的身份和主体

如果您从 v 1.0 开始创建 .NET 框架应用程序,那么您很可能已经遇到过 IIdentityIPrincipal 接口。IIdentity 代表已通过身份验证用户的身份,而 IPrincipal 包含该特定身份以及一个用于检查用户是否属于某个角色的方法。

存在 IIdentityIPrincipal 的不同实现:

  • WindowsIdentityWindowsPrincipal 用于 Windows、Active Directory 或 Kerberos 身份验证。
  • GenericIdentityGenericPrincipal 用于自定义身份验证,如表单身份验证。

正如您所见,直到 .NET 4.0,基于角色的访问(或授权)确实受限于 IPrincipal 及其实现的 IsInRole 方法。有多种方法可以调用此方法;您可以直接通过 API 调用,也可以使用基于属性的授权(PrincipalPermission),或者使用 web.config 中的授权元素。无论采用哪种方法,您的基于角色的访问能力仅限于检查登录用户是否属于某个组。

现在,如果您读到这里,您肯定会注意到声明式授权为您提供了更大的权力。使用声明,您可以基于用户的出生日期、国家 ID 以及角色等因素做出访问决策。关键在于执行身份验证的系统(在我们的文献中是 IP)将与 RP 约定的任何属性作为一组声明(断言)附加;然后 RP 使用这些声明来做出适当的授权决策。

那么,.NET 4.5 之前是否不支持声明?是的,它们得到了支持,而且是这样实现的:

WCF 3.0 声明转换

在 Windows Identity Foundation (WIF) 1.0 发布之前,Microsoft 将声明整合到其安全模型中的第一个尝试是在 WCF 的框架下进行的。在 WCF 3.0 中,Microsoft 包含了 System.IdentityModel 程序集,该程序集基本上为 WCF 身份验证的每个安全令牌生成一组声明。WCF 3.0 随附了以下类:

  • System.IdentityModel.Claims.DefaultClaimSet,它表示发送到服务的任何其他通用声明。
  • System.IdentityModel.Claims.X509CertificateClaimSet,用于将 X509 令牌转换为声明。
  • System.IdentityModel.Claims.WindowsClaimSet,用于将 Windows 令牌转换为声明。

WCF 3.0 包括用于执行实际声明转换的授权策略。

这种方法的问题在于,.NET 开发人员现在必须为 Web 应用程序(IIdentityIPrincipal)和 WCF 服务(System.IdentityModel)维护两个完全不同的安全基础结构。因此,如果您有一个同时包含 Web 应用和 Web 服务的应用程序,那么您将不得不针对两个不同的库编写几乎相同的代码。

WIF 1.0

Microsoft 在 WIF 1.0 中增强了其声明基础结构。在 WCF 3.0 中使用的 System.IdentityModel 之后,他们发布了一个名为 Microsoft.IdentityModel 的新程序集。

通过添加 IPrincipal 的另一个实现,称为 IClaimsPrincipal,可以满足支持声明的需求。一旦使用声明式身份验证进行填充,IClaimsPrincipal 就会被填充。正如您所见,WIF 结合了两种世界:基础类 IIdentityIPrincipal 的世界以及 WCF 3.0 声明基础结构的世界。

以下是如何为启用了声明式身份验证的应用程序检索声明:

IClaimsIdentity identity = Thread.CurrentPrincipal.Identity as IClaimsIdentity;
string email = (from c in identity.Claims where
   c.ClaimType == System.IdentityModel.Claims.ClaimTypes.Email
   select
   c.Value).Single();   

正如您所见,我们正在强制转换当前主体的标识以获取 IClaimsIdentity

即使有了这种改进的方法,您是否已经注意到其缺点?好吧,问题在于,通过这种方法,如果您使用 WindowsPrincipalGenericPrincipal,您将无法获得声明,因为 IClaimsPrincipal 只是 IPrincipal 的另一个实现,就像其他两个一样。非此即彼。这使得 .NET 4.0 中的声明支持不是一流的。

.NET 4.5 中的身份和主体

在 .NET 4.5 中,无论身份验证类型如何,都可以获得声明。Microsoft 所做的是创建 IPrincipal 的新实现,称为 ClaimsPrincipal。然后,他们让所有其他主体(WindowsPrincipalGenericPrincipal)派生自 ClaimsPrincipal,并删除了 .NET 4.0 的 IClaimsPrincipal。这样,您将始终获得声明;例如,即使您使用表单身份验证,从成员资格提供程序拉取的所有属性也将以声明的形式传递。

这样,所有身份验证类型的基于角色的访问都是统一的,更重要的是,它比简单的 IsInRole 方法更丰富,因为现在您依赖声明来做出决策。

让我们看看如何为启用了声明式身份验证的应用程序检索声明,并与 .NET 4.5 之前的代码进行比较:

string email = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;

ClaimsPrincipal.Current 的作用与 Thread.CurrentPrincipal 过去的作用基本相同。

让我们看一下 .NET 4.5 中新的声明式模型。下面您可以看到一个使用 WindowsIdentity 的 VS 2012 Web 应用程序的调试器屏幕截图:

您会注意到基类是 System.Security.Claims.ClaimIdentity 类型,如前所述,这是 .NET 4.5 中身份类的新的基类。另请注意,即使我们使用了 Windows 身份,声明也填充了 Windows 登录特定的信息。在 .NET 4.5 中,您无论如何都会获得声明。

下图显示了当我们定义 GenericIdentity(模拟表单身份验证等)时的类似结果。再次,基类是通用的,并且默认生成一个 Name 类型的声明。

使用表单身份验证时,默认情况下您会获得 Name 声明。您可以使用 ASP.NET Role Manager 获取其他声明。

让我们简要讨论 .NET 4.5 声明模型的一些更多概念和功能。

支持的凭据类型

如前所述,声明模型最大的优势在于,无论使用何种身份验证机制,您的应用程序始终依赖声明来实现授权。因此,您的应用程序逻辑实际上并不关心用于身份验证的安全令牌的实际类型;身份验证逻辑是一个独立的问题,有其独立的模块,您的应用程序获得声明,您使用这些声明做出授权决策。

现在,我所说的这个身份验证层可以是您应用程序的一部分,位于一个单独的模块中,或者——如最开始所讨论的——它可以是一个您信任的独立 STS,遵循 IP/RP 模型。在本讨论中,我们的重点是 .NET 4.5,因此身份验证将是应用程序的一部分,下一节将深入介绍 WIF 4.5,您将在其中看到 STS 的实际应用。

因此,您的 .NET 4.5 应用程序可以使用以下任何安全令牌:

  • Windows/AD/Kerberos
  • 表单身份验证
  • 客户端证书
  • SAML 令牌
  • 其他扩展令牌类型

一旦通过身份验证层,您的应用程序就会在前面显示的 ClaimsPrincipal 中获得声明。

声明转换

在声明实际到达您的应用程序之前,它们可能会经过一个转换/验证层。例如,转换需求是您知道声明会以某种格式到来,而您希望更改此格式以适应您的应用程序代码。例如,验证是——假设您的应用程序接受来自 STS 的声明——在将声明交给您的代码之前,您想确保存在最少数量的必需声明。

要实现此转换/验证,您必须覆盖一个名为 ClaimsAuthenticationManager 的类。

身份验证会话

您在 ClaimsAuthenticationManager 派生类中编写的逻辑可以在每个请求中运行,或者您可以选择缓存其结果,如果您认为其逻辑成本很高。缓存的值可以保存在 ASP.NET 应用程序的 cookie 中,并使用 WS-SecureConversation 来处理 WCF 服务。

声明式授权

最后,我们进入了根据声明执行授权决策的阶段。ClaimsAuthorizationManager 类是您想要派生以实现授权逻辑的类。该类包含 CheckAccess 方法,可以在任何需要做出授权决策时调用。

这样,您就不会将授权逻辑直接混入您的业务逻辑中(这通常是 IsInRole 检查时代使用的方法)。

再次提醒您,这种在应用程序内部使用声明的方法与声明是由您的应用程序的一部分身份验证逻辑生成的,还是由它信任的 STS 提供的,都是相同的。在这两种情况下,您都可以使用 ClaimsAuthorizationManager 来最大限度地减少您的业务逻辑与授权决策之间的耦合。

最后一点:声明式模型对于 Web 应用程序和 WCF 服务是相同的。因此,.NET 4.5 用于检索、转换和授权声明的代码,无论使用者是 .NET 4.5 Web 应用还是 WCF 服务,都是一样的。

.NET 4.5 中的 Windows Identity Foundation (WIF)

在上一节中,我讨论了 .NET 4.0 与 .NET 4.5 中声明模型的区别,并向您展示了声明在 .NET 4.5 中现在是如何成为一等公民的。然而,上一节仍然使用了“传统”身份验证机制,即身份验证仍然是您应用程序的责任。不过要小心,我不希望上一节分散您对本文主要焦点的注意力:将身份验证责任委托给外部实体。

WIF 是 Microsoft 的技术,它将 WS-Federation(和 WS-Trust)的内部工作封装在一个 .NET 库中,使得开发人员能够轻松创建声明式应用程序,而无需了解我们之前讨论过的规范的详细信息。

如上一节所述,我们已经看到身份和访问支持在 .NET 中经历了多个阶段,从简单的 IsInRole 检查,到 WCF 3.0 中的声明支持,再到 WIF 1.0,然后到 .NET 4.5。

WIF 4.5 是这一切的终点(新的工作才开始!)。在 .WIF 4.5 中,Microsoft 再次更改了程序集的命名。

WIF 实战

VS 2012 提供了工具,让您可以快速设置 RP 并使用本地 STS。创建 STS 应该是您最后尝试做的事情。然而,您只会将此 STS 用于开发/测试目的。运行 STS 并非易事,因为它关系到业务关键性,并且依赖于复杂的协议和加密操作。

现有的 STS 商业产品,您很可能会用到它们。其中一些产品包括:

  • Active Directory Federation Services (ADFS) v2
  • IBM Tivoli Federation Manager
  • Oracle Identity Manager

 ADFS v2 是下一篇文章的主题。

那么,为什么 Visual Studio 会提供这个本地 STS 呢?简单地说,是为了在开发(可能还有测试)阶段为您提供帮助,此时 STS 产品可能无法供您使用。由于您的 RP 不再承担身份验证逻辑,因此在上线之前,您要做的就是编辑 RP 的策略,使其信任新的 STS 而不是使用 Visual Studio 创建的那个。

开始吧。

创建一个新的 VS 2012 ASP.NET 4.5 Web Forms 应用程序。右键单击项目并选择“身份和访问”。这将显示一个向导,提供三个选项:ADFS2 和 ACS 将在未来的帖子中讨论,我将快速说明 ADFS2 是 AD 的 STS,而 ACS 是 Azure 上的 STS。

选择创建本地 STS 的选项。在“本地开发 STS”选项卡中,您可以选择要使用的 SAML 令牌版本、STS 的本地端口,但最重要的是,您可以选择 STS 将向您的 RP 提供的声明。在 WIF 1.0 中,您必须手动编辑本地 STS 代码来更改声明集;这种方式更清晰,并且符合将您(RP 所有者)与身份验证逻辑隔离的承诺。请注意,您可以使用许多预定义的声明命名空间,也可以定义自己的。接受默认值关闭向导。

VS 2012 现在已配置您的 RP 以信任本地 STS,并设置了它们之间的策略。要查看此内容,让我们检查 RP 的 web.config 文件。

  • 已删除表单身份验证:您的 RP 现在既不是基于 Windows 也不是基于表单身份验证的。它是一个声明式应用程序,因此表单身份验证被禁用,因为它是创建 VS Web Forms 应用程序时的默认设置。
  • 使 WIF 魔力成为可能的两项 HTTP 模块:
    • WSFederationAuthenticationModule:此模块拦截传入请求,并将未经身份验证的请求重定向到受信任的 IP。对于已通过身份验证的请求,它会处理安全令牌中的声明,并以可用的格式将其呈现给您的应用程序。
    • SessionAuthenticationModule:此模块负责身份验证建立后的会话管理。WSFederationAuthenticationModule 模块会被绕过,SessionAuthenticationModule 会处理请求,直到会话过期或调用注销流程。
  • audienceUris:列出您的 RP 将视为有效接收令牌的 URI。
  • trustedIssuers:RP 将接受其签名的信任的 IP 证书列表,以验证令牌。
  • wsFederation:配置 WS-Federation 协议,例如使用被动协议流、协议将与之通信的 IP,以及 realm,它基本上是协议流最终将返回到的最终 URL——在这种情况下是 RP 本身。

此外,VS 2012 在 RP 项目中创建了一个 FederationMetadata.xml 文件。回想一下 WS-Federation 的讨论,参与联合的组织应该在联合元数据中发布通信和安全要求。此 XML 文件保存了该 RP 的这些要求。

现在运行应用程序,快速注意浏览器导航,您会看到您的应用程序被重定向到本地 STS,该 STS 执行(硬编码的)身份验证,并作为已通过身份验证的用户返回到您的应用程序(假设您暂时是 Terry!)。现在您可以像之前看到的那样在应用程序中访问声明了。

现在,让我们看看后台发生了什么,以检查 WS-Federation 和之前讨论的支持协议的实际应用。为此,我将使用 Fiddler。

步骤 1:用户浏览 RP

您通过浏览器请求应用程序。WIF HTTP 模块 WSFederationAuthenticationModule 检测到您未经验证,因此它以 302 响应将浏览器重定向回去,并在 Location 头中包含您必须进行身份验证的 IP-STS 的地址。此外,还提供了一组 WS-Federation 协议查询字符串来控制流程的行为。

  • wa:值为 wsignin1.0,表示这是一个登录请求(请注意,WS-Federation 也支持注销流程,因此此参数是必需的)。
  • wtrealm:这是 RP 本身,代表令牌的预期使用者。
  • wct:这是一个可选参数,指定 RP 的响应时间。如果 IP 发现此参数值与实际收到登录请求的时间之间存在时间延迟,则可能将其用作可能攻击的指示。

步骤 2:浏览器向 STS 发送 GET 请求

浏览器然后使用 Location 头中的 STS 地址和之前讨论的查询字符串来构建对 STS 的登录请求。这是本地 STS 的请求:

步骤 3:IP-STS 执行身份验证

在“真实”场景中,STS 通常会向您显示一个身份验证表单,您可以在其中提供您的凭据。STS 身份验证用户的此过程(如前所述)超出了 WS-Federation 的范围,因此也超出了 WIF 的范围。STS 可以根据 AD、自定义用户存储,甚至使用 X.509 证书来验证您的身份。这取决于 RP 应用程序的类型以及用户的来源。无论身份验证机制如何,STS 都将——假设身份验证成功——生成一个包含 IP 和 RP 通过策略约定的声明的安全令牌。

步骤 4:STS 将响应发送回浏览器

STS 将一个隐藏表单 POST 回到 RP 发送回浏览器。表单包含以下信息:

  • wa:与之前相同,表示登录流程。
  • wresult:包含 STS 颁发的 SAML 安全令牌。

如果您仔细检查响应,您会看到之前讨论的许多协议正在发挥作用:

  • WS-Trust 的 RequestSecurityTokenResponse (RSTR) 携带令牌集合。
  • WS-Security 的 XML 签名用于提供 IP 和 RP 之间的消息完整性和信任。
  • WS-Policy——由联合元数据驱动——指示令牌生命周期等规则。
  • WS-Addressing 用于标识被动请求(即 RP)的端点引用。

我重新格式化了内容以便于显示,您可以在此处看到这些协议的实际应用:

注意:SAML-P(协议)和 SAML 令牌之间存在区别。SAML-P 是一个完整的协议,类似于 WS-Federation。SAML 令牌是一种令牌类型,可以独立于 SAML-P 使用,并且它是 WS-Federation 中常用的令牌类型之一。

我将在本文末尾简要介绍 SAML-P 2.0。 

步骤 5:浏览器 POST 回到 RP

浏览器使用上一步的隐藏 POST 表单将上一步显示的响应 POST 回到 RP。

步骤 6:RP 验证令牌

验证令牌涉及多个检查,这些检查可能根据具体情况和策略进行。其中一些检查是:

  • 完整性:如果使用数字签名,RP 会使用请求中包含的 IP 公钥证书来验证数字签名是否有效。
  • 过期:如果令牌存在过期时间,RP 会验证令牌是否未过期。
  • 解密:如果使用加密,RP 会使用其私钥解密内容。在上面的示例中,未使用加密,因为我们处于被动(Web 浏览器)情况;稍后我将讨论活动情况并说明区别。
  • 来源:根据策略,RP 确保令牌是由受信任的 IP 颁发的。
  • 声明:同样根据策略,RP 检查颁发的声明集是否是约定的声明。

步骤 7:发出会话 cookie

令牌验证后,RP 会向浏览器发出一个会话 cookie,以便后续请求不再需要通过相同的 WS-Federation 过程。

WIF for Active Clients

我们刚刚看到的基于浏览器的场景称为被动场景。被动客户端是指不具备 WS-* 功能的客户端。浏览器是被动的,因为它们只执行被告知执行的重定向,而浏览器本身没有 WS-Federation 的概念。

另一类客户端是活动客户端。活动客户端是指能够执行 WS-* 操作的客户端;一个明显的例子是 WCF 服务。WCF 服务也可以充当启用了声明式身份验证的 RP。在这种场景下,客户端(根据定义的术语是主体)是一个调用 WCF 服务的应用程序,该应用程序需要来自受信任 STS 的声明式身份验证。

完整的流程如下:

  • 应用程序执行到调用 WCF 服务的某一行。WCF 服务本身就是一个配置为声明式身份验证的 RP。
  • 应用程序中的 WCF 客户端库会发现 WCF 服务需要一个安全令牌才能授予访问权限。然后该库向 STS 发出 RST。
  • STS 通过 RSTR 回复一个安全令牌。
  • 客户端应用程序然后使用此令牌访问 WCF 服务。在这里,您可以发现被动和活动场景之间的主要区别。回想一下在被动情况下,客户端(浏览器)只有 Https 作为向 RP 加密其请求的选项——称为传输级别。在活动情况下,客户端(应用程序)实际上可以使用令牌对消息执行自定义消息级别加密。消息级别安全性具有更好的性能,因为我们可以选择性地确定消息的哪些部分被视为敏感信息,因此需要加密,它还支持端到端消息传递。
好消息是,在 WIF 方面,您无需学习任何比在被动场景中看到的新知识。相同的编程模型适用。您可以在 VS 2012 中右键单击 WCF 项目,然后使用“身份和访问”向导将其配置为 RP。活动和被动客户端之间的定义性区别在您检查 WCF 服务的 web.config 时会变得很清楚;您会看到使用了 ws2007FederationHttpBinding,这再次表明活动客户端是 WS-* 感知的。

联合身份提供者

 到目前为止,讨论一直集中在 STS 可以扮演的一个角色,即代表 IP 颁发声明;因此,它被称为 IP-STS。然而,STS 可以扮演另一个角色;联合身份提供者的角色。

让我们回顾一下我之前讨论过的两家公司 A 和 B 希望建立联合业务协议的场景。在该场景中,我举了一个 B 用户需要访问 A 中的(单个)应用程序的例子,以及该应用程序如何配置为 B IP 的 STS 的 RP。

现在让我们稍微扩展一下场景:而不是 B 用户希望访问 A 中的单个应用程序,两家公司都希望扩大他们的合作关系,现在 B 用户必须能够访问多个 A 应用程序。在我们到目前为止讨论的 IP-STS 角色下,每个 A 应用程序都必须与 B IP 建立信任,然后 B 只需要配置每个 A 应用程序。

一个更好的解决方案是让 A 暴露一个联合身份提供者。联合身份提供者是一个资源 STS (R-STS),它位于资源端(在信赖方端——即 A 域)。然后,A 公司应用程序与 R-STS 建立信任,然后 B 只需配置此 STS。

典型的流程如下:

  • B 域中的员工尝试访问 A 应用程序。
  • A 检测到(例如通过 WIF)用户未经验证,并将请求重定向到它信任的 STS;在本例中,是 A 域中的 R-STS。
  • 反过来,R-STS 配置为接受来自 B IP 的令牌,因此请求被重定向回 B IP。
  • 用户使用 B 定义的任何机制再次在 B IP 进行了身份验证。
  • 向 A 中的 R-STS 提交一个包含令牌的请求。
  • R-STS 处理请求,通常执行以下 3 件事之一:
    • 完全按照从 B IP 发送的方式颁发声明。在此,R-STS 决定包含的声明满足 A 应用程序的需求。
    • 根据某些规则修改声明,例如满足 A 应用程序的特殊格式需求。
    • 添加 R-STS 已知对 A 应用程序很重要的新声明,而 B IP 却不知道。例如,R-STS 可能会维护来自特定用户先前交易的一些信息。
  • 生成的令牌然后发送到最初请求的 A 应用程序,该应用程序授予访问权限。

同样,使用 WIF,您可以创建自己的本地 R-STS;尽管如前所述,在实际场景中您会选择商业产品。ADFS v2 也适合扮演 R-STS 的角色;例如,其声明转换语言非常适合声明修改。另一个很好的例子是 Azure Access Control Service (ACS),它也在云端扮演联合身份提供者的角色。

ADFS v2 和 ACS 都将在未来的文章中讨论。

SAML 2.0

我将通过简要介绍 SAML 2.0 来结束本文。请注意,我本人从未实现过此协议,我在这里呈现的是对 WS-Federation 与 SAML 常见问题的总结性回答,以便您开始,但如果您想要一个明确的答案,您还有很多阅读内容。

SAML 2.0 由两部分组成;一个协议(类似于 WS-Federation),它定义了交互和支持的通信协议,以及一个令牌格式——方便地称为 SAML 令牌。令牌规范独立于协议规范,因此您可以在其他协议中使用该令牌。实际上,这正是我们在本文中一直所做的,即使用 SAML 令牌在 WS-Federation 协议中传递声明。

从非常高层次的角度来看,SAML 2.0 协议 (SAML-P) 实现了与 WS-Federation 相同的目标:它允许业务伙伴达成联合协议,并允许将身份验证逻辑从应用程序(服务提供者)委托给外部实体(身份提供者)。身份提供者创建一个 SAML 断言,服务提供者然后验证该断言以授予身份验证。SAML 断言是包含声明的 SAML 令牌。

SAML 规范实际上分为多个部分:

  • SAML core:此规范定义了 SAML 断言的结构和支持的协议。您可以将其视为其他所有规范的基础。
  • SAML bindings:核心规范中描述的每个协议都在绑定规范中进行了详细说明,其中每个绑定都有特定的通信和格式要求。
  • SAML profiles:profiles 规范将不同的规范组合成一个使用配置文件,例如登录和注销配置文件。
  • SAML metadata:此规范基本上使 SAML-P 能够正常工作。它定义了服务提供者和身份提供者之间建立 SAML-P(支持的绑定、证书、加密等)的协议要求。基本上,这对于 SAML-P 就像 WS-Trust 对于 WS-Federation 一样。

WIF 不支持 SAML-P,尽管以前有一个 WIF 的扩展添加了 SAML 2.0 支持,但该扩展已作为 CTP 发布,但此后一直没有流行起来。您可以在此处看到公告:

http://blogs.msdn.com/b/card/archive/2011/05/16/announcing-the-wif-extension-for-saml-2-0-protocol-community-technology-preview.aspx

不过,情况并非完全糟糕,ADFS 2.0 完全支持 SAML 2.0 协议。为什么这是个好消息?仅仅是因为现在可以在采用 WS-Federation 的一个环境和一个采用 SAML-P 的环境之间实现广泛的互操作性。因此,已经拥有基于 SAML-P 的协议基础结构的公司,无需更改即可与基于 ADFS 的环境互操作。

Web 空间怎么办?

声明式架构在 Web 空间(RESTful)中也得到了广泛应用。您可以查看我关于 OpenID 和 OpenAuth 的博客文章。

[更新]

我的 ADFS 2.0 和 ACS 文章已发布在我的博客上。

© . All rights reserved.