使用 Windows CardSpace 保证您的 ASP.NET 应用程序和 WCF 服务的安全

M
icrosoft 于 2005 年 5 月提出了对 Identity Metasystem 的构想。Identity Metasystem 可以降低与管理和交换数字身份标识相关的复杂性和风险。此构想解释了基于互操作性标准(如 WS-Security、WS-Trust、WS-MetadataExchange、WS-SecurityPolicy 和其他 WS-* 协议)的交互,“ Microsoft's Vision for an Identity Metasystem”一文中对此构想进行了探讨。借助这些协议,应用程序和服务能够通过安全策略传达其安全要求,并安全可靠地传输数字身份标识。Identity Metasystem 的构想描述了用户在向应用程序和服务进行自我标识时所获得的简单一致的体验,同时还涉及到向用户标识目标站点,以降低他们在向未经授权站点或恶意站点发送私人信息时所面临的相关风险。

 

随 Windows Vista™ 和 Microsoft® .NET Framework 3.0 发布的 Windows CardSpace™(前称“InfoCard”)在 Identity Metasystem 中发挥了重要作用。Windows CardSpace 并未采用传统的用户名和密码身份验证,取而代之地使用了一个验证工具,此工具有助于用户更好地管理数字身份标识,同时还可帮助他们抵御各种形式的身份标识攻击(例如网络钓鱼诈骗)。

在本文的开篇,首先要简单介绍 Identity Metasystem 中每一方的角色,介绍 Windows CardSpace,并讨论一下个人信息卡和托管信息卡。然后我将就一些涉及 ASP.NET Web 应用程序和 Windows Communication Foundation 服务的方案进行讨论,介绍如何将 Windows CardSpace 作为身份验证机制集成到每个方案之中。

本文假定您具备 ASP.NET 和 Windows Communication Foundation 的使用经验并熟悉 Windows CardSpace 的各项功能。有关 Windows CardSpace 的详细概述,建议您参阅 David Chappell 撰写的“Introducing Windows CardSpace”一文。您可以从 Keith Brown 主持的两个专栏“A First Look at InfoCard”和“A Deeper Look at InfoCard”中获得有关该话题的其他背景信息。


Windows CardSpace 和信息卡

Identity Metasystem 中有三个关键的参与方:信赖方 (RP)、使用者和身份标识提供程序 (IP)。RP 可以是任何接受令牌以执行给定任务(例如,登录和提供成员资格详细信息)的事物,通常为应用程序或服务。从本文的目的出发,我将为大家演示使用者是如何利用 Windows CardSpace 身份标识选择器选择和提供适当的凭证来进行身份验证的。

使用者是希望向 RP 安全地提供信息(如身份标识信息)的人。信息以一种由某个 IP(例如,银行、员工、政府等)颁发的安全令牌的形式进行传递。

该 IP 负责代表使用者颁发安全令牌,并为令牌内的声明所描述的使用者信息提供担保。IP 通常以安全令牌服务 (STS) 的形式来实现,这是一种 Web 服务端点,它可以实现 WS-Trust 协议,以颁发、更新、验证或取消对使用者进行描述的安全令牌。

图 1 Identity Metasystem 参与方
图 1  Identity Metasystem 参与方 (单击该图像获得较大视图)

图 1 说明了三个参与方之间的关系。RP 依赖于特定类型的安全令牌以对调用进行授权。IP 对使用者进行身份验证,并按 RP 要求的格式为使用者颁发安全令牌。使用者随后会将该令牌中继传递给 RP,令牌中含有代表使用者的声明。这些角色之间的相互分离以及角色之间使用互操作性协议进行通信都是 Identity Metasystem 所遵循的规则。只要参与方都遵照相应的 Web 和 WS-* 协议进行交互通信,就可以在不同技术或平台上实现每个参与方。

在 Identity Metasystem 的上下文中,Windows CardSpace 担当着两个角色。第一,作为一种客户端技术,它用于安全、一致地创建、管理和选择数字身份标识。(在选择数字身份标识方面,Windows CardSpace 用于充当身份标识选择器。)第二,它为个人数字身份标识提供本地 IP,并且可为这些身份标识生成安全令牌。

Windows CardSpace 以信息卡来表示数字身份标识。Windows CardSpace 允许用户创建个人卡或导入其他 IP 颁发的托管卡。稍后,当 RP 要求用户使用信息卡验证自己的身份时,用户可以选择一张卡进行验证。用户只能选择符合 RP 要求的卡,或者选择个人卡并动态地添加必要的声明,相关的 IP 会颁发包含相应使用者声明的安全令牌。

信息卡由 IP 代表通过身份验证的使用者颁发,用于描述该 IP 能够担保的声明。 每张信息卡均表示颁发该卡的 IP 的重要信息,其中包括:

  • 颁发安全令牌的 IP 的 STS 的 URL(或多个 URL)。这样,当用户选择一张卡向 RP 进行身份验证时,Windows CardSpace 就知道从何处请求含有相应声明的安全令牌。
  • 与信息卡相关的声明类型。由于卡是由 IP 颁发的,因此需要由 IP 来定义信息卡表示什么声明。RP 指定了其需要的声明,用户只能选择可以表示这些声明的卡。
  • IP 可以颁发的安全令牌的类型。RP 指定了它所支持的令牌类型,用户只能选择可以支持这些令牌的卡。

 

IP 颁发的卡可以被序列化为文件扩展名为 .crd 的已签名 XML 文档。该 .crd 文件包含 <InformationCard> 部分,其中含有上述信息和 Windows CardSpace 的其他相关信息。图 2 所示为向 Windows CardSpace 导入已签名托管卡的示例。

信息卡可分为两种:个人卡和托管卡。个人卡(有时称为自行颁发的卡)由用户在 Windows CardSpace 内创建,并由本地 Windows CardSpace IP 颁发。托管卡可由其他任何 IP 颁发,而且必须显式地导入到 Windows CardSpace 中。

图 3 中显示了使用者、RP、卡和相关 IP 以及 Windows CardSpace 之间的交互。当网站或服务 (RP) 需要 Windows CardSpace 颁发令牌时,会指定需要哪些声明。客户端应用程序(浏览器或 Web 服务客户端)调用 Windows CardSpace (1),将此信息向前传递。Windows CardSpace 使用此信息为用户 (2) 提供可以满足这些声明的合适的卡。当用户选择卡 (3) 时,Windows CardSpace 使用 IP 定义的方法对用户进行身份验证,调用卡 (4) 所引用的相应的 IP 来颁发一个含有 RP (5) 所请求的声明的安全令牌。但是,令牌中包含哪些声明是由 IP 自己决定的(可能是 RP 策略中包含的声明的超集或子集)。最终,经过签名和加密的安全令牌被传回给应用程序或 Web 浏览器 (6),由它们转发给 RP (7)。

图 3 如何选择并使用信息卡颁发安全令牌
图 3  如何选择并使用信息卡颁发安全令牌 (单击该图像获得较大视图)

信息卡被存储在本地计算机的一个经过双重加密的文件中,同时受到计算机密钥和您的 Windows 登录密码的保护,此外您还可以选择提供 pin 码来确保对卡的安全访问。如果使用多台计算机,可以将卡导出到一个加密的数据文件中,然后再将其导入其他您所信任的计算机。

Back to top

个人卡

个人卡是通过 Windows CardSpace 控制面板创建的。创建个人卡时,实际上要做的事情只有两件:一是创建一组表示某些个人信息的声明,二是创建一张列有这些声明的卡。实际上,表示您所输入声明的个人卡是由本地 Windows CardSpace IP 颁发的,它还对您的声明进行妥善安全的存储,等待对安全令牌的请求。图 4 说明了个人卡如何告知 Windows CardSpace IP 在所请求的安全令牌中加入哪些声明。

图 4 从个人卡生成安全令牌
图 4  从个人卡生成安全令牌 (单击该图像获得较大视图)

创建个人卡时,只能为预定义的某些声明或全部 15 条声明输入信息,如姓和名、电子邮件地址和邮件地址信息。声明由来自 WS-Identity 命名空间的 URI schemas.xmlsoap.org/ws/2005/05/identity 来表示。图 5 列出了个人卡能够存储的声明的 URI(为清楚起见,URI 进行了缩写)。

创建个人卡与为站点创建用户名和密码的差别并不大。网站和 Web 服务可以将个人卡与您的用户帐户关联起来,这样您就可以使用 Windows CardSpace 选择您的身份标识,只需几次鼠标单击即可,不必键入用户名和密码。将卡与帐户建立关联要使用基于信息卡专用个人标识符 (PPID) 的唯一标识符。此标识符对于每张卡和 RP 组合都是唯一的。也就是说,如果多个 RP 使用同一张卡,则每个 RP 收到的 PPID 是不同的,以便保护用户的使用模式的隐私。

Back to top

托管卡

与个人卡不同,托管卡可以表示 IP 希望添加的有关使用者的任何声明(实际的卡数据存储在 IP 的系统中,并非本地计算机中)。在 Windows CardSpace 界面中无法创建托管卡,这是因为本地 Windows CardSpace IP 只能颁发针对一组固定声明的卡。任何 IP 都可以颁发托管卡,这些托管卡表示可以为之生成安全令牌的声明。实际上,由于 RP 和 IP 之间必须存在某种关系,因此 RP 和 IP 可能同属于一家企业。

例如,如果您向某家银行申请了一个帐户,该银行知道您的帐号和帐户类型,则 IP 可能会颁发一张卡,指明可以为这些声明颁发安全令牌。为规避使用用户名和密码登录帐户的相关风险,可以将托管卡安装在 Windows CardSpace 中,这样用户就可以在向银行站点进行身份验证时选择该卡。这表明银行在颁发该卡时就已将卡与您的帐户关联,或者说明您需要在卡安装完毕后进行额外的一步操作将卡与帐户关联。

用户在选择使用此卡向银行 RP 进行身份验证时,只能选择能够满足这些声明的兼容托管卡。托管卡不包含实际的声明值,但 Windows CardSpace 知道从何处寻找 IP 来颁发包含这些声明的加密令牌。图 6 说明了托管卡如何告知托管 IP 向所请求的安全令牌加入哪些内容。

图 6 从托管卡生成安全令牌
图 6  从托管卡生成安全令牌 (单击该图像获得较大视图)

每个相互联系的 RP 和 IP 也应就安全令牌中所要包含的声明达成一致。可以使用唯一的 URI 对这些声明进行标识。请考虑下面的 Create/Read/Update/Delete (CRUD) 声明示例:

http://www.thatindigogirl.com/2006/06/claims/create
http://www.thatindigogirl.com/2006/06/claims/read
http://www.thatindigogirl.com/2006/06/claims/update
http://www.thatindigogirl.com/2006/06/claims/delete

 

应用程序或服务可能会使用这些声明对功能和资源进行基于声明的授权。

虽然托管卡受本地计算机的保护,并可导出到其他计算机,但实际的声明存储在 IP 的系统中,必须放入经过加密的安全令牌中才能传出 IP 系统。IP 使用 RP 的公钥对安全令牌进行加密,这样任何人(包括 Windows CardSpace)都无法查看令牌中的声明。(如果用户希望预览要发送给 RP 的声明,可以请求额外的可选的显示令牌。Windows CardSpace 可以对采用这种方式加密的声明进行解密并将其显示给用户。)

Back to top

浏览器和身份标识选择器

目前人们正在开发其他与 Windows 中的 Windows CardSpace 功能相同的身份标识选择器。Windows CardSpace 或其他任何身份标识选择器都可用来选择个人卡或托管卡,以满足身份验证请求。

Web 应用程序要支持个人卡或托管卡身份验证,首先必须提供一个 Web 页,该 Web 页需要具有对象标记或 XHTML,用于描述应用程序的信息卡要求。支持这些标记并具有信息卡扩展的浏览器可以启动客户端计算机上相应的身份标识选择器,以便用户选择卡。如图 7 所示,这里并未特别指定 Windows CardSpace 作为身份标识选择器,也未指定 Internet Explorer® 作为浏览器、ASP.NET 作为网站建立技术。实际上,其他浏览器自身具有处理这些和其他对象标记和行为所用的扩展,而每个操作系统本身也可以具备支持信息卡的身份标识选择器。所有这些元素与平台无关。

图 7 从对象标记或二进制行为触发身份标识选择器
图 7  从对象标记或二进制行为触发身份标识选择器 (单击该图像获得较大视图)

包括 ASP.NET 在内的任何 Web 应用程序平台都可以公开那些含有触发身份标识选择所需的对象标记或 XHTML 二进制行为的页面。对象标记使用如下所示的 MIME 类型 application/x-informationCard:

<object id="informationCard" name="informationCard" 
        type="application/x-informationCard">
    ...
</object>

 

使用 <informationCard> 元素中的 #default#informationCard 行为可以将信息卡二进制行为指定为 XHTML 格式。

  <ic:informationCard name="xmlToken" 
      style="behavior:url(#default#informationCard)" ... >
      ...
  </ic:informationCard>

 

这些 <object> 和 <informationCard> 元素中包含一些参数,这些参数描述了网站对信息卡身份验证的要求。稍后我会为大家做详细介绍。

尽管早期版本的 Internet Explorer 支持对象标记和 XHTML,但只有 Internet Explorer 7.0 才能通过名为 Information Card IE Helper 的 MIME 处理程序扩展(可从 icardie.dll 获得)提供对信息卡的支持。(目前能够下载到可以向 Mozilla Firefox 添加 Windows CardSpace 支持的扩展。)以下注册表项将信息卡的 MIME 类型链接到处理程序:

HKEY_CLASSES_ROOT/MIME/Database/Content Type/application/x-informationCard

 

然后此 MIME 处理程序被链接到浏览器的对象标记和行为配置。此处理程序负责调用身份标识选择器,传递对象标记或 XHTML 二进制行为指定的参数。从下列注册表项我们可以看出,Internet Explorer 7.0 的身份标识选择器默认为 Windows CardSpace:

HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Internet Explorer/InformationCard Token Provider

 

对于对象标记语法,MIME 处理程序需要由 InformationCardSigninHelper Class 触发,并且默认情况下 InformationCardSigninHelper Class 在 Internet Explorer 7.0 加载项对话框中是已启用的,如图 8 所示:(打开“Internet 选项”,从“程序”选项卡选择“管理加载项”可打开此对话框。)如果此加载项被禁用,对象标记将不会触发身份标识选择,但 XHTML 语法不受此设置的影响。XHTML 信息卡行为在下列注册表项下标记为 INFORMATIONCARD 的字符串项中进行配置:

HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Internet Explorer/Default Behaviors 

 

图 8 Internet Explorer 7.0 中的信息卡 MIME 处理程序
图 8  Internet Explorer 7.0 中的信息卡 MIME 处理程序 (单击该图像获得较大视图)

此行为还会触发 MIME 处理程序,以激活身份标识选择器。

遗憾的是,即使经常检测浏览器对信息卡的支持也不是最好的办法,而且不同浏览器的情况各不相同。虽然不推荐这样做,但是对于 Internet Explorer,您可以对 UserAgent 进行初步检查,从中查找 Internet Explorer 7.0 和 .NET 公共语言运行库 (CLR) 3.0 支持。下面是表明了此支持的 UserAgent 字符串的示例:

Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1;
.NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)

 

在 ASP.NET 中,您可以使用 Request 对象的 UserAgent 属性来检查服务器上可能提供的支持,如下所示:

string userAgent = Request.UserAgent;
if (userAgent.Contains("MSIE 7.0") &&
    userAgent.Contains(".NET CLR 3.0"))
    { Response.Write(
        "Information cards are supported, but might not be enabled."); }
else
    { Response.Write("Information cards may not be supported."); }

 

但这种方法的缺点很多。除 Internet Explorer 之外,其他浏览器也支持 Windows CardSpace,而且即使在支持 Windows CardSpace 的浏览器中,MIME 处理程序也可能会被禁用。更好的解决方案是使用客户端脚本来检测浏览器是否支持 Windows CardSpace 以及该支持是否已启用。有关该解决方案的示例,请参阅 www.fearthecowboy.com/2006/12/detecting-cardspace-support-including.html

Internet Explorer 7.0 和相应的 MIME 处理程序配置是从对象标记和 XHTML 触发 Windows CardSpace 的关键之处。除此之外,网站还必须启用 SSL 来确保通信安全。由受信任的根证书颁发机构(如 VeriSign 或 Thawte)颁发的扩展验证 (EV) 证书不需要任何特殊配置,但如果您使用的是测试证书,则需要安装 SSL 测试证书作为受信任的根,并将站点添加到 Internet Explorer 7.0 的受信任站点列表中。本文的代码示例中包含了对此操作的说明。

Back to top

对象和 XHTML 参数

之前我曾说过,您可以使用对象标记或 XHTML 二进制行为从提供支持的浏览器触发身份标识选择器。如图 9 所示,无论使用哪种语法,都必须向信息卡浏览器扩展提供一组基本属性。

图 10 所示,使用对象标记对这些属性进行配置。按照名称,每个 <param> 表示一个信息卡属性。requiredClaims 和 optionalClaims 的值是以空格分隔的声明 URI 的列表。如果默认的设置适合您的应用程序,您可以选择性地省略 issuer 和 tokenType 参数。

图 11 所示,使用 XHTML 对信息卡属性进行配置。在这种情况下,属性用于指定行为方式、颁发者和 tokenType。使用 <add> 指令指定每个声明,该指令指定了声明的 URI 及其是否为可选。至少必须指定一个声明。

在任何情况下,当在含有信息卡触发器的页面上选择了 Submit 按钮时,浏览器会调用 MIME 处理程序并将参数传递给身份标识选择器。如果选择了卡,则经过签名和加密的令牌会包含在以 <object> 或 <informationCard> 标识符命名的表单参数中被发送到站点。在图 10 和图 11 中,标识符为 informationCards。

如果出于某种原因浏览器禁用了信息卡,或者站点未启用 SSL,则表单参数集合将不包含 informationCards 项。如果用户启动 Windows CardSpace 后出于某种原因取消了操作,或者参数无效导致加载 Windows CardSpace 时出现错误,则 informationCards 表单参数将作为空字符串发送。换言之,除非 informationCards 表单参数中包含 <encryptedData> 元素,否则不会进行任何操作。

不管 <object> 或 <informationCard> 使用任何语法,您都可以自行决定从任何 ASP.NET 页面触发 Windows CardSpace,但如果要确保只为页面上特定的 Submit 按钮调用 Windows CardSpace,您还需要进行另外几步操作。ASP.NET 页面有一个活动的 <form> 对象,因此如果您将 <object> 或 <informationCard> 标记放入该唯一的 <form> 对象中,那么无论您愿不愿意,任何发回至服务器的按钮都会触发 Windows CardSpace。

为避免这一点,可以将信息卡对象放入 HTML 标头部分,并在单击相应按钮时通过脚本对其进行显示调用。图 12 所示为一个简单的 ASP.NET 页,其标头中含有 <object> 标记,同时还有一个 SelectInformationCard 函数,该函数用于激活对象并将返回值放入隐藏的输入字段。<form> 标记中所含为一个标准的 ASP.NET Login 控件和一个 ImageButton。

当 Login 控件提交时,由于对象标记位于标头部分内,因此不会调用 Windows CardSpace。而当 ImageButton 提交时,由于 OnClientClick 属性要调用 SelectInformationCard,因此 Windows CardSpace 会被调用。您也可以创建自定义的 ASP.NET 控件,用于发出对象标记和相关脚本。重要的是对每个 Submit 按钮加以区分,以便 Windows CardSpace 仅在适当的时间被激活。

Back to top

处理安全令牌

如前所述,如果 Windows CardSpace 被调用,就会发送经过签名和加密的令牌。在图 12 所示情况下,如果成功颁发了令牌,则 hiddenXmlToken 输入字段中将含有此 <encryptedData> 部分。如果 Windows CardSpace 被激活,但用户取消操作,则该字段将包含一个空字符串。如果 Windows CardSpace 无法激活,则该字段将包含其初始值“empty”。如果在此页面上选择了 Windows CardSpace 登录选项,则会调用 Windows CardSpaceLogin 方法;这样,您可以检查隐藏字段的值,然后再继续。

当网站收到发回的加密令牌时,您遇到的第一个问题是 ASP.NET 为了降低受脚本攻击的风险,不允许发送 XML 和 HTML 数据。您将收到如下 HttpRequestValidationException:

System.Web.HttpRequestValidationException: A potentially dangerous 
Request.Form value was detected from the client 
(informationCards="<enc:EncryptedData T...").

 

添加以下代码到 web.config 的 <system.web> 部分可以对整个站点禁用此功能:

<pages validateRequest="false"/>

 

在此类情况下,我建议您仅对那些需要接收含有安全令牌的回发的页面应用上述设置。幸运的是,您可以按如下方式对每个页面进行设置:

<%@ Page Language="C#" AutoEventWireup="true" 
         CodeFile="Login.aspx.cs" Inherits="Login" 
         ValidateRequest="false" %>

 

接下来您会遇到另一个问题,即令牌处理代码并未内建在 ASP.NET 中。您必须手动处理 <encryptedData> 元素、解密令牌、验证令牌签名并提取声明,然后才能执行任何身份验证或授权。幸运的是,Microsoft 在 Windows SDK for Windows Vista 和 Windows SDK for .NET Framework 3.0 附带的 Windows CardSpace 示例中提供了一个 TokenProcessor 类的示例(请参阅 msdn2.microsoft.com/aa967562.aspx)。我对此版本的 TokenProcessor 做了少许改动,并将其包含在本文的代码示例中。

要将 TokenProcessor 类用于 ASP.NET 应用程序,只需构建带有 <encryptedData> 元素的类型并访问安全令牌中传递的声明。例如,以下代码用于查找前面所述对象标记要求的 PPID、emailaddress 和 dateofbirth 声明:

using Microsoft.IdentityModel.TokenProcessor;

string token = Request.Form["hiddenXmlToken"] as string;
if (!String.IsNullOrEmpty(token)) {
  Token tokenProcessor = new Token(token);
  string ppid = tokenProcessor.Claims[ClaimTypes.PPID];
  string emailaddress = tokenProcessor.Claims[ClaimTypes.Email];
  string dateofbirth = tokenProcessor.Claims[ClaimTypes.DateOfBirth];
}

 

从一个很高的层面上看,TokenProcessor 工作原理如下。首先使用网站的 SSL 证书对令牌加密。TokenProcessor 使用此证书的指纹找到相关的私钥,默认在 My/LocalMachine 存储区。Web 应用程序主机身份标识(通常为 ASPNET 或 NETWORK SERVICE)必须获得对此私钥的访问权限,否则解密操作将失败。解密的结果随后会转换为 SamlToken 并通过验证,以确保令牌在创建以后其内容未曾被篡改。一旦验证通过,如前所示,您的代码即可使用对令牌及其声明的引用了。

对于个人卡,您的应用程序无法识别对 SAML 令牌进行签名所用的密钥,因为该密钥是个人卡第一次在您的站点上使用时动态生成的。因此,您无法对照受信任的公钥来检查个人卡的签名。但是,如果之前您已将卡与用户帐户建立关联,则可以使用 PPID 的哈希。

对于托管卡,由于 RP 和 IP 之间存在某种关系,因此您应该向 RP 的令牌处理代码添加另一个步骤,以验证该令牌已获得您认可的 IP 的签名。您可以使用 IP 的公钥对签名进行验证。

Back to top

将卡与帐户建立关联

到目前为止,我已经介绍了如何从 ASP.NET 触发 Windows CardSpace,以及如何处理所得到的安全令牌,您可能还想知道应如何处理令牌中的声明。这取决于您网站上要求的卡的类型:个人卡还是托管卡。

支持个人卡的站点这样做主要是为了改善用户的登录体验。如我所述,受支持的声明类型是有限的,尽管相关的人口统计信息可能会对站点有用。也就是说,即使拥有这些声明,也仍然需要进行基于角色的授权。有一种两全其美的方法,就是允许用户将个人卡与其现有帐户建立关联,并在用户使用该卡登录时使用卡来查找用户的角色。

图 13 说明了为实现这一目的,用户、网站和 Windows CardSpace 之间进行的交互。用户可以提前创建个人卡,然后登录到现有帐户,再将卡与帐户建立关联。如果目前还没有满足站点要求的卡,也可以在建立关联期间创建卡。一旦选择了一张个人卡与站点建立关联,由此生成安全令牌将被发送给站点进行处理。当用户使用该卡登录时,安全令牌中包含的声明必须足够充分,以便查找用户帐户。

图 13 将个人卡与网站帐户建立关联
图 13  将个人卡与网站帐户建立关联 (单击该图像获得较大视图)

只有当随令牌提供的电子邮件地址声明与登录用户的电子邮件匹配时,以下代码才会将卡与当前用户帐户建立关联:

MembershipUser user = Membership.GetUser(this.User.Identity.Name);
if (user.Email == emailaddressClaim) {
    user.Comment = ppidClaim;
    Membership.UpdateUser(user);
}

 

此代码使用用户记录的 Comment 字段将卡的 PPID 与用户帐户关联起来。PPID 声明对于卡和它要发送到的 RP 都是唯一的,从而可以唯一地标识用户。(但是请注意,只有首先对令牌的签名进行加密确认和验证,才能依靠 PPID。)

当用户使用个人卡登录时,电子邮件地址声明可用于使用 ASP.NET Membership API 查找用户帐户。Comment 字段中出现匹配的 PPID 表明已经找到正确的用户,如下所示:

MembershipUserCollection matchingUsers = 
    Membership.FindUsersByEmail(emailaddressClaim);
if (matchingUsers.Count > 0) {
    foreach (MembershipUser user in matchingUsers) {
        if (user.Comment == ppid) {
            authenticatedUser = user;
            break;
        }
    }
}

 

找到用户帐户后,即可完成为用户创建验证票证的常见步骤。只要对 RedirectFromLoginPage 进行调用就可以轻松地实现这一点:

FormsAuthentication.RedirectFromLoginPage(
    authenticatedUser.UserName, true);

 

有趣的是,此操作还会在 ASP.NET 会话过程中对用户进行传统的身份验证,这意味着传统的基于角色的安全检查在整个应用程序中也是可以使用的。

托管卡引入了一种稍微不同的工作流程来将卡关联到帐户。将托管卡分发给最终用户的方法很多,其中之一就是允许用户先登录站点,然后再请求卡。然后将卡从站点的登录页面导入到 Windows CardSpace 中,以备稍后使用。图 14 说明了该通信流程。

由于托管卡可以包含几乎任何一组被认为对 IP 和 RP 非常重要的声明,因此它们甚至对授权流程具有更大的意义。RP 收到的一组声明可能表明了应用程序的一系列权限。在这种情况下,由于它依赖于基于角色的安全性,并且不了解声明,因此会跳过 ASP.NET 成员和角色提供程序。

图 14 请求并导入托管卡以登录
图 14  请求并导入托管卡以登录 (单击该图像获得较大视图)
Back to top

将 Windows CardSpace 与 WCF 集成

基于浏览器的应用程序是与 Windows CardSpace 身份验证进行集成的自然之选。Web 服务也可以要求进行 Windows CardSpace 身份验证,以便客户端应用程序可以调用 Windows CardSpace 来以类似的方式颁发安全令牌。

对于 Windows Communication Foundation 来说,通过对服务端点进行配置使用 WSFederationHttpBinding,就可以实现这一点。这将为服务生成安全策略,该安全策略包含在 Web 服务描述语言 (WSDL) 文档中,此文档表明了其需要个人令牌。当 SvcUtil 从此 WSDL 生成 Windows Communication Foundation 代理时,与之匹配的客户端端点也会生成,该端点使用等同的 WSFederationHttpBinding 配置。客户端应用程序使用此代理构建通道来调用服务,而代理负责处理对 Windows CardSpace 的调用,以收集满足目标服务声明的安全令牌。由此产生的交互与图 3 中所示非常相似,其中 RP 为 Windows Communication Foundation 服务,并非 Web 应用程序,客户端应用程序为 Windows Communication Foundation 客户端和代理,而不再是浏览器。

WSFederationHttpBinding 允许您通过依赖于某一 IP 所颁发的令牌的 HTTP 来公开 Windows Communication Foundation 服务。IP 可以为 Windows CardSpace,这时意味着必须提供个人卡或托管卡,以找到颁发实际令牌的相应的 IP。也可以对 IP 进行显式配置,这意味着令牌请求不会通过 Windows CardSpace。鉴于本文的目的,我仅重点讨论 Windows CardSpace 的配置。

WSFederationHttpBinding 的必需参数与用于从 Web 页触发 Windows CardSpace 的对象标记或 XHTML 配置的要求非常类似。您必须指定颁发者、令牌类型以及必需或可选声明的列表。颁发者必须设置为 schemas.xmlsoap.org/ws/2005/05/identity/issuer/self,以触发 Windows CardSpace;令牌格式可以是个人卡或托管卡所支持的任何格式。同样,声明也可以是个人声明或托管声明。这些设置将决定个人卡或托管卡是否能满足安全令牌的请求。

图 15 所示为一个简单 Windows Communication Foundation 服务的一个完整的 <system.serviceModel> 部分,该服务公开了一个 WSFederationHttpBinding 端点。<wsFederationHttpBinding> 部分描述了我刚刚所讲的绑定配置的属性。在此情形下,需要 SAML 1.1 令牌包含 PPID 和电子邮件地址声明。服务还必须提供证书来实现与客户端的安全交换,此证书在 <serviceCertificate> 元素的 <serviceBehavior> 部分中指定。

在使用个人卡时,<issuedTokenAuthentication> 元素中的 allowUntrustedRsaIssuers 设置是非常重要的。默认情况下,该设置为 false。但由于已经使用未知私钥对所得到的令牌进行了签名,因此使用个人卡时必须将其设置为 true。对于托管卡,由于服务很可能会将您接受的任何 IP 的公钥安装到 Trusted People 证书存储区,因此无需将其设置为 true。在使用托管卡的情况下,会对照此受信任的公钥列表对所颁发令牌的签名进行检查。另外还提供自定义的授权选项。

所生成的用于初始化代理的客户端配置与服务配置等同,但有几处例外。客户端需要访问服务公钥,以便对令牌及其与服务的通信进行加密。幸运的是,SvcUtil 可在 <identity> 下生成带客户端端点配置的 base64 编码的公钥版本,以避免将公钥安装到客户端计算机的证书存储区这一步骤。图 16 中显示了此配置。在此图中,由于 <wsFederationHttpBinding> 部分等同于图 15,因此未被展开。客户端代理在构建时使用此信息进行初始化,并通过此信息来确定如何获得安全令牌来对服务进行身份验证。实际上,调用服务的实际代码非常简单,如下所示:

HelloIndigoContractClient proxy = new HelloIndigoContractClient();
string s = proxy.HelloIndigo("Hello");

 

在客户端,Windows Communication Foundation 触发了 Windows CardSpace,因为颁发者设置告诉它使用个人令牌提供程序。只有使用满足绑定内所要求的声明的卡,才会为用户提供身份标识选择界面。当个人卡无法满足令牌类型或所要求的声明时,就需要使用托管卡。

服务器对声明的处理方式是 Windows Communication Foundation 与 ASP.NET 在 Windows CardSpace 身份验证方面的一个巨大不同。与 ASP.NET 不同,通过 Windows CardSpace 颁发的安全令牌被打包放入到发送给服务的 SOAP 消息的安全标头中,作为标头的一部分。在调用服务操作之前,此安全令牌会被解密并进行验证,其声明会提取到服务安全上下文中。这些提取出来的声明被添加到名为 ClaimSet 的抽象中,其中包含了声明列表和有关声明颁发者的信息。对于个人卡,声明是自我颁发的,这意味着您将不会对颁发者的公钥进行授权。这就是将卡的 PPID 声明(它是唯一且保密的)与系统中的帐户关联起来之所以重要的原因所在。您可以检查附加到 AuthorizationContext 的声明集并查找 PPID 声明,看是否存在匹配,然后检查其他预期声明的值,以便进行进一步授权,如图 17 所示。

图 17 中的代码用于检查是否存在来自任何 ClaimSet 的 PPID 和出生日期声明(假定令牌是由个人卡颁发的),然后查找一个出生日期声明来确认调用方的存在时间。附加到 AuthorizationContext 的声明集可以为一个或更多,因为从消息中能够提取出不同的安全令牌,而这些安全令牌会由服务授权策略进行处理。如果颁发者已知并可以被标识,则可以在处理声明之前从特定的颁发者选择正确的 ClaimSet。

使用托管卡会获得更多种可能性,因为声明具有可标识的颁发者。颁发者也由一个 ClaimSet 来描述,该 ClaimSet 通常包含一个具有您接受的 IP 公钥的身份标识声明。您可以按如下所示搜索身份标识声明,并检查它是否为有效的 RSA 声明:

ClaimSet csIssuer = cs.Issuer;
IEnumerable<Claim> issuerClaims = csIssuer.FindClaims(
    ClaimTypes.Rsa, Rights.Identity);
foreach (Claim c in issuerClaims)
{
    System.Security.Cryptography.RSACryptoServiceProvider rsa = 
        c.Resource as RSACryptoServiceProvider;
    if (rsa != null)
    {
        ... // claim exists; check the public key to identify the IP
    }
}

 

一旦您确定所获得的是正确的 ClaimSet,就可以执行基于声明的安全检查了。例如,如果声明基于前面提到的 CRUD 声明,则可以检查是否存在相应操作的创建、读取、更新和删除声明。这样,托管卡不仅能够使用户更加轻松地选择身份标识,并且可以方便地生成很多能够标识用户权限的声明集。服务开发人员可以重点关注基于声明的授权检查,而不是传统的基于角色的安全检查。您可以从以下网址下载一个完整的有关基于声明的安全性的说明性示例:msdn.microsoft.com/msdnmag/code07.aspx

Back to top

总结

将 Windows CardSpace 与您的 ASP.NET 应用程序和 Windows Communication Foundation 服务集成,通过为向受信任的应用程序和服务进行身份验证提供简单、一致的身份标识选择流程,可改善最终用户的体验。尽管个人卡和托管卡提供相同的登录体验,但托管卡具有支持 IP 提供特定声明集的优势,应用程序和服务可利用此声明集更好地标识其系统内用户的权限。本文所讨论的以及在本文示例代码中实现的主题将帮助您从 ASP.NET 或 Windows Communication Foundation 引发 Windows CardSpace 体验。 尽情享受吧!

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值