构建自定义安全令牌服务
[轉(zhuǎn):http://msdn.microsoft.com/zh-cn/magazine/dd347547.aspx]
本文基于 "Geneva" 框架的預(yù)發(fā)布版本撰寫(xiě)而成。所有信息均有可能發(fā)生變更。
本文將介紹以下內(nèi)容:
- 使用 Geneva 框架實(shí)現(xiàn)安全令牌服務(wù)
- 聯(lián)合安全性
- 聲明轉(zhuǎn)換
本文使用了以下技術(shù):
Windows Communication Foundation、ASP.NET、Geneva 框架
代碼下載位置:MSDN 代碼庫(kù)
在線瀏覽代碼
? 目錄
安全令牌服務(wù)入門
構(gòu)建自定義主動(dòng) STS
擴(kuò)展 SecurityTokenService
托管和配置 STS
安全令牌處理程序
構(gòu)建自定義被動(dòng) STS
FederatedPassiveTokenService 控件
SessionAuthenticationModule
用戶身份驗(yàn)證
聲明轉(zhuǎn)換
總結(jié)
Microsoft 基于聲明的訪問(wèn) (CBA) 平臺(tái)戰(zhàn)略(代號(hào)為 "Geneva")包括 "Geneva" 框架、"Geneva" 服務(wù)器和 Windows CardSpace "Geneva"。Geneva 框架可為開(kāi)發(fā)人員提供相關(guān)工具來(lái)構(gòu)建基于聲明的應(yīng)用程序和服務(wù)(這些服務(wù)包括由“安全令牌服務(wù)”(STS) 所頒發(fā)的令牌),還提供相關(guān)工具來(lái)構(gòu)建自定義 STS 和啟用 CardSpace 的 Windows 應(yīng)用程序。雖然 Geneva 服務(wù)器是企業(yè)級(jí) STS,但 Geneva 框架可以為不需要企業(yè)級(jí)功能的環(huán)境構(gòu)建自定義 STS。Windows CardSpace Geneva 由 Windows 客戶端計(jì)算機(jī)中作為標(biāo)識(shí)選擇器和標(biāo)識(shí)提供者的 Windows CardSpace 演變而來(lái)。
在我上一篇介紹 Geneva 框架的文章中,我曾討論過(guò)依靠 STS 頒發(fā)的令牌來(lái)構(gòu)建基于聲明的 Windows Communication Foundation (WCF) 服務(wù)的一種較好方法。在這里,我將使用 Geneva 框架來(lái)構(gòu)建自定義 STS。
在繼續(xù)閱讀本文之前,建議您先閱讀一下由 Keith Brown 和 Sesha Mani 合著的Geneva 框架開(kāi)發(fā)人員白皮書(shū)和我的上一篇文章“Geneva 框架構(gòu)建基于聲明的 WCF 服務(wù)的更好方法”。
安全令牌服務(wù)入門
無(wú)論是基于 Geneva 服務(wù)器的 STS 還是使用 Geneva 框架構(gòu)建的 STS,其主要作用都是作為安全網(wǎng)關(guān)對(duì)調(diào)用方進(jìn)行身份驗(yàn)證,并頒發(fā)附帶描述調(diào)用方聲明的安全令牌。從前面提到的文章中,您應(yīng)該能夠回想起 STS 身份驗(yàn)證支持多種方案:
- 從身份驗(yàn)證機(jī)制中分離出應(yīng)用程序和服務(wù),從而使其能夠?qū)W⒂谑跈?quán)相關(guān)聲明。
- 支持多種憑據(jù)類型,而不會(huì)使應(yīng)用程序和服務(wù)的實(shí)現(xiàn)變復(fù)雜。
- 支持聯(lián)合方案,用戶可以通過(guò)在自身的域中進(jìn)行身份驗(yàn)證來(lái)獲得對(duì)另一個(gè)域中資源的訪問(wèn)權(quán)限(通過(guò)建立不同域的 STS 之間的信任關(guān)系)。
- 簡(jiǎn)化標(biāo)識(shí)委派方案,經(jīng)過(guò)身份驗(yàn)證的用戶將獲得對(duì)下游服務(wù)的訪問(wèn)權(quán)限。
- 簡(jiǎn)化聲明轉(zhuǎn)換,使相關(guān)聲明能夠用于對(duì)應(yīng)用程序和服務(wù)進(jìn)行授權(quán)。
其中的任何方案都可以基于被動(dòng)聯(lián)合(基于瀏覽器)或主動(dòng)聯(lián)合(基于 Windows 客戶端)。下面我將詳細(xì)介紹這些方案,同時(shí)說(shuō)明如何使用 Geneva 框架在自定義 STS 中構(gòu)建相關(guān)邏輯。
在深入探討 STS 的實(shí)現(xiàn)之前,讓我們先來(lái)回顧一些基礎(chǔ)知識(shí)。在主動(dòng)聯(lián)合中使用的 STS 是 WS-Federation 主動(dòng)請(qǐng)求者配置文件(請(qǐng)參閱 WS-Federation TC)和(主要)WS-Trust 規(guī)范(請(qǐng)參閱 WS-Trust 1.3)的實(shí)現(xiàn)。
從較高層次看,WS-Trust 使用四種服務(wù)操作來(lái)描述一個(gè)約定:頒發(fā)、驗(yàn)證、續(xù)訂和取消。客戶端分別調(diào)用這些操作來(lái)請(qǐng)求安全令牌、驗(yàn)證安全令牌、續(xù)訂已過(guò)期的安全令牌以及取消不應(yīng)再繼續(xù)使用的安全令牌。根據(jù) WS-Trust 規(guī)范,每個(gè)操作都必須以“請(qǐng)求安全令牌”(RST) 的格式發(fā)送消息,并以“RST 響應(yīng)”(RSTR) 的格式返回消息。在本文中,我假定頒發(fā)的令牌是“安全聲明標(biāo)記語(yǔ)言”(SAML) 1.1 或 SAML 2.0 令牌。
圖 1 展示了主動(dòng)令牌頒發(fā)時(shí) RST 和 RSTR 的核心內(nèi)容。RST 消息包括請(qǐng)求安全令牌所需的必要信息,其中涉及待頒發(fā)令牌的類型(在本討論中是 SAML)、將要被納入到頒發(fā)令牌中的“依賴方”(RP) 所請(qǐng)求的聲明、有關(guān) RP (AppliesTo) 的信息(包括 URL 和通常用于標(biāo)識(shí) RP 的證書(shū))以及將被用于 RSTR 所返回的“證明密鑰”(proof key) 的可選(未顯示)密鑰材料。
圖 1 主動(dòng)聯(lián)合方案的令牌頒發(fā)
如果令牌頒發(fā)成功,RSTR 將包括頒發(fā)的 SAML 令牌和證明密鑰(假定 STS 決定使用哪個(gè)證明密鑰,因此必須在 RSTR 中返回它)。SAML 令牌將包括已驗(yàn)證方的相關(guān)聲明,它由 STS 簽名來(lái)保護(hù)令牌不被篡改,令牌中將包含用于 RP 加密的證明密鑰,并且它會(huì)為 RP 加密自身以確保只有目標(biāo)接收節(jié)點(diǎn)才能處理該令牌。
客戶端使用證明密鑰來(lái)簽署發(fā)往 RP 的消息。RP 必須能夠在 SAML 令牌中解密證明密鑰,否則拒收該消息。如果令牌中的證明密鑰與消息中的簽名匹配,則證明此次對(duì) RP 的調(diào)用是由請(qǐng)求該令牌的調(diào)用方所發(fā)送的。
被動(dòng)聯(lián)合方案基于 WS-Federation 被動(dòng)請(qǐng)求者配置文件,其中涉及基于瀏覽器的通信。雖然底層消息傳遞仍基于 WS-Trust,但 RST 卻在 STS URL 中被分解為查詢字符串參數(shù),而 RSTR 通常會(huì)作為表單參數(shù)被發(fā)布到 RP。被動(dòng) STS 和 RP 使用聯(lián)合 Web 處理程序來(lái)截取這些參數(shù)。被動(dòng) STS 可以直接處理 WS-Trust 請(qǐng)求,或者將其傳遞到底層 WS-Trust 實(shí)現(xiàn)。圖 2 說(shuō)明了在被動(dòng)聯(lián)合方案中對(duì) RST 和 RSTR 的處理方式。
圖 2 被動(dòng)聯(lián)合方案的令牌頒發(fā)
主動(dòng)與被動(dòng)聯(lián)合方案的一個(gè)本質(zhì)差異在于頒發(fā)的 SAML 令牌的類型。主動(dòng)聯(lián)合通常依靠使用“密鑰所有者”(holder-of-key) 類型主體確認(rèn)的 SAML 令牌,這意味著正如我前面所述,在實(shí)際當(dāng)中存在著一個(gè)證明密鑰,它可以證明發(fā)出令牌進(jìn)行驗(yàn)證的客戶端是請(qǐng)求該令牌(也稱為 ActAs 行為)的主體。被動(dòng)聯(lián)合方案通常涉及帶有“持有者”(bearer) 類型主體確認(rèn)的 SAML 令牌(也稱為持有者令牌)。這種類型的令牌不包含證明密鑰,有時(shí)也稱為無(wú)密鑰令牌。它依靠傳輸來(lái)確保從 STS 獲得該令牌并將其傳遞給 RP。
這些概念(WS-Federation、WS-Trust 和 SAML 令牌)是下面要討論的主題的重要背景信息。首先,我將說(shuō)明如何使用 Geneva 框架來(lái)構(gòu)建主動(dòng) STS。然后,我將討論如何構(gòu)建被動(dòng) STS,最后會(huì)介紹一些它們各自的擴(kuò)展方案。
構(gòu)建自定義主動(dòng) STS
在簡(jiǎn)單的主動(dòng)聯(lián)合方案中(如圖 3 所示),通常存在以下參與者:
- RP,由客戶端調(diào)用的服務(wù)。
- 單獨(dú)的 STS(也作為服務(wù)實(shí)現(xiàn)),支持 WS-Trust 協(xié)議。此 STS 將對(duì)調(diào)用方進(jìn)行身份驗(yàn)證并頒發(fā)具有標(biāo)識(shí)調(diào)用方聲明的安全令牌,也稱為標(biāo)識(shí)提供者或 IP-STS。
- 客戶端,在本例中為基于 Windows 的應(yīng)用程序,它依靠代理對(duì) STS 進(jìn)行身份驗(yàn)證、檢索令牌頒發(fā)結(jié)果以及發(fā)送消息給 RP(它會(huì)提供用于身份驗(yàn)證和授權(quán)的頒發(fā)令牌)。
圖 3 使用單一 RP 和主動(dòng) IP-STS 的簡(jiǎn)單聯(lián)合方案
圖 4 說(shuō)明了在此實(shí)現(xiàn)中可以靈活設(shè)置的部分。其中包括自定義 SecurityTokenService 實(shí)現(xiàn)、使用 ServiceHost 擴(kuò)展 (WSTrustServiceHost) 初始化用于聯(lián)合的運(yùn)行時(shí)、使用 WSTrustContract 類型的派生配置一個(gè)或多個(gè) WS-Trust 端點(diǎn)以及用于標(biāo)識(shí)模型運(yùn)行時(shí)的其他相關(guān)配置設(shè)置。在接下來(lái)的章節(jié)中,我將回顧基于 Geneva 框架的自定義 STS 實(shí)現(xiàn)中的各個(gè)要素。
圖 4 自定義主動(dòng) STS 和主動(dòng) IP-STS 的實(shí)現(xiàn)體系結(jié)構(gòu)
擴(kuò)展 SecurityTokenService
Geneva 框架通過(guò) Microsoft.IdentityModel.SecurityTokenService 命名空間中的 SecurityTokenService 類型為構(gòu)建自定義 STS 提供核心功能。此抽象類擔(dān)負(fù)著傳遞 RST 和 RSTR 消息和生成安全令牌的重任。自定義 STS 類型將繼承該類并提供(至少)以下功能:
- 構(gòu)造函數(shù),用于接受自定義 SecurityTokenServiceConfiguration 實(shí)例以配置 STS 的一些基本功能(稍后討論)。
- GetScope 的重載函數(shù),用于驗(yàn)證請(qǐng)求的目標(biāo) RP,并為該 RP 提供正確的加密憑據(jù)和用于安全令牌的簽名憑據(jù)。
- GetOutputClaimsIdentity 的重載函數(shù),用于為生成的安全令牌提供聲明。
圖 5 顯示了使用此功能實(shí)現(xiàn)的簡(jiǎn)單自定義 STS 的部分代碼。請(qǐng)回想一下在圖 1 和圖 2 中介紹過(guò)的主動(dòng) STS 通信流程。STS 的實(shí)現(xiàn) IdentitySTS 將在調(diào)用 GetScope 時(shí)驗(yàn)證傳入 RST——通過(guò)驗(yàn)證 RST 的 AppliesTo 元素是否確實(shí)指向信任的 URI。假定 STS 管理著一組可為其頒發(fā)令牌的可信 RP 及其證書(shū)。如果 AppliesTo 通過(guò)了驗(yàn)證,GetScope 將把該范圍的 EncryptingCredentials 屬性設(shè)置為正確的證書(shū),在本例中為 "RPKey"。此外,SigningCredentials 屬性也將被設(shè)置為正確的證書(shū),此證書(shū)將被用于為頒發(fā)的令牌簽名。通常情況下,它是 STS 的私鑰,在本例中為 "IPKey"。
? 圖 5 簡(jiǎn)單的自定義 STS 實(shí)現(xiàn)
public class IdentitySTS : SecurityTokenService {public IdentitySTS(SecurityTokenServiceConfiguration config): base( config ){}protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal, RequestSecurityToken request, Scope scope){IClaimsIdentity claimsIdentity = new ClaimsIdentity();claimsIdentity.Claims.Add(new Claim(ClaimTypes.Name, principal.Identity.Name));claimsIdentity.Claims.Add(new Claim(ClaimTypes.Role, "Users"));return claimsIdentity;}protected override Scope GetScope(Microsoft.IdentityModel.Claims.IClaimsPrincipal principal, RequestSecurityToken request){Scope scope = new Scope(request);scope.EncryptingCredentials = this.GetCredentialsForAppliesTo(request.AppliesTo);scope.SigningCredentials = new X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=IPKey"));return scope;}private X509EncryptingCredentials GetCredentialsForAppliesTo(EndpointAddress appliesTo){if (appliesTo == null || appliesTo.Uri ==null || string.IsNullOrEmpty(appliesTo.Uri.AbsolutePath)){throw new InvalidRequestException("AppliesTo must be supplied in the RST.");}X509EncryptingCredentials creds = null;if (appliesTo.Uri.AbsoluteUri.StartsWith("http://localhost:8000/RelyingPartyService")){creds = new X509EncryptingCredentials(CertificateUtil.GetCertificate(StoreName.TrustedPeople, StoreLocation.LocalMachine, "CN=RPKey"));}elsethrow new InvalidRequestException(String.Format("Invalid relying party address: {0}", appliesTo.Uri.AbsoluteUri));return creds;} }當(dāng)調(diào)用 GetOutputClaimsIdentity 時(shí),運(yùn)行時(shí)將傳遞 ClaimsPrincipal 及經(jīng)過(guò)驗(yàn)證的調(diào)用方標(biāo)識(shí)。此標(biāo)識(shí)通常用于決定要授予調(diào)用方的適當(dāng)聲明。在圖 5 中,代碼將為調(diào)用方生成一個(gè)名稱聲明和硬編碼的角色聲明,并會(huì)以 ClaimsIdentity 的形式返回。此 ClaimsIdentity 將向運(yùn)行時(shí)提供待頒發(fā)令牌的聲明。
此 STS 實(shí)現(xiàn)還可以針對(duì)以下功能進(jìn)行擴(kuò)展:
- GetOutputClaimsIdentity 可以包括用于在自定義憑據(jù)存儲(chǔ)庫(kù)中查找用戶及查找其他聲明的代碼。例如,角色列表、有關(guān)用戶的其他相關(guān)詳細(xì)信息(如電子郵件地址),或者代表更精細(xì)應(yīng)用程序權(quán)限(如創(chuàng)建、讀取、更新或刪除)的自定義聲明。
- GetScope 可以在列出所有可信 RP 及其關(guān)聯(lián)證書(shū)的自定義數(shù)據(jù)庫(kù)中查找 AppliesTo URI。
托管和配置 STS
如果熟悉 WCF,那您一定清楚必須配置一個(gè)或多個(gè)端點(diǎn)才能使客戶端將消息發(fā)送到某個(gè)服務(wù)。對(duì)于 STS 而言,將要用于各個(gè)端點(diǎn)的服務(wù)約定必須基于 WS-Trust 協(xié)議,其中包括四個(gè)操作:頒發(fā)、驗(yàn)證、續(xù)訂和取消。事實(shí)上,STS 能夠?qū)崿F(xiàn)兩個(gè)版本的 WS-Trust 協(xié)議:
- WS-Trust 1.3:最新版本的 WS-Trust 規(guī)范。
- WS-Trust 2005 年 2 月:許多行業(yè)合作伙伴在等待標(biāo)準(zhǔn)通過(guò)認(rèn)可期間實(shí)施的 WS-Trust 版本。
您還可以在 SecurityTokenService 類型中提供 GetScope()、GetOutputClaimsIdentity() 等方法的異步實(shí)現(xiàn)。這將提高 I/O 密集型操作(如訪問(wèn)證書(shū)或與聲明數(shù)據(jù)交互)的可伸縮性。為 STS 配置端點(diǎn)時(shí),必須選擇要為端點(diǎn)公開(kāi)的約定。Microsoft.IdentityModel.Protocols 命名空間包括兩個(gè)用于 STS 端點(diǎn)的服務(wù)約定:IWSTrust13SyncContract 和 IWSTrustFeb2005SyncContract。圖 6 顯示了具有兩個(gè)端點(diǎn)的 STS 服務(wù)配置,每個(gè)端點(diǎn)都有一個(gè)約定。請(qǐng)注意還有用于實(shí)現(xiàn)異步代理的異步版本的約定:IWSTrust13AsyncContract 和 IWSTrustFeb2005AsyncContract。
? 圖 6 具有多個(gè) WS-Trust 端點(diǎn)的 STS 服務(wù)配置
<service name="Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract" behaviorConfiguration="stsBehavior"><endpoint address="WSTrustFeb05" binding="wsHttpBinding" contract="Microsoft.IdentityModel.Protocols.WSTrust.IWSTrustFeb2005SyncContract"/><endpoint address="WSTrust13" binding="wsHttpBinding" contract="Microsoft.IdentityModel.Protocols.WSTrust.IWSTrust13SyncContract"/> </service>STS 應(yīng)該基于 WS-Trust 2005 年 2 月的版本公開(kāi)端點(diǎn),以便向后兼容早期的客戶端。實(shí)現(xiàn)這兩種約定的服務(wù)類型是 Microsoft.IdentityModel.Protocols.WSTrust 命名空間中的 WSTrustServiceContract 類型。這是一個(gè)應(yīng)在 STS 的 <service> 配置部分引用的類型。
如圖 4 中的圖表所示,<service> 配置及其端點(diǎn)被用來(lái)使用正確的 WSTrustServiceContract 類型初始化主機(jī)。在主機(jī)初始化期間,還會(huì)使用對(duì)自定義 SecurityTokenService 實(shí)現(xiàn)的引用來(lái)初始化此類型。這就是運(yùn)行時(shí)直接將消息傳遞到自定義 STS 的方式。
在圖 6 中,兩個(gè) STS 端點(diǎn)都依賴于 Windows 憑據(jù)來(lái)驗(yàn)證調(diào)用方(wsHttpBinding 的默認(rèn)行為)。STS 可以使用其他綁定配置來(lái)公開(kāi)多個(gè)端點(diǎn),以便支持不同的憑據(jù)類型。這還包括為每種憑據(jù)類型配置正確的安全令牌處理程序。稍后我將討論令牌處理程序的配置設(shè)置。
Geneva 框架將提供用于托管 STS 實(shí)例的自定義 ServiceHost 類型 WSTrustServiceHost。下面的代碼說(shuō)明了如何在自托管環(huán)境中構(gòu)造 WSTrustServiceHost 類型:
WSTrustServiceHost stsHost = new WSTrustServiceHost(new IdentitySTSConfiguration()); stsHost.Open();WSTrustServiceHost 依賴自定義 SecurityTokenServiceConfiguration 實(shí)例來(lái)初始化 WS-Trust 端點(diǎn)的運(yùn)行時(shí)、啟用 STS 的元數(shù)據(jù)交換行為以及配置元數(shù)據(jù)交換端點(diǎn)。
在 IIS 中托管時(shí),WSTrustServiceHostFactory 類型用于存檔相同的結(jié)果。在 .svc 文件中,@ServiceHost 配置將指定工廠類型和自定義 SecurityTokenServiceConfiguration 類型,如下所示:
<%@ ServiceHost Factory="Microsoft.IdentityModel.Protocols.WSTrust. WSTrustServiceHostFactory" Service="STS.IdentitySTSConfiguration" %>工廠在激活后將使用指定的配置來(lái)初始化 WSTrustServiceHost。
為 STS 初始化 WSTrustServiceHost 時(shí),必須使用自定義的 SecurityTokenServiceConfiguration 類型。圖 7顯示了名為 IdentitySTSConfiguration 的自定義實(shí)現(xiàn)。
? 圖 7 自定義 SecurityTokenServiceConfiguration
public class IdentitySTSConfiguration: SecurityTokenServiceConfiguration {public IdentitySTSConfiguration(): base("http://localhost:8010/sts"){this.TokenIssuerName = "http://localhost:8010/sts";this.SigningCredentials = new X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=IPKey"));this.SecurityTokenService = typeof( IdentitySTS);}}此類型必須為 STS 提供一個(gè) URI、簽名的憑據(jù)以及對(duì)與該配置相關(guān)聯(lián)的 STS 類型的引用。在 STS 頒發(fā)托管卡時(shí),URL 必須有效,否則 Windows CardSpace 將無(wú)法導(dǎo)入這些卡。基類型要求為 TokenIssuerName 的構(gòu)造函數(shù)傳入一個(gè)字符串值,但我建議在代碼中重載它,以便能夠從配置中動(dòng)態(tài)設(shè)置 URI,而不是硬編碼這個(gè)需要傳入構(gòu)造函數(shù)的值。
SecurityTokenServiceConfiguration 類型也公開(kāi)了一些屬性,它們可以用于設(shè)置密鑰大小和令牌類型的默認(rèn)值、禁用對(duì)元數(shù)據(jù)的訪問(wèn)、控制令牌生存期和時(shí)鐘偏差、設(shè)置自定義 RST 和 RSTR 序列化程序、配置用來(lái)驗(yàn)證調(diào)用方的令牌處理程序以及配置 WS-Trust 端點(diǎn)。
下面的示例顯示了如何禁用元數(shù)據(jù)訪問(wèn)以及如何通過(guò)編程方式而不是依賴 <service> 配置設(shè)置來(lái)初始化 WS-Trust 端點(diǎn)(類似于圖 6 中所示):
IdentitySTSConfiguration config = new IdentitySTSConfiguration(); config.DisableWsdl = true; config.TrustEndpoints.Add(new ServiceHostEndpointConfiguration("WSTrustFeb05", new WSHttpBinding(), typeof(IWSTrustFeb2005SyncContract))); config.TrustEndpoints.Add(new ServiceHostEndpointConfiguration("WSTrust13", new WSHttpBinding(), typeof(IWSTrust13SyncContract)));WSTrustServiceHost stsHost = new WSTrustServiceHost(config);基本 SecurityTokenServiceConfiguration 類型還通過(guò)讀取 <microsoft.identityModel> 配置部分來(lái)初始化相關(guān)的 STS 配置設(shè)置。能夠?yàn)樽远x STS 進(jìn)行聲明性配置的設(shè)置包括最大時(shí)鐘偏差、用于身份驗(yàn)證和頒發(fā)的安全令牌處理程序、聲明驗(yàn)證管理器、頒發(fā)者名稱注冊(cè)以及令牌解析程序。圖 8 顯示了一些為 STS 配置的有用設(shè)置。
? 圖 8 STS 的 配置
<microsoft.identityModel><maximumClockSkew value="00:05:00"/><claimsAuthenticationManager type="STS.CustomClaimsAuthenticationManager, STS"/><securityTokenHandlers><remove type="Microsoft.IdentityModel.Tokens.WindowsUserNameSecurityTokenHandler, Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /><add type="Microsoft.IdentityModel.Tokens.MembershipUserNameSecurityTokenHandler, Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"><usernameSecurityTokenHandlerRequirement membershipProvider="CustomProviders.CustomMembershipProvider, CustomProviders, Version=1.0.0.0, Culture=neutral,PublicKeyToken=c03h5a64f15d0b3f" /></add></securityTokenHandlers> </microsoft.identityModel>對(duì)于非 Windows 憑據(jù),會(huì)調(diào)用一種自定義的 ClaimsAuthenticationManager 類型,它可以在 GetOutputClaimsIdentity 中頒發(fā)聲明之前向運(yùn)行時(shí)提供自定義 ClaimsPrincipal 類型。自定義安全令牌處理程序可能被配置為提供一些設(shè)置來(lái)覆蓋特定處理程序的默認(rèn)行為,或更改特定憑據(jù)類型的安全令牌處理程序的選項(xiàng)。
安全令牌處理程序
您可能需要一種服務(wù)行為配置來(lái)確定為每個(gè) STS 端點(diǎn)進(jìn)行身份驗(yàn)證和授權(quán)時(shí)所采用的方式。請(qǐng)回想一下,我在上一篇文章中曾講過(guò) Geneva 框架處理事情的方式略有不同。對(duì)于身份驗(yàn)證來(lái)說(shuō),<securityTokenHandlers> 集合將指定可用于驗(yàn)證傳入請(qǐng)求的 SecurityTokenHandler 類型。
此集合只能為每個(gè) SecurityTokenHandler 類型包含一個(gè)項(xiàng)目。例如,只能為各憑據(jù)類型注冊(cè)一個(gè) KerberosSecurityTokenHandler、UserNameSecurityTokenHandler、X509SecurityTokenHandler、Saml11SecurityTokenHandler 或 Saml2SecurityTokenHandler 來(lái)處理請(qǐng)求。如果 STS 端點(diǎn)需要 UserName 憑據(jù),則默認(rèn)注冊(cè)的 UserNameSecurityTokenHandler 是 WindowsUserNameSecurityTokenHandler。圖 8說(shuō)明了如何刪除 WindowsUserNameSecurityTokenHandler 并添加 MembershipUserNameSecurityTokenHandler 作為其替換處理程序——包括與成員關(guān)系提供者相關(guān)的配置設(shè)置。
您還可以創(chuàng)建自定義 SecurityTokenHandler 類型。請(qǐng)記住,只要它們是從與令牌類別(例如 UserNameSecurityTokenHandler)匹配的相應(yīng)基類派生而來(lái)的,那么您就可以使用新的自定義處理程序來(lái)替換默認(rèn)處理程序。圖 9 說(shuō)明了名為 CustomUserNameSecurityTokenHandler 的自定義 UserNameSecurityTokenHandler 實(shí)現(xiàn)。
? 圖 9 自定義 UserNameSecurityTokenHandler
public class CustomUserNameSecurityTokenHandler: UserNameSecurityTokenHandler {public override ClaimsIdentityCollection ValidateToken(SecurityToken token){UserNameSecurityToken userNameToken = token as UserNameSecurityToken;AuthenticateUser(userNameToken.UserName, userNameToken.Password);return new ClaimsIdentityCollection(new IClaimsIdentity[] {new ClaimsIdentity(new Claim(System.IdentityModel.Claims.ClaimTypes.Name,userNameToken.UserName), "CustomUserNameSecurityTokenHandler")});}public override bool CanValidateToken{get { return true; }} }至少,必須在自定義 SecurityTokenHandler 實(shí)現(xiàn)中重載 ValidateToken 和 CanValidateToken。在 ValidateToken 內(nèi)部,您要負(fù)責(zé)根據(jù)相應(yīng)的憑據(jù)存儲(chǔ)庫(kù)來(lái)驗(yàn)證身份。該驗(yàn)證的結(jié)果應(yīng)該是一組聲明,此聲明可被返回給運(yùn)行時(shí)以便附加到請(qǐng)求線程的 ClaimsPrincipal。
圖 10 使用單一 RP 和被動(dòng) IP-STS 的簡(jiǎn)單聯(lián)合方案
重載 CanValidateToken 并返回 True 也非常重要。如果沒(méi)有這一重載,令牌處理程序?qū)o(wú)法注冊(cè)到集合中,從而無(wú)法被調(diào)用。
構(gòu)建自定義被動(dòng) STS
在簡(jiǎn)單的被動(dòng)聯(lián)合方案中,也存在著與主動(dòng)聯(lián)合方案同樣的參與者(如圖 3 所示),不同之處在于其客戶端是瀏覽器而 RP 是 Web 應(yīng)用程序,另外 IP-STS 還需要作為 Web 應(yīng)用程序的前端以處理基于 HTTP 的通信。圖 10 說(shuō)明了被動(dòng)聯(lián)合的參與者和通信流。
對(duì)于核心 STS 而言,此方案中可以靈活設(shè)置的部分與圖 4 中所示的內(nèi)容相似,但在被動(dòng) STS 對(duì)身份驗(yàn)證的處理方式和對(duì)底層 STS 功能的調(diào)用方式方面也存在著明顯的差異。圖 10 中的圖表從較高級(jí)別說(shuō)明了這些不同之處。被動(dòng) STS 是作為網(wǎng)站來(lái)實(shí)現(xiàn),它需要 SSL 加密以確保令牌頒發(fā)過(guò)程的安全。默認(rèn)頁(yè)面 (Default.aspx) 承載了一個(gè)通過(guò)底層自定義 STS 來(lái)促進(jìn)通信的控件,它的配置過(guò)程與主動(dòng) STS 一樣。
STS 站點(diǎn)必須在令牌頒發(fā)之前驗(yàn)證調(diào)用方,而這正是傳統(tǒng)的 ASP.NET 配置執(zhí)行其驗(yàn)證和授權(quán)功能的地方。在圖 11 中,STS 應(yīng)用程序被配置為用于窗體身份驗(yàn)證,因此如果請(qǐng)求尚未經(jīng)過(guò) FormsAuthenticationModule 的驗(yàn)證,則它們將被重定向到登錄頁(yè)面 (Login.aspx)。
只需進(jìn)行一個(gè)細(xì)微的改動(dòng),被動(dòng) STS 就可以與主動(dòng) STS 共享相同的核心 STS 實(shí)現(xiàn)。在 GetScope 重載函數(shù)中(如圖 5 所示),被動(dòng) STS 必須設(shè)置 ReplyToAddress 屬性,只有這樣 STS 才能在頒發(fā)令牌后重定向。這通常設(shè)置為 RP 的默認(rèn)頁(yè)面(根據(jù)隨 RST 提供的 AppliesTo 地址而定):
Scope scope = new Scope(request); scope.ReplyToAddress = scope.AppliesToAddress + "/default.aspx"; // other scope settings圖 11 使用窗體身份驗(yàn)證的被動(dòng) STS 的實(shí)現(xiàn)體系結(jié)構(gòu)
被動(dòng) STS 的 Geneva 框架配置與主動(dòng) STS 并無(wú)二致。SecurityTokenServiceConfiguration 類型被用于初始化 STS(如圖 7 所示),另外還需要考慮 <microsoft.identityModel> 配置部分中的所有相關(guān)設(shè)置。
FederatedPassiveTokenService 控件
Geneva 框架提供了一個(gè)實(shí)現(xiàn)被動(dòng) STS 必要功能的控件。具體來(lái)說(shuō),它可以處理登錄和注銷 HTTP 請(qǐng)求,并可以將每個(gè)請(qǐng)求轉(zhuǎn)換到 RST 然后再調(diào)用底層 STS 實(shí)現(xiàn)。此控件還處理 RSTR 響應(yīng)和 RP 重定向,并為經(jīng)過(guò)驗(yàn)證的調(diào)用方編寫(xiě)會(huì)話 cookie。
請(qǐng)按照如下方式將此控件放在被動(dòng) STS 站點(diǎn)的默認(rèn)頁(yè)面并將其 Service 屬性設(shè)置為自定義 SecurityTokenServiceConfiguration 實(shí)現(xiàn):
<idfx:FederatedPassiveTokenService ID="FederatedPassiveTokenService1" runat="server" Service="STS.IdentityProviderSTSConfiguration, STS"> </idfx:FederatedPassiveTokenService>此控件要求用戶必須經(jīng)過(guò)身份驗(yàn)證,它會(huì)在其 PreRender 事件中對(duì)此進(jìn)行檢查。需要對(duì) STS 站點(diǎn)進(jìn)行適當(dāng)配置以確保在用戶到達(dá)此默認(rèn)頁(yè)面之前將其重定向到其他頁(yè)面進(jìn)行身份驗(yàn)證。
只要經(jīng)過(guò)身份驗(yàn)證的用戶始終定向到此默認(rèn)頁(yè)面,則無(wú)需其他配置即可處理請(qǐng)求。此控件還提供 Error、PreSignInRequested、PostSignInRequested、PreSignOutRequested 和 PostSignOutRequested 事件來(lái)處理異常以及掛接登錄和注銷請(qǐng)求。
SessionAuthenticationModule
作為 FederatedPassiveTokenService 控件的替代方法,您可以通過(guò)編程方式啟用被動(dòng) STS 功能。首先在 <microsoft.identityModel> 配置部分啟用聯(lián)合驗(yàn)證:
<microsoft.identityModel><federatedAuthentication enabled="true"/> </microsoft.identityModel>然后,為被動(dòng) STS 啟用聯(lián)合模塊,即來(lái)自 Microsoft.IdentityModel.Web 命名空間的 SessionAuthenticationModule 模塊:
<modules><add name="SessionAuthentication" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule,Microsoft.IdentityModel, Version=0.5.1.0,Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </modules>這將得到與 FederatedPassiveTokenService 控件相同的結(jié)果,請(qǐng)求將被發(fā)送到 STS 網(wǎng)站中的任意頁(yè)面。該模塊將把未驗(yàn)證的調(diào)用方重定向到登錄頁(yè)面。成功登錄后,調(diào)用方將被重定向到最初請(qǐng)求的 STS 頁(yè)面。這種編程方法為開(kāi)發(fā)人員提供了除 FederatedPassiveTokenService 控件以外的其他控件。例如,該模塊公開(kāi)了以下事件以便與初始化、安全令牌管理、登錄和注銷進(jìn)行交互:ConfigurationLoading、ConfigurationLoaded、SecurityTokenReceived、SecurityTokenValidated、SessionSecurityTokenCreated、SessionSecurityTokenReceived、SignedIn、SigningOut、SignedOut、SignInError 和 SignOutError。
用戶身份驗(yàn)證
STS 站點(diǎn)負(fù)責(zé)根據(jù)支持的憑據(jù)類型來(lái)驗(yàn)證用戶。雖然使用 WCF 實(shí)現(xiàn)的主動(dòng) STS 能夠輕松配置多個(gè)端點(diǎn)來(lái)支持不同的身份驗(yàn)證機(jī)制,但被動(dòng) STS 只能支持 ASP.NET 網(wǎng)站本身配置的一種身份驗(yàn)證機(jī)制。因此,必須為每種支持的身份驗(yàn)證機(jī)制提供不同的被動(dòng) STS 站點(diǎn)。當(dāng)然,這些站點(diǎn)都可以共享相同的核心 STS 實(shí)現(xiàn)。
被動(dòng) STS 身份驗(yàn)證基于 ASP.NET 配置技術(shù)。典型選項(xiàng)是 Windows 身份驗(yàn)證、窗體身份驗(yàn)證和 Windows CardSpace 身份驗(yàn)證。對(duì)于 Windows 身份驗(yàn)證,將使用以下配置:
<authentication mode="Windows"/> <authorization><deny users="?"/> </authorization>在用戶到達(dá) STS 默認(rèn)頁(yè)面前,會(huì)通過(guò)交互式對(duì)話框?qū)ζ溥M(jìn)行身份驗(yàn)證,因此在這種情況下不需要自定義登錄頁(yè)面。
圖 11 說(shuō)明了使用窗體身份驗(yàn)證的示例。FormsAuthenticationModule 將未驗(yàn)證的調(diào)用重定向到登錄頁(yè)面,在這里用戶可以提供憑據(jù)。通過(guò)驗(yàn)證后,登錄頁(yè)面將重定向到默認(rèn) STS 頁(yè)面,在這里聯(lián)合控件將繼續(xù)處理最初的請(qǐng)求。對(duì)應(yīng)的 ASP.NET 配置如下:
<authentication mode="Forms"/> <authorization><deny users="?"/> </authorization>對(duì)于 Windows CardSpace 身份驗(yàn)證,可以將 STS 站點(diǎn)配置為窗體身份驗(yàn)證,但登錄頁(yè)面將包括一個(gè) InformationCard 控件用于 Windows CardSpace 身份驗(yàn)證。
聲明轉(zhuǎn)換
聲明轉(zhuǎn)換對(duì)于聯(lián)合的安全性至關(guān)重要——它可能在聯(lián)合過(guò)程中的任意時(shí)刻發(fā)生。在 IP-STS 和 RP 屬于同一域的簡(jiǎn)單聯(lián)合方案中,IP-STS 負(fù)責(zé)將聲明從身份驗(yàn)證期間用戶所提供的一組初始身份標(biāo)識(shí)聲明轉(zhuǎn)換為 RP 能夠用以授權(quán)調(diào)用的聲明。用戶可以為 IP-STS 提供任何支持的憑據(jù)類型來(lái)進(jìn)行身份驗(yàn)證,其中每個(gè)都會(huì)評(píng)估一組代表該憑據(jù)的聲明。
IP-STS 將這些聲明轉(zhuǎn)換成一組標(biāo)準(zhǔn)的應(yīng)用程序聲明,RP 可以通過(guò)這組聲明授權(quán)調(diào)用——它們可以是角色或更精細(xì)的聲明,如創(chuàng)建、讀取、更新或刪除等權(quán)限。圖 12 中的圖表對(duì)這種方案進(jìn)行了說(shuō)明,其中 Admin 用戶登錄并被授予 Role 聲明和幾項(xiàng) Action 聲明,其中包括創(chuàng)建、讀取、更新和刪除等。
圖 12 IP-STS 聲明轉(zhuǎn)換
這種類型的聲明轉(zhuǎn)換非常有用,因?yàn)閷?duì) STS 的身份驗(yàn)證會(huì)得到一個(gè)令牌,其中包含授予該用戶的所有聲明。也有一些情況需要使用其他方法進(jìn)行聲明轉(zhuǎn)換;例如為了減少頒發(fā)給那些僅與當(dāng)前調(diào)用上下文相關(guān)的聲明、為了保護(hù)聲明的隱私性,或者為了促進(jìn)跨域聯(lián)合等。
向經(jīng)過(guò)驗(yàn)證的調(diào)用方授予與 RP 公開(kāi)的所有功能相關(guān)的完整聲明列表既無(wú)必要,有時(shí)可能也并不合適。這不但會(huì)使列表變得非常長(zhǎng),而且還可能待授予的聲明取決于調(diào)用上下文,因此在不具備該上下文的情況下不應(yīng)授予該聲明。例如,如果某用戶正在與客戶進(jìn)行訂單交互,則只授予 Delete 聲明即可,但如果他正直接與客戶記錄交互,則不應(yīng)授予該權(quán)限。
在其他一些類似情況中,如果 RP 能夠只從 IP-STS 請(qǐng)求少量聲明即可標(biāo)識(shí)調(diào)用方,然后使用一組特定的僅適用于該調(diào)用上下文的附加聲明來(lái)請(qǐng)求一個(gè)新令牌,則將會(huì)非常有幫助。例如,如果用戶正在 RP 服務(wù)中調(diào)用 DeleteCustomer 操作,在授權(quán)執(zhí)行此操作之前,RP 將會(huì)調(diào)用從 IP-STS 傳入令牌的 RP-STS,并在 DeleteCustomer 操作的上下文中請(qǐng)求 Delete 聲明。如果該聲明存在,則調(diào)用將獲得授權(quán)。圖 13 中的圖表進(jìn)一步說(shuō)明了此示例。
此外,有時(shí)還存在 STS 頒發(fā)的聲明不應(yīng)與 RP 直接共享的情況。例如,可以不必通過(guò)頒發(fā) Age 聲明來(lái)使 RP 了解用戶的年齡,RP 可以請(qǐng)求 IsOver13 聲明來(lái)確保調(diào)用方的年齡符合使用 RP 功能的條件。這樣可以確保 Age 聲明的實(shí)際值不會(huì)離開(kāi) STS。當(dāng)然,這也表明 ST 將提供既能避免共享個(gè)人詳細(xì)信息又可以包含 RP 所需數(shù)據(jù)的聲明。
圖 13 RP-STS 聲明轉(zhuǎn)換
當(dāng)屬于一個(gè)域的用戶被授予對(duì)另一個(gè)域中的 RP 的訪問(wèn)權(quán)限時(shí),聯(lián)合方案中也會(huì)發(fā)生聲明轉(zhuǎn)換。在這種情況下會(huì)涉及兩個(gè) STS——用戶域的 IP-STS 和 RP 所屬域的 RP-STS。
同樣也是在這種情況下,IP-STS 會(huì)授予一些 RP-STS 能夠理解且達(dá)成一致的聲明;但這些聲明可能無(wú)法在 RP 應(yīng)用程序中直接使用。相反,RP-STS 可能會(huì)負(fù)責(zé)將另一組可信聲明轉(zhuǎn)換為能夠被 RP 域所理解的聲明。
圖 14 說(shuō)明了這種方案。當(dāng) Joe 試圖在沒(méi)有令牌的情況下訪問(wèn) RP 時(shí),他將登錄到自己所在域(域 B)的 IP-STS。該請(qǐng)求將申請(qǐng) RP 能夠理解的聲明(在本例中為 RPClaim),以便 IP-STS 知道應(yīng)該頒發(fā) RP 能夠使用的令牌。當(dāng) RP-STS 接收到此令牌后,它將把該聲明轉(zhuǎn)換為 RP 專用的聲明。為了使此聯(lián)合方案能夠工作,必須在 RP-STS 和 IP-STS 之間建立信任關(guān)系,而且它們必須對(duì) IP-STS 應(yīng)該為其用戶頒發(fā)的將被授予對(duì) RP 訪問(wèn)權(quán)限的一組聲明達(dá)成一致。
圖 14 聯(lián)合方案中的聲明轉(zhuǎn)換
總結(jié)
對(duì)于那些熱衷于構(gòu)建自定義 STS 而又不需要 STS 平臺(tái)全部功能(如 Geneva 服務(wù)器)的用戶而言,Geneva 框架是一種非常受歡迎的實(shí)用工具。但即便使用 Geneva 框架,構(gòu)建自定義 STS 也不是一項(xiàng)簡(jiǎn)單的任務(wù),強(qiáng)烈建議您盡量使用完整功能的 STS 以減少出現(xiàn)安全漏洞的風(fēng)險(xiǎn)。
無(wú)論使用什么平臺(tái),主動(dòng)和被動(dòng) STS 實(shí)現(xiàn)的通信流程都是一致的,并且聲明轉(zhuǎn)換的原理也相同。與 STS 實(shí)現(xiàn)相關(guān)的其他概念還包括標(biāo)識(shí)委派和逐級(jí)驗(yàn)證。您可以在 Geneva 框架 SDK 中找到與這些及其他概念相關(guān)的示例和文檔。
Michele Leroux Bustamante 是 IDesign Inc. 的首席架構(gòu)師、圣地亞哥的 Microsoft 區(qū)域總監(jiān)和互聯(lián)系統(tǒng)的 Microsoft MVP。她的最新著作是《學(xué)習(xí) WCF》。可通過(guò) mlb@idesign.net 或訪問(wèn) idesign.net與她取得聯(lián)系。Michele 的博客網(wǎng)址是 dasblonde.net。
轉(zhuǎn)載于:https://www.cnblogs.com/frankzye/archive/2013/03/20/2971132.html
總結(jié)
以上是生活随笔為你收集整理的构建自定义安全令牌服务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 王朔:我看鲁迅
- 下一篇: 假期读好书——力荐《八位大学校长》