[WCF權(quán)限控制]從兩個(gè)重要的概念談起:Identity與Principal[上篇]
在安全領(lǐng)域,認(rèn)證和授權(quán)是兩個(gè)重要的主題。認(rèn)證是安全體系的第一道屏障,守護(hù)著整個(gè)應(yīng)用或者服務(wù)的第一道大門。當(dāng)訪問(wèn)者叩門請(qǐng)求進(jìn)入的時(shí)候,認(rèn)證體系通過(guò)驗(yàn)證對(duì)方提供憑證確定其真實(shí)身份。作為看門人的認(rèn)證體系,只有在證實(shí)了訪問(wèn)者的真實(shí)身份的情況下才會(huì)為其打開(kāi)城門,否則將之舉之門外。
當(dāng)訪問(wèn)者入門之后,并不意味著它可以為所欲為。為了讓適合的人干適合的事,就需要授權(quán)機(jī)制為具體的人設(shè)置具體的權(quán)限,并根據(jù)這些權(quán)限設(shè)置決定試圖調(diào)用的操作或者訪問(wèn)的資源對(duì)該訪問(wèn)者是否是安全的。對(duì)于一個(gè)安全保障體系來(lái)說(shuō),授權(quán)是目的。但是授權(quán)的執(zhí)行是假定已經(jīng)通過(guò)認(rèn)證體現(xiàn)確定了訪問(wèn)者真實(shí)身份,因?yàn)橛糜谶M(jìn)行授權(quán)采用的權(quán)限集是基于真?zhèn)€確定的身份的。在真正進(jìn)入對(duì)WCF授權(quán)的具體介紹之前,我們有必要來(lái)了解一下這個(gè)“身份”的問(wèn)題。
目錄
一、IIdentity
二、WinodwsIdentity
三、GenericIdentity
四、X509Identity
五、服務(wù)安全上下文中的身份
一、IIdentity
在.NET的安全應(yīng)用編程接口中,身份通過(guò)System.Security.Principal.IIdentity接口表示。從下面表示IIdentity接口定義的代碼片斷中,我們可以看到這個(gè)接口定義其實(shí)很簡(jiǎn)單,它具有如下三個(gè)只讀屬性:
- Name:身份所代表的用戶的名稱;
- IsAuthenticated:身份所代表的用戶是否經(jīng)過(guò)認(rèn)證;
- AuthenticationType:身份認(rèn)證所采用的類型。
1: public interface IIdentity
2: {
3: string AuthenticationType { get; }
4: bool IsAuthenticated { get; }
5: string Name { get; }
6: }
通過(guò)IIdentity表示的身份是基于某種認(rèn)證類型的,不同類型的認(rèn)證往往對(duì)應(yīng)于不同的身份類型。以ASP.NET認(rèn)證為例,如果我們采用Forms認(rèn)證,那么認(rèn)證后的身份通過(guò)一個(gè)FormsIdentity對(duì)象表示。而Windows Live Passport認(rèn)證對(duì)應(yīng)的具體身份類型則是PassportIdentity。在這里我們著重介紹一下如下三種身份類型:WindowsIdentity、GenericIdentity和X509Identity。
二、WindowsIdentity
WindowsIdentity定義在System.Security.Principal命名空間下。顧名思義,WindowsIdentity用于表示一個(gè)基于Windows認(rèn)證的身份。一個(gè)采用WindowsIdentity定義的Windos身份具有一系列的屬性,它們主要定義在如下的代碼片斷中。
1: public class WindowsIdentity : IIdentity, ...
2: {
3: //其他成員
4: public virtual string Name { get; }
5: public string AuthenticationType { get; }
6:
7: public virtual bool IsAuthenticated { get; }
8:
9: public IdentityReferenceCollection Groups { get; }
10: public virtual bool IsAnonymous { get; }
11: public virtual bool IsGuest { get; }
12: public virtual bool IsSystem { get; }
13: }
對(duì)于用于表示認(rèn)證類型的AuthenticationType屬性來(lái)說(shuō),在工作組模式下返回NTLM。對(duì)于域模式,如果操作系統(tǒng)是Vista或者以后的版本,該屬性返回Negotiate,表示采用SPNEGO認(rèn)證協(xié)議。而對(duì)于之前的Windows版本,則該屬性值為Kerberos。
Groups屬性返回WindowsIdentity對(duì)應(yīng)的Windows帳號(hào)所在的用戶組(User Group),而IsGuest則用于判斷Windows帳號(hào)是否存在于Guest用戶組中。IsSystem屬性則表示W(wǎng)indows帳號(hào)是否是一個(gè)系統(tǒng)帳號(hào)。
如果你對(duì)ASP.NET的安全有一定的了解,應(yīng)該知道我們可以對(duì)IIS進(jìn)行相應(yīng)的配置是ASP.NET應(yīng)用支持匿名用戶。也就是說(shuō),用戶無(wú)需提供具體的用戶憑證,而是以匿名的方式登錄到ASP.NET站點(diǎn)中。對(duì)于匿名登錄,IIS實(shí)際上會(huì)采用一個(gè)預(yù)先指定的Windows帳號(hào)進(jìn)行登錄。而在這里,IsAnonymous屬性就表示該WindowsIdentity對(duì)應(yīng)的Windows帳號(hào)是否是匿名帳號(hào)。
對(duì)于匿名身份的問(wèn)題,在這里還有一點(diǎn)值得補(bǔ)充一下。WindowsIdentity定義了如下一個(gè)靜態(tài)的GetAnonymous方法用于返回一個(gè)表示匿名身份的WindowsIdentity對(duì)象。但是這僅僅是一個(gè)空的WindowsIdentity對(duì)象而以,并不對(duì)應(yīng)著某個(gè)確定的Windows帳號(hào)。
1: public class WindowsIdentity : IIdentity, ...
2: {
3: //其他成員
4: public static WindowsIdentity GetAnonymous()
5: }
任何一個(gè)具體的Windows進(jìn)程總是運(yùn)行在一個(gè)確定的安全身份下。如果你手工啟動(dòng)一個(gè).exe文件,被開(kāi)啟的進(jìn)程會(huì)運(yùn)行在基于當(dāng)前登錄帳號(hào)的身份下。如有你同時(shí)擁有多個(gè)Windows帳號(hào),你可以通過(guò)“Run As”的方式選擇一個(gè)不同于當(dāng)前登錄帳號(hào)的身份去運(yùn)行某個(gè).exe文件。而對(duì)于很多的Windows服務(wù),它們大多運(yùn)行在某個(gè)系統(tǒng)帳號(hào)下。比如我們熟悉的IIS(IIS6或者之后的版本)在默認(rèn)的情況下就運(yùn)行在Network Service這個(gè)系統(tǒng)帳號(hào)下面。當(dāng)一個(gè)線程在這個(gè)進(jìn)程中被創(chuàng)建并啟動(dòng)的時(shí)候,進(jìn)程的安全身份會(huì)自動(dòng)附加到線程上。WindowsIdentity為我們提供了如下一個(gè)GetCurrent靜態(tài)方法返回基于當(dāng)前線程/進(jìn)程的WindowsIdentity。
1: public class WindowsIdentity : IIdentity, ...
2: {
3: //其他成員
4: public static WindowsIdentity GetCurrent();
5: }
三、 GenericIdentity
雖然對(duì)于這些我們常用的認(rèn)證類型,比如Windows認(rèn)證、Forms認(rèn)證和Windows Live Passport認(rèn)證,都具有對(duì)應(yīng)的安全身份類型。如果我們采用自定義的認(rèn)證方式,是否意味著我們也需要定義一個(gè)實(shí)現(xiàn)了IIdentity接口的類型呢?實(shí)際上是不需要的,我們可以直接使用GenericIdentity這個(gè)類型。
正如名稱所體現(xiàn)的一樣,GenericIdentity為我們定義了一個(gè)一般性的安全身份。GenericIdentity的定義非常簡(jiǎn)單,僅僅實(shí)現(xiàn)了定義在IIdentity接口的三個(gè)只讀屬性而以。我們可以通過(guò)指定用戶名或者用戶名與認(rèn)證類型來(lái)創(chuàng)建一個(gè)GenericIdentity對(duì)象。下面的代碼片斷體現(xiàn)了GenericIdentity的整個(gè)定義。
1: public class GenericIdentity : IIdentity
2: {
3: public GenericIdentity(string name);
4: public GenericIdentity(string name, string type);
5:
6: public virtual string AuthenticationType { get; }
7: public virtual bool IsAuthenticated { get; }
8: public virtual string Name { get; }
9: }
由于GenericIdentity的IsAuthenticated屬性是只讀,也不同通過(guò)存儲(chǔ)過(guò)程對(duì)其進(jìn)行初始化,那么如何確定一個(gè)通過(guò)GenericIdentity對(duì)象表示的安全身份是否已經(jīng)通過(guò)認(rèn)證了呢?實(shí)際上,GenericIdentity采用很簡(jiǎn)單的邏輯來(lái)判斷其自身是否經(jīng)過(guò)認(rèn)證:如果用戶名不為空,IsAuthenticated返回True,否則返回False。下面給出的代碼可以驗(yàn)證這一點(diǎn)。
1: var anonymousIdentity = new GenericIdentity("");
2: var authenticatedIdentity = new GenericIdentity("Foo");
3: Debug.Assert(anonymousIdentity.IsAuthenticated == false);
4: Debug.Assert(authenticatedIdentity.IsAuthenticated == true);
四、X509Identity
通過(guò)前面一章的介紹,我們知道了WCF具有三種典型的認(rèn)證方式:Windows認(rèn)證、用戶名/密碼認(rèn)證和證書認(rèn)證。認(rèn)證的方式?jīng)Q定了安全身份的類型,對(duì)于Windows認(rèn)證和用戶名/密碼認(rèn)證,認(rèn)證后的安全身份分別由一個(gè)WindowsIdentity和GenericIdentity表示。但是對(duì)于證書認(rèn)證,則對(duì)應(yīng)著另一種安全身份類型:X509Identity。
X509Identity定義在程序集System.IdentityModel中,對(duì)應(yīng)的命名空間是System.IdentityModel.Claims。從下面給出的定義我們可以看出X509Identity僅僅是一個(gè)內(nèi)部(Internal)類型。
1: internal class X509Identity : GenericIdentity, IDisposable
2: {
3: //其他成員
4: public X509Identity(X500DistinguishedName x500DistinguishedName);
5: public X509Identity(X509Certificate2 certificate);
6:
7: public X509Identity Clone();
8: public void Dispose();
9: public override string Name { get; }
10: }
X509Identity直接繼承自GenericIdentity。我們可以通過(guò)傳入一個(gè)X509Certificate2對(duì)象或者以X500DistinguishedName對(duì)象表示的證書的標(biāo)識(shí)名稱來(lái)創(chuàng)建X509Identity。X509Identity重寫了GenericIdentity的Name屬性,最終作為名稱的返回的是證書的主題名稱和指紋的組合,<<主題名稱>>; <<指紋>>(分號(hào)之后具有一個(gè)空格,比如:CN=Foo; 12BA3675C89BD7FE00E3F7E92A620749FB9E6D89)。X509Identity對(duì)象的AuthenticationType屬性為“X509”。
五、服務(wù)安全上下文中的身份
當(dāng)服務(wù)安全開(kāi)始的情況,服務(wù)端在經(jīng)過(guò)認(rèn)證之后會(huì)創(chuàng)建一個(gè)上下文用以存儲(chǔ)基于當(dāng)前服務(wù)調(diào)用相關(guān)的安全相關(guān)的信息,其中就包含了代表被認(rèn)證客戶端的安全身份。這個(gè)上下文被稱為服務(wù)安全上下文,通過(guò)類型ServiceSecurityContext表示。
1: public class ServiceSecurityContext
2: {
3: //其他成員
4: public static ServiceSecurityContext Current { get; }
5: public IIdentity PrimaryIdentity { get; }
6: public WindowsIdentity WindowsIdentity { get; }
7:
8: public bool IsAnonymous { get; }
9: public static ServiceSecurityContext Anonymous { get; }
10: }
你可以通過(guò)兩種方式獲取當(dāng)前的ServiceSecurityContext,一種是通過(guò)ServiceSecurityContext的靜態(tài)只讀屬性Current,另一種則是通過(guò)當(dāng)前OperationContext的ServiceSecurityContext屬性。實(shí)際上通過(guò)這兩種方式得到的是同一個(gè)ServiceSecurityContext。ServiceSecurityContext對(duì)象的同一性可以通過(guò)下面的代碼來(lái)驗(yàn)證。
1: var securityContext1 = OperationContext.Current.ServiceSecurityContext;
2: var securityContext2 = ServiceSecurityContext.Current;
3: Debug.Assert(object.ReferenceEquals(securityContext1, securityContext2));
ServiceSecurityContext具有兩個(gè)表示安全身份的屬性PrimaryIdentity和WindowsIdentity,它們都代表當(dāng)前客戶端的身份。對(duì)于Windows認(rèn)證,這兩個(gè)屬性返回同一個(gè)WindowsIdentity對(duì)象。不過(guò)需要注意的是,這是所說(shuō)的Windows認(rèn)證實(shí)際上包括如下三種情況:
- 客戶端憑證為Windows憑證;
- 客戶端憑證為用戶名/密碼憑證,并采用Windows認(rèn)證模式;
- 客戶端憑證為X.509證書憑證,并允許與Windows帳號(hào)進(jìn)行映射。
而對(duì)于不屬于上述三種情況下的非Windows憑證,當(dāng)前ServiceSecurityContext的WindowsIdentity屬性返回Null,而PrimaryIdentity屬性則因客戶端憑證類型和認(rèn)證方式有所區(qū)別。具體來(lái)說(shuō),如果客戶端憑證為用戶名/密碼憑證,并采用Membership和Custom認(rèn)證模式,則在成功認(rèn)證的情況下PrimaryIdentity的屬性返回一個(gè)以用戶名作為名稱的GenericIdentity。如果客戶端憑證為X.509證書憑證,但不采用Windows帳號(hào)映射機(jī)制,則PrimaryIdentity的屬性返回的是一個(gè)X509Identity。
對(duì)于匿名客戶端(客戶端憑證類型為None),PrimaryIdentity返回的是一個(gè)空的GenericIdentity,IsAnonymous返回True。你通過(guò)靜態(tài)屬性Anonymous可以返回一個(gè)匿名ServiceSecurityContext。下滿的表格體現(xiàn)了成功認(rèn)證后當(dāng)前ServiceSecurityContext的PrimaryIdentity與客戶端憑證類型以及認(rèn)證模式之間的關(guān)系。
從兩個(gè)重要的概念談起:Identity與Principal[上篇]
從兩個(gè)重要的概念談起:Identity與Principal[下篇]


我們?yōu)閼?yīng)用建立安全保障體系的一個(gè)重要的目的在于:通過(guò)權(quán)限控制讓用戶只能執(zhí)行被允許的功能,訪問(wèn)被許可的資源。這就是本系列文章討論的主題授權(quán)。對(duì)于WCF服務(wù)來(lái)說(shuō),一個(gè)服務(wù)具有若干操作,而這些操作由于提供的功能或者內(nèi)部訪問(wèn)的資源不同,需要進(jìn)行相應(yīng)的授權(quán)。在正式介紹WCF授權(quán)之前,先來(lái)談?wù)剝蓚€(gè)重要的概念:身份與安全主體。

浙公網(wǎng)安備 33010602011771號(hào)