安全令牌服务(STS)是用于根据WS-Trust和WS-Federation协议构建、签署和颁发安全令牌的服务组件。实施这些协议需要进行大量的工作,但WIF能为你完成所有这些工作,让那些不精通协议的人不费吹灰之力即可启动并运行STS。可以使用云STS(如LiveID STS)、预先构建的STS(如ADFS 2.0),或者如果想要颁发自定义令牌或提供自定义身份验证或授权,可以使用 WIF构建自定义的STS。借助WIF即可轻松地构建自己的STS。
STS身份验证支持多种方案:
q 从身份验证机制中分离出应用程序和服务,从而使其能够专注于授权相关声明。
q 支持多种凭据类型,而不会使应用程序和服务的实现变复杂。
q 支持联合方案,用户可以通过在自身的域中进行身份验证来获得对另一个域中资源的访问权限(通过建立不同域的 STS之间的信任关系)。
q 简化标识委派方案,经过身份验证的用户将获得对下游服务的访问权限。
q 简化声明转换,使相关声明能够用于对应用程序和服务进行授权。
其中的任何方案都可以基于被动联合(基于浏览器)或主动联合(基于 Windows客户端)。下面详细介绍这些方案,同时说明如何使用Geneva框架在自定义STS中构建相关逻辑。
在深入探讨STS的实现之前,先回顾一些基础知识。在主动联合中使用的 STS是WS-Federation主动请求者配置文件和(主要)WS-Trust 规范的实现。
从较高层次看,WS-Trust使用四种服务操作来描述一个约定:颁发、验证、续订和取消。客户端分别调用这些操作来请求安全令牌、验证安全令牌、续订已过期的安全令牌以及取消不应再继续使用的安全令牌。根据WS-Trust 规范,每个操作都必须以“请求安全令牌”(RST) 的格式发送消息,并以“RST 响应”(RSTR) 的格式返回消息。在本节中,假定颁发的令牌是“安全声明标记语言”SAML 1.1或SAML 2.0令牌。
图15-4展示了主动令牌颁发时RST和RSTR的核心内容。
图15-4 主动联合方案的令牌颁发
如图所示,RST消息包括请求安全令牌所需的必要信息,其中涉及待颁发令牌的类型(本书中是SAML)、将要被纳入到颁发令牌中的“依赖方”(RP) 所请求的声明、有关RP (AppliesTo) 的信息(包括URL和通常用于标识RP的证书),以及将被用于RSTR所返回的“证明密钥”(proof key) 的可选(未显示)密钥材料。
如果令牌颁发成功,RSTR将包括颁发的SAML令牌和证明密钥(假定STS决定使用哪个证明密钥,因此必须在RSTR中返回它)。SAML令牌将包括已验证方的相关声明,它由 STS签名来保护令牌不被篡改,令牌中将包含用于 RP 加密的证明密钥,并且它会为 RP 加密自身以确保只有目标接收节点才能处理该令牌。
客户端使用证明密钥来签署发往RP的消息。RP必须能够在 SAML 令牌中解密证明密钥,否则拒收该消息。如果令牌中的证明密钥与消息中的签名匹配,则证明此次对 RP 的调用是由请求该令牌的调用方所发送的。
被动联合方案基于 WS-Federation 被动请求者配置文件,其中涉及基于浏览器的通信。虽然底层消息传递仍基于 WS-Trust,但RST却在STS URL中被分解为查询字符串参数,而RSTR通常会作为表单参数被发布到 RP。被动STS和RP使用联合Web处理程序来截取这些参数。被动STS可以直接处理WS-Trust 请求,或者将其传递到底层WS-Trust实现。图15-5说明了在被动联合方案中对 RST和 RSTR 的处理方式。
图15-5 被动联合方案的令牌颁发
主动与被动联合方案的一个本质差异在于颁发的 SAML令牌的类型。主动联合通常依靠使用“密钥所有者”(holder-of-key) 类型主体确认的 SAML令牌,这意味着前面所述,在实际当中存在着一个证明密钥,它可以证明发出令牌进行验证的客户端是请求该令牌(也称为ActAs行为)的主体。被动联合方案通常涉及带有“持有者”(bearer) 类型主体确认的 SAML令牌(也称为持有者令牌)。这种类型的令牌不包含证明密钥,有时也称为无密钥令牌。它依靠传输来确保从 STS获得该令牌并将其传递给 RP。
简单的主动联合方案如图15-6所示。
图15-6 使用单一RP 和主动 IP-STS 的简单联合方案
如图所示,通常存在以下参与者:
q RP,由客户端调用的服务。
q 单独的 STS(也作为服务实现),支持 WS-Trust 协议。此 STS将对调用方进行身份验证并颁发具有标识调用方声明的安全令牌,也称为标识提供者或 IP-STS。
q 客户端,在本例中为基于 Windows的应用程序,它依靠代理对 STS进行身份验证、检索令牌颁发结果以及发送消息给 RP(它会提供用于身份验证和授权的颁发令牌)。
图15-7说明了在此实现中可以灵活设置的部分。
图15-7 自定义主动STS和主动IP-STS的实现体系结构
图中包括自定义SecurityTokenService 实现、使用 ServiceHost 扩展 (WSTrustServiceHost) 初始化用于联合的运行时、使用 WSTrustContract 类型的派生配置一个或多个 WS-Trust 端点以及用于标识模型运行时的其他相关配置设置。
声明转换对于联合的安全性至关重要:它可能在联合过程中的任意时刻发生。在 IP-STS 和 RP 属于同一域的简单联合方案中,IP-STS 负责将声明从身份验证期间用户所提供的一组初始身份标识声明转换为 RP 能够用以授权调用的声明。用户可以为 IP-STS 提供任何支持的凭据类型来进行身份验证,其中每个都会评估一组代表该凭据的声明。
IP-STS 将这些声明转换成一组标准的应用程序声明,RP 可以通过这组声明授权调用,它们可以是角色或更精细的声明,如创建、读取、更新或删除等权限。图15-8对这种方案进行了说明,其中Admin用户登录并被授予 Role 声明和几项 Action 声明,其中包括创建、读取、更新和删除等。
图15-8 IP-STS 声明转换
这种类型的声明转换非常有用,因为对 STS的身份验证会得到一个令牌,其中包含授予该用户的所有声明。也有一些情况需要使用其他方法进行声明转换;例如为了减少颁发给那些仅与当前调用上下文相关的声明、为了保护声明的隐私性,或者为了促进跨域联合等。
向经过验证的调用方授予RP 公开的所有功能,既无必要,也不合适。这不但会使声明列表变得非常长,而且很多列表中的功能不符合当前环境的上下文,因此在不具备该上下文的情况下不应授予该声明。例如,某用户正在与客户进行订单交互,只授予Delete声明即可,但如果他正直接与客户记录交互,则不应授予该权限。
在其他一些类似情况中,如果 RP 能够只从 IP-STS 请求少量声明即可标识调用方,然后使用一组特定的仅适用于该调用上下文的附加声明来请求一个新令牌,则将会非常有帮助。例如,用户正在 RP 服务中调用 DeleteCustomer 操作,在授权执行此操作之前,RP 将会调用从 IP-STS 传入令牌的 RP-STS,并在 DeleteCustomer 操作的上下文中请求 Delete 声明。如果该声明存在,则调用将获得授权。图15-9说明了此示例。
图15-9 RP-STS 声明转换
此外,有时还存在 STS颁发的声明不应与 RP 直接共享的情况。例如,可以不必通过颁发 Age 声明来使 RP 了解用户的年龄,RP 可以请求 IsOver13 声明来确保调用方的年龄符合使用 RP 功能的条件。这样可以确保 Age 声明的实际值不会离开 STS。当然,这也表明 ST 将提供既能避免共享个人详细信息又可以包含 RP 所需数据的声明。
当属于一个域的用户被授予对另一个域中RP 的访问权限时,联合方案中也会发生声明转换。在这种情况下会涉及两个 STS:用户域的 IP-STS 和 RP 所属域的 RP-STS。
同样也是在这种情况下,IP-STS 会授予一些 RP-STS 能够理解且达成一致的声明;但这些声明可能无法在 RP 应用程序中直接使用。相反,RP-STS 可能会负责将另一组可信声明转换为能够被 RP 域所理解的声明。
图15-10说明了这种方案。
图15-10 联合方案中的声明转换
如图所示,当 Joe 试图在没有令牌的情况下访问 RP 时,他将登录到自己所在域(域 B)的 IP-STS。该请求将申请 RP 能够理解的声明(在本例中为 RPClaim),以便 IP-STS 知道应该颁发 RP 能够使用的令牌。当 RP-STS 接收到此令牌后,它将把该声明转换为 RP 专用的声明。为了使此联合方案能够工作,必须在 RP-STS 和 IP-STS 之间建立信任关系,而且它们必须对 IP-STS 应该为其用户颁发的将被授予对 RP 访问权限的一组声明达成一致。
对于那些热衷于构建自定义STS而又不需要STS平台全部功能(如Geneva服务器)的用户而言,WIF框架是非常实用的工具。但即便使用WIF框架,构建自定义STS也不是一项简单的任务,建议尽量使用完整功能的STS以减少出现安全漏洞的风险。
-----------------------------注:本文部分内容改变自《.NET 安全揭秘》