擴展JAAS
Extending JAAS
Guosheng Huang, PhD, is a seniorsoftware developer withWysdom Inc. He has over 15years of experience in software engineering and technical architecture. gorsenhuang@yahoo.com
翻譯:綠野風(fēng)煙 2003/10
用戶(hù)認證和訪(fǎng)問(wèn)控制是大多數java應用的重要安全尺度,特別是J2EE應用。Java認證和權限服務(wù)(即JAAS),J2SE1.4和1.5的核心API,描繪表達了新的安全標準。其提供了一個(gè)可插拔的(pluggable)和富有彈性的(flexible)框架(framework)允許開(kāi)發(fā)者混合不同的安全機制和豐富的已經(jīng)存在各種安全方面的資源。
伴隨著(zhù)即將來(lái)臨的J2SE1.5版本的發(fā)布,它包含了許多諸如加密技術(shù)、XML安全性、公鑰機制(PKI)、Kerberos (是一個(gè)網(wǎng)絡(luò )附加系統/協(xié)議,可以允許用戶(hù)通過(guò)一個(gè)安全伺服器的服務(wù)來(lái)驗證 自己。象遠端登陸,遠端拷貝,系統間的相互檔拷貝和另外高風(fēng)險任務(wù)的服務(wù)將被變 得相當安全和可控制。)和結盟認證(the federating identity)的增強!,JAAS將會(huì )在J2EE實(shí)現中扮演一個(gè)更加重要的角色。
認證
認證就是校驗一個(gè)用戶(hù)擁有使用已經(jīng)被企業(yè)用戶(hù)注冊機構證明了的身份鑒定的權限的處理過(guò)程。JAAS的認證機制建立于一整套可插拔的模塊(參看圖1)基礎上。JAAS允許不同的驗證模型在運行時(shí)可被插拔??蛻?hù)應用總是通過(guò)登陸上下文對象和JAAS交互。
認證處理過(guò)程典型的要經(jīng)過(guò)下面的步驟:
1、 生成一個(gè)LoginContext對象。這個(gè)LoginContext尋找配置文件以決定使用那個(gè)LoginModule。同樣,可選擇的,有可能傳遞一個(gè)CallbackHandler給LoginContext.
2、 通過(guò)調用LoginContext的login方法執行認證,它會(huì )加載預定義的LoginModule去檢驗是否用戶(hù)可以被認證。
3、 如果用戶(hù)被認證,那么用規則和標識和其所屬項進(jìn)行關(guān)聯(lián)。
4、 或者在登陸失敗的情況下跑出一個(gè)LoginException
5、 使用LoginContext的logout方法進(jìn)行注銷(xiāo)登陸
在JAAS中,登陸是一個(gè)兩階段(two-phase)的處理過(guò)程。第一階段是“登陸(login)”階段(就像上面2所描述的)。這個(gè)階段唯一的任務(wù)是認證。只要處理過(guò)程成功通過(guò)這個(gè)階段,認證處理過(guò)程就進(jìn)入了“提交(commit)”階段(如上步驟3),這一階段LoginModule的commit方法被調用去關(guān)聯(lián)所屬子項相關(guān)的規則和標識。
在JAAS中一個(gè)所屬子項表示一個(gè)認證實(shí)體,比如一個(gè)人或者一臺設備。它包含了一整套法則和安全相關(guān)的屬性諸如密碼和加密密鑰。在JAAS體系結構中,所屬子項和其所附屬的相關(guān)權限,扮演了重要的角色在認證過(guò)程當中。所有的認證模塊當中,LoginModule是事實(shí)上的認證機制的借口。雖然LoginModule決沒(méi)有得到直接調用客戶(hù)應用的機會(huì ),但是他經(jīng)由一個(gè)可插拔的模塊提供了一個(gè)認證的具體類(lèi)型,其實(shí)現了認證的算法并且決定實(shí)際的認證過(guò)程是怎樣被執行的。
SUN提供了幾個(gè)默認的LoginModule 實(shí)現,在sun.com.security.auth.module包里有諸如JndiLoginModule,Krb2LoginModule,UnixLoginModule和NTLoginModule等幾個(gè)LoginModule實(shí)現。因為JAAS登錄結構體系是可擴展的,所以你只要在配置文件中指定使用哪個(gè)LoginModule模塊就可以幾乎全部插入任何LoginModule模塊。
如下即為一個(gè)配置文件的例子:
這里MySample是登錄上下文環(huán)境(login context)的名字,當你生成一個(gè)新的LoginContext開(kāi)始認證過(guò)程時(shí)它會(huì )被傳入LoginContex的構造函數中。依據配置塊提示,那個(gè)文本塊提醒JAAS有關(guān)LoginModule在登錄過(guò)程中應該被用來(lái)執行認證。另外,對于LoginModule,任何關(guān)于他的選項也可以在這里被指定。在執行登錄這一步驟的過(guò)程中,CallbackHandler類(lèi)被LoginModule類(lèi)用來(lái)跟用戶(hù)通信已便于取得認證信息。CallbackHandler類(lèi)處理三種類(lèi)型的回調(Callback):NameCallback,提示用戶(hù)輸入一個(gè)用戶(hù)名;PasswordCallcack,提示輸入密碼;TextOutputCallback,報告錯誤、警告或則發(fā)送給用戶(hù)一些其他信息。
授權是決定是否認證的用戶(hù)可以執行一些動(dòng)作的工作,例如訪(fǎng)問(wèn)一處資源。因為JAAS建立于已經(jīng)存在的Java安全模型的基礎上,故這個(gè)過(guò)程時(shí)基于策略的。策略配置文件實(shí)質(zhì)上包含了一系列的入口,諸如“Keystore”和/或“grant”.
grant入口包含了所有的權限,他是通過(guò)認證的代碼或則法則被授予可以進(jìn)行安全敏感的操作,例如,訪(fǎng)問(wèn)一個(gè)具體的Web頁(yè)面或則本地的文件。JAAS支持基于法則的策略入口,賦權入口基本格式如下:
上面格式中“動(dòng)作(action)”可能是必需的或則可能被忽略依賴(lài)于權限類(lèi)型。在JAAS體系結構中,策略對象表達了一個(gè)Java應用環(huán)境的系統安全策略和在任何時(shí)間事實(shí)上只有一個(gè)策略對象。依據Java2 SDK文檔,默認的策略實(shí)現是sun.security.provider.PolicyFile,其中策略被指定在一個(gè)或多個(gè)策略配置文件里。
只要用戶(hù)被認證,授權經(jīng)由Subject.doAs方法發(fā)生,或者從Subject類(lèi)的靜態(tài)方法doAsPrivileged,doAS方法用當前的AccessControlContext動(dòng)態(tài)和子項并且同時(shí)調用run方法去執行動(dòng)作,他導致安全驗證。權限驗證過(guò)程通過(guò)下面的步驟在圖2:
就像LoginModule,策略也是可插拔的模型。你可以?huà)焐掀渌牟呗詫?shí)現通過(guò)在java.security的屬性文件中改變“policy.provider=sun.security.provider.PolicyFile”
到一個(gè)你項使用的策略類(lèi)。
Extend JAAS
JAAS建立于已經(jīng)存在的Java安全模型的頂端,其基于“CodeSource”和平面文本格式策略文件實(shí)現。這可能對企業(yè)應用是不夠用的,你可能想使用可定制的安全倉庫。對于JAAS的其它實(shí)現,諸如LDAP(輕型目錄訪(fǎng)問(wèn)協(xié)議),數據庫或者其他文件系統,它可以通過(guò)編寫(xiě)你自己的可定制模塊被完成,感謝JAAS的可插拔的特性。然而,這需要對模塊和JAAS中的處理過(guò)程有完善的理解,同時(shí)你必須做許多編碼去覆寫(xiě)相關(guān)的類(lèi),并且處理好配置和策略?xún)煞N文件。
理想情況下,我們愿意能夠擴展JAAS以一個(gè)更加容易的方式以便于無(wú)論何時(shí)一個(gè)可定制的安全知識庫或者不同的訪(fǎng)問(wèn)控制機制改變或者必須去增加時(shí),你能夠只開(kāi)發(fā)和插入這些不同的小模塊(即,適配器)去適應這些新的變化和需求,并且在最好的情況下,不必去理解和熟悉JAAS處理過(guò)程的細節,同樣,我們也愿意能夠去做這些變化僅僅通過(guò)改變一個(gè)配置文件。另一個(gè)目標是我們的JAAS擴展組件能夠被使用在不同的J2EE應用中—獨立的或者Web上的。圖3描述了JAAS擴展組件的設計意圖。我們的JAAS擴展組在實(shí)現可定制的LoginModule和策略模塊時(shí)充分件利用了JAAS插拔式的體系結構。這些模塊中,我們委派數據請求到適配器。這些適配器的每個(gè)對于諸如數據取回的簡(jiǎn)單任務(wù)是隔離的,所以你可以快速地使用不同的安全知識或者算法開(kāi)發(fā)不同的適配器而不是嘗試去實(shí)現不同的LoginModule或者策略模塊,它們更加復雜并且需要更多的努力。
你可以從www.sys-con.com/java/sourcec.cfm.下在完整的源瑪。
實(shí)現的AuthLoginModule類(lèi)
AuthLoginModule類(lèi)是我們定制的LoginModule實(shí)現,LoginModule類(lèi)是在JAAS中是一個(gè)可插拔組件并且服務(wù)于兩個(gè)目的:
1、鑒定認證用戶(hù)
2、如果認證成公,則用相關(guān)的負責人信息或者證書(shū)更新主題。
LoginModule有5個(gè)方法去實(shí)現功能,讓我們關(guān)注一下login()方法。這個(gè)方法被調用以認證主題并且主要作兩件事情:
1、包含用戶(hù)名和密碼,典型地,LoginModule要調用CallbackHandler類(lèi)的handle方法去得到用戶(hù)名和密碼
2、通過(guò)和數據源中的比較校驗密碼。LoginModule從Callbacks取回用戶(hù)名和密碼。(其默認期望用戶(hù)接口的某種排序),這一點(diǎn)對于一個(gè)簡(jiǎn)單的演示程序或者就在命令行,可是他對于一個(gè)J2EE應用來(lái)說(shuō)不太實(shí)用,例如,對于大多數的Web應用,用戶(hù)名和密碼將比較典型的從一個(gè)form中讀出。在這種情況下,使用JAAS認證會(huì )比較困難??紤]我們不直接使用LoginModule,解決方案是實(shí)現一個(gè)可定制的CallbackHandler類(lèi),他會(huì )接收用戶(hù)名和密碼然后遞交它們給LoginModule,所以他沒(méi)有必要提示用戶(hù)輸入信息
以下示例説明用戶(hù)信息如何從JSP或者Servlet中傳遞:
一旦擁有了用戶(hù)名和密碼在手,AuthLoginModule類(lèi),我們的LoginModule類(lèi)的定制實(shí)現,會(huì )經(jīng)由LoginSourceAdapterFactory實(shí)例化LoginSourceAdapter并同時(shí)委派實(shí)際的認證過(guò)程到資源適配器。適配器只不過(guò)是一個(gè)簡(jiǎn)單的類(lèi),其從一個(gè)具體的數據適配器(比如數據庫或者LDAP,或者一些別的系統)領(lǐng)取用戶(hù)信息。在“提交”階段,AuthLoginModule類(lèi)從LoginSourceAdapter類(lèi)取回相關(guān)的信息并且把他們和主題相關(guān)聯(lián)。
LoginSourceAdapter類(lèi)
LoginSourceAdapter類(lèi)是一個(gè)認證目的的資源適配器的接口,它有4個(gè)需要實(shí)現的方法:
1、void initialize(Hashtable parameters):initialized方法被調用來(lái)以相關(guān)的參數初始化適配器。此方法在對象生成后立即被調用并且優(yōu)先于任何對其他方法的調用。
2、boolean authenticate(String username,char[] password):此認證方法被調用來(lái)認證用戶(hù)。
3. String[] getGroupNames (String userName):getGroupNames方法被調用來(lái)在認證成功后得到相關(guān)的主要信息。
4. void terminate ():這個(gè)方法在LoginModule類(lèi)的logout方法被執行后調用,它給適配器做一些清理工作的機會(huì )。
AuthPolicy類(lèi)
在JAAS架構下,安全策略被java.securety.Policy 類(lèi)來(lái)處理,他會(huì )證明賦給一個(gè)具體的代碼源或者主體的多種權限。就像在上一段被討論的,sun.securety.provider.PolicyFile是其默認實(shí)現。PolicyFile類(lèi)使用平面文本文件去證明在權限和代碼源之間的對應關(guān)系,這點(diǎn)對于企業(yè)級應用可能不是太好。一個(gè)集中的系統比如支持基于角色的安全性的關(guān)系數據庫將會(huì )更好。很明顯,擴展JAAS授權以處理不同的來(lái)源的不同的安全標記,我們需要寫(xiě)我們自己的策略實(shí)現。
生成一個(gè)定制的策略實(shí)現的步驟如下:
•擴展java.securety.Policy類(lèi)
•實(shí)現getPermissions()方法
•實(shí)現refresh()方法.
如果你看到我們定制的策略類(lèi)的實(shí)現,你可能注意到我們的AuthPolicy類(lèi)派生在sun.security.provider.PolicyFile而不是java.security.Policy. 為什么?首先,我想要實(shí)現AuthPolicy類(lèi)作為通用的Policy類(lèi),這可以處理默認的策略類(lèi)不需要用任何適配器介入。通過(guò)從PolicyFile類(lèi),我們不需要去實(shí)現策略文件解析和其他相關(guān)的代碼。同時(shí),黨應用運行于一個(gè)安全管理器起作用的情況下,一些權限,比如doAsPrivileged AuthPermission類(lèi)和讀入配置文件的FilePermission(為了載入配置文件),需要被賦權為了執行JAAS.
當然,這些權限可以被存儲在數據源里,但是把它們放入標準Java安全策略文件中可能更為有利??墒?,對于正規開(kāi)發(fā)你應該實(shí)現一個(gè)適配器以應付這些事情。在擴展認證時(shí)要遵循相同的設計模式。我們的策略類(lèi)委托權限請求于
PermisssionAdapter類(lèi)
在權限類(lèi)里,不同的權限保存于自己的PermissionCollection類(lèi)實(shí)例,如果你創(chuàng )建一個(gè)定制的權限類(lèi),你需要生成你自己的PermissionCollection類(lèi)類(lèi)型,否則不能保證你的權限對象將被參考確認。
PermissionAdapter類(lèi)
PermissionAdapter類(lèi)在我們的JAAS擴展組件中是認證過(guò)程可插拔模塊的接口。它從一個(gè)具體的數據源評估策略并且分發(fā)一個(gè)包含一套已賦予的權限的PermissionCollection類(lèi)。PermissionAdapter類(lèi)接口有下面的方法:
• void initialize (Hashtable initParams):initialize方法被調用以相關(guān)的參數初始化適配器。此方法會(huì )被立即調用并且優(yōu)先于任何其它的方法調用。同時(shí),在Policy類(lèi)的refresh方法被執行后它也會(huì )被調用。
• PermissionCollection getPermissions (ProtectionDomain
domain): 本方法只要某種主體權限被請求就會(huì )被調用。
作為一例子,讓我們看看如何實(shí)現一個(gè)基于角色的PermissionAdapter類(lèi)。假設有三個(gè)角色:管理員,用戶(hù),和客人,都擁有不同的權限,并且所有的權限信息被存儲在數據庫中。
首先,在initialize方法中,我們將從數據中取得所有角色的權限信息并且組裝入集合類(lèi)中,比如,Hashtable.接下來(lái),在getPermissions方法中,我們會(huì )收集到相關(guān)主體有關(guān)的權限(這是僅有的會(huì )涉及到基于角色的訪(fǎng)問(wèn)控制)并且返回它們。注意我們可以得到相關(guān)的主體通過(guò)調用ProtectedDomain類(lèi)的getPrincipals方法。它是如此的簡(jiǎn)單,不是嗎?
JaasUtil類(lèi)
對于我們的JAAS擴展組件JaasUtil類(lèi)是主要的紐帶,并且它有一個(gè)構造函數取得用戶(hù)名和密碼。有兩個(gè)關(guān)鍵的方法:
1. boolean authenticate()
2. boolean checkPermission(Subject subject,final Permission perm)
JaasUtil類(lèi)實(shí)際延遲了LoginContext類(lèi)的登陸請求和SecurityManager類(lèi)的權限檢查步驟。 Listing 1 顯示了如何使用JaasUtil類(lèi)。這段代碼首先從HtttpServletRequest類(lèi)取得用戶(hù)名和密碼并且嘗試認證用戶(hù).然后其檢測是否用戶(hù)有權限訪(fǎng)問(wèn)“editReg.jsp”.
配置
現在我們擁有自己的定制的LoginModule,Policy和其他相關(guān)模塊實(shí)現。這些模塊可以委托相關(guān)的數據請求給合適的適配器;這是很好的事情。然而,在JAAS結構中LoginModule類(lèi)和Policy類(lèi)絕對不會(huì )被應用程序直接調用,所以我們怎樣知道那種適配器應該被實(shí)力化和怎樣傳遞需要的參數或者信息,比如數據連接,給適配器?答案是適配器可以通過(guò)更新一個(gè)XML配置文件被動(dòng)態(tài)配置。這個(gè)XML配置文件由兩個(gè)主要的數據段組成:
1、<authentication>:本段內容定義登陸源適配器和認證過(guò)程需要的各種可能的輸入參數。
2、<authorization>:本段內容定義權限適配器和授權過(guò)程序要的各種可能的輸入參數
你可以制定使用哪個(gè)LoginSourceAdapter類(lèi)和PermissionAdapter類(lèi)。在配置文件中傳遞額外的信息也是可能的。讓JaasUtil類(lèi)知道在那里尋找配置文件有兩種途徑:
1、 制定配置文件經(jīng)由命令行屬性開(kāi)關(guān): -Dcon.auth.config
2、 調用JaasUtil.setConfigFile(configFile)方法.
當你部署JAAS擴展組件時(shí),這個(gè)定制安全策略類(lèi)文件必須被加入到Java的jre/lib目錄,這將引起策略類(lèi)文件被bootstrap類(lèi)加載其載入。否則,即便你放置策略文件在你的Java類(lèi)路徑中,它也將不能被檢出并且Sun默認提供的策略類(lèi)將會(huì )代替而被使用。
總結
擴展JAAS是不困難的。JAAS結構提供給你定制實(shí)現認證和授權過(guò)程的彈性。理解這些過(guò)程如何工作是懂得如何替換你自己的實(shí)現的第一步。在本文中,我們重溫JAAS的基礎,并且檢查驗證了如何擴展JAAS使其成為一個(gè)更加具備動(dòng)態(tài)化、靈活化和規?;奶匦缘目蚣?。使用這種擴展框架,你既能夠輕松的生成自己登陸和訪(fǎng)問(wèn)控制機制以支持你自己的企業(yè)級別的安全需求也能夠支持新興的安全標準,或者平衡你們已經(jīng)存在的或定制安全模型作為適配器,然后熱插拔他們進(jìn)入JAAS中。這應該可以給你的企業(yè)應用提供一個(gè)基于標準的同時(shí)高可定制的認證和授權過(guò)程。
Guosheng Huang, PhD, is a seniorsoftware developer withWysdom Inc. He has over 15years of experience in software engineering and technical architecture. gorsenhuang@yahoo.com
翻譯:綠野風(fēng)煙 2003/10
用戶(hù)認證和訪(fǎng)問(wèn)控制是大多數java應用的重要安全尺度,特別是J2EE應用。Java認證和權限服務(wù)(即JAAS),J2SE1.4和1.5的核心API,描繪表達了新的安全標準。其提供了一個(gè)可插拔的(pluggable)和富有彈性的(flexible)框架(framework)允許開(kāi)發(fā)者混合不同的安全機制和豐富的已經(jīng)存在各種安全方面的資源。
伴隨著(zhù)即將來(lái)臨的J2SE1.5版本的發(fā)布,它包含了許多諸如加密技術(shù)、XML安全性、公鑰機制(PKI)、Kerberos (是一個(gè)網(wǎng)絡(luò )附加系統/協(xié)議,可以允許用戶(hù)通過(guò)一個(gè)安全伺服器的服務(wù)來(lái)驗證 自己。象遠端登陸,遠端拷貝,系統間的相互檔拷貝和另外高風(fēng)險任務(wù)的服務(wù)將被變 得相當安全和可控制。)和結盟認證(the federating identity)的增強!,JAAS將會(huì )在J2EE實(shí)現中扮演一個(gè)更加重要的角色。
認證
認證就是校驗一個(gè)用戶(hù)擁有使用已經(jīng)被企業(yè)用戶(hù)注冊機構證明了的身份鑒定的權限的處理過(guò)程。JAAS的認證機制建立于一整套可插拔的模塊(參看圖1)基礎上。JAAS允許不同的驗證模型在運行時(shí)可被插拔??蛻?hù)應用總是通過(guò)登陸上下文對象和JAAS交互。
認證處理過(guò)程典型的要經(jīng)過(guò)下面的步驟:
1、 生成一個(gè)LoginContext對象。這個(gè)LoginContext尋找配置文件以決定使用那個(gè)LoginModule。同樣,可選擇的,有可能傳遞一個(gè)CallbackHandler給LoginContext.
2、 通過(guò)調用LoginContext的login方法執行認證,它會(huì )加載預定義的LoginModule去檢驗是否用戶(hù)可以被認證。
3、 如果用戶(hù)被認證,那么用規則和標識和其所屬項進(jìn)行關(guān)聯(lián)。
4、 或者在登陸失敗的情況下跑出一個(gè)LoginException
5、 使用LoginContext的logout方法進(jìn)行注銷(xiāo)登陸
在JAAS中,登陸是一個(gè)兩階段(two-phase)的處理過(guò)程。第一階段是“登陸(login)”階段(就像上面2所描述的)。這個(gè)階段唯一的任務(wù)是認證。只要處理過(guò)程成功通過(guò)這個(gè)階段,認證處理過(guò)程就進(jìn)入了“提交(commit)”階段(如上步驟3),這一階段LoginModule的commit方法被調用去關(guān)聯(lián)所屬子項相關(guān)的規則和標識。
在JAAS中一個(gè)所屬子項表示一個(gè)認證實(shí)體,比如一個(gè)人或者一臺設備。它包含了一整套法則和安全相關(guān)的屬性諸如密碼和加密密鑰。在JAAS體系結構中,所屬子項和其所附屬的相關(guān)權限,扮演了重要的角色在認證過(guò)程當中。所有的認證模塊當中,LoginModule是事實(shí)上的認證機制的借口。雖然LoginModule決沒(méi)有得到直接調用客戶(hù)應用的機會(huì ),但是他經(jīng)由一個(gè)可插拔的模塊提供了一個(gè)認證的具體類(lèi)型,其實(shí)現了認證的算法并且決定實(shí)際的認證過(guò)程是怎樣被執行的。
SUN提供了幾個(gè)默認的LoginModule 實(shí)現,在sun.com.security.auth.module包里有諸如JndiLoginModule,Krb2LoginModule,UnixLoginModule和NTLoginModule等幾個(gè)LoginModule實(shí)現。因為JAAS登錄結構體系是可擴展的,所以你只要在配置文件中指定使用哪個(gè)LoginModule模塊就可以幾乎全部插入任何LoginModule模塊。
如下即為一個(gè)配置文件的例子:
MySample {
com.sample.module.MyLoginModule required debug=true;
};這里MySample是登錄上下文環(huán)境(login context)的名字,當你生成一個(gè)新的LoginContext開(kāi)始認證過(guò)程時(shí)它會(huì )被傳入LoginContex的構造函數中。依據配置塊提示,那個(gè)文本塊提醒JAAS有關(guān)LoginModule在登錄過(guò)程中應該被用來(lái)執行認證。另外,對于LoginModule,任何關(guān)于他的選項也可以在這里被指定。在執行登錄這一步驟的過(guò)程中,CallbackHandler類(lèi)被LoginModule類(lèi)用來(lái)跟用戶(hù)通信已便于取得認證信息。CallbackHandler類(lèi)處理三種類(lèi)型的回調(Callback):NameCallback,提示用戶(hù)輸入一個(gè)用戶(hù)名;PasswordCallcack,提示輸入密碼;TextOutputCallback,報告錯誤、警告或則發(fā)送給用戶(hù)一些其他信息。
授權是決定是否認證的用戶(hù)可以執行一些動(dòng)作的工作,例如訪(fǎng)問(wèn)一處資源。因為JAAS建立于已經(jīng)存在的Java安全模型的基礎上,故這個(gè)過(guò)程時(shí)基于策略的。策略配置文件實(shí)質(zhì)上包含了一系列的入口,諸如“Keystore”和/或“grant”.
grant入口包含了所有的權限,他是通過(guò)認證的代碼或則法則被授予可以進(jìn)行安全敏感的操作,例如,訪(fǎng)問(wèn)一個(gè)具體的Web頁(yè)面或則本地的文件。JAAS支持基于法則的策略入口,賦權入口基本格式如下:
grant Codebase “codebase_URL” Signedby “signer_name,”
Principal principal_class_name “principal_name”,
Principal principal_class_name “principal_name”,
… {
permission permission_class_name “target_name”, “action”,
permission permission_class_name “target_name”, “action”,
…
}
上面格式中“動(dòng)作(action)”可能是必需的或則可能被忽略依賴(lài)于權限類(lèi)型。在JAAS體系結構中,策略對象表達了一個(gè)Java應用環(huán)境的系統安全策略和在任何時(shí)間事實(shí)上只有一個(gè)策略對象。依據Java2 SDK文檔,默認的策略實(shí)現是sun.security.provider.PolicyFile,其中策略被指定在一個(gè)或多個(gè)策略配置文件里。
只要用戶(hù)被認證,授權經(jīng)由Subject.doAs方法發(fā)生,或者從Subject類(lèi)的靜態(tài)方法doAsPrivileged,doAS方法用當前的AccessControlContext動(dòng)態(tài)和子項并且同時(shí)調用run方法去執行動(dòng)作,他導致安全驗證。權限驗證過(guò)程通過(guò)下面的步驟在圖2:
就像LoginModule,策略也是可插拔的模型。你可以?huà)焐掀渌牟呗詫?shí)現通過(guò)在java.security的屬性文件中改變“policy.provider=sun.security.provider.PolicyFile”
到一個(gè)你項使用的策略類(lèi)。
Extend JAAS
JAAS建立于已經(jīng)存在的Java安全模型的頂端,其基于“CodeSource”和平面文本格式策略文件實(shí)現。這可能對企業(yè)應用是不夠用的,你可能想使用可定制的安全倉庫。對于JAAS的其它實(shí)現,諸如LDAP(輕型目錄訪(fǎng)問(wèn)協(xié)議),數據庫或者其他文件系統,它可以通過(guò)編寫(xiě)你自己的可定制模塊被完成,感謝JAAS的可插拔的特性。然而,這需要對模塊和JAAS中的處理過(guò)程有完善的理解,同時(shí)你必須做許多編碼去覆寫(xiě)相關(guān)的類(lèi),并且處理好配置和策略?xún)煞N文件。
理想情況下,我們愿意能夠擴展JAAS以一個(gè)更加容易的方式以便于無(wú)論何時(shí)一個(gè)可定制的安全知識庫或者不同的訪(fǎng)問(wèn)控制機制改變或者必須去增加時(shí),你能夠只開(kāi)發(fā)和插入這些不同的小模塊(即,適配器)去適應這些新的變化和需求,并且在最好的情況下,不必去理解和熟悉JAAS處理過(guò)程的細節,同樣,我們也愿意能夠去做這些變化僅僅通過(guò)改變一個(gè)配置文件。另一個(gè)目標是我們的JAAS擴展組件能夠被使用在不同的J2EE應用中—獨立的或者Web上的。圖3描述了JAAS擴展組件的設計意圖。我們的JAAS擴展組在實(shí)現可定制的LoginModule和策略模塊時(shí)充分件利用了JAAS插拔式的體系結構。這些模塊中,我們委派數據請求到適配器。這些適配器的每個(gè)對于諸如數據取回的簡(jiǎn)單任務(wù)是隔離的,所以你可以快速地使用不同的安全知識或者算法開(kāi)發(fā)不同的適配器而不是嘗試去實(shí)現不同的LoginModule或者策略模塊,它們更加復雜并且需要更多的努力。
你可以從www.sys-con.com/java/sourcec.cfm.下在完整的源瑪。
實(shí)現的AuthLoginModule類(lèi)
AuthLoginModule類(lèi)是我們定制的LoginModule實(shí)現,LoginModule類(lèi)是在JAAS中是一個(gè)可插拔組件并且服務(wù)于兩個(gè)目的:
1、鑒定認證用戶(hù)
2、如果認證成公,則用相關(guān)的負責人信息或者證書(shū)更新主題。
LoginModule有5個(gè)方法去實(shí)現功能,讓我們關(guān)注一下login()方法。這個(gè)方法被調用以認證主題并且主要作兩件事情:
1、包含用戶(hù)名和密碼,典型地,LoginModule要調用CallbackHandler類(lèi)的handle方法去得到用戶(hù)名和密碼
2、通過(guò)和數據源中的比較校驗密碼。LoginModule從Callbacks取回用戶(hù)名和密碼。(其默認期望用戶(hù)接口的某種排序),這一點(diǎn)對于一個(gè)簡(jiǎn)單的演示程序或者就在命令行,可是他對于一個(gè)J2EE應用來(lái)說(shuō)不太實(shí)用,例如,對于大多數的Web應用,用戶(hù)名和密碼將比較典型的從一個(gè)form中讀出。在這種情況下,使用JAAS認證會(huì )比較困難??紤]我們不直接使用LoginModule,解決方案是實(shí)現一個(gè)可定制的CallbackHandler類(lèi),他會(huì )接收用戶(hù)名和密碼然后遞交它們給LoginModule,所以他沒(méi)有必要提示用戶(hù)輸入信息
以下示例説明用戶(hù)信息如何從JSP或者Servlet中傳遞:
String userName = request.getParameter (“user”);
String password = request.getParameter(“password”);
LoginContext context = new LoginContext (“MySample”,
new AuthCallbackHandler (userName, password));
一旦擁有了用戶(hù)名和密碼在手,AuthLoginModule類(lèi),我們的LoginModule類(lèi)的定制實(shí)現,會(huì )經(jīng)由LoginSourceAdapterFactory實(shí)例化LoginSourceAdapter并同時(shí)委派實(shí)際的認證過(guò)程到資源適配器。適配器只不過(guò)是一個(gè)簡(jiǎn)單的類(lèi),其從一個(gè)具體的數據適配器(比如數據庫或者LDAP,或者一些別的系統)領(lǐng)取用戶(hù)信息。在“提交”階段,AuthLoginModule類(lèi)從LoginSourceAdapter類(lèi)取回相關(guān)的信息并且把他們和主題相關(guān)聯(lián)。
LoginSourceAdapter類(lèi)
LoginSourceAdapter類(lèi)是一個(gè)認證目的的資源適配器的接口,它有4個(gè)需要實(shí)現的方法:
1、void initialize(Hashtable parameters):initialized方法被調用來(lái)以相關(guān)的參數初始化適配器。此方法在對象生成后立即被調用并且優(yōu)先于任何對其他方法的調用。
2、boolean authenticate(String username,char[] password):此認證方法被調用來(lái)認證用戶(hù)。
3. String[] getGroupNames (String userName):getGroupNames方法被調用來(lái)在認證成功后得到相關(guān)的主要信息。
4. void terminate ():這個(gè)方法在LoginModule類(lèi)的logout方法被執行后調用,它給適配器做一些清理工作的機會(huì )。
AuthPolicy類(lèi)
在JAAS架構下,安全策略被java.securety.Policy 類(lèi)來(lái)處理,他會(huì )證明賦給一個(gè)具體的代碼源或者主體的多種權限。就像在上一段被討論的,sun.securety.provider.PolicyFile是其默認實(shí)現。PolicyFile類(lèi)使用平面文本文件去證明在權限和代碼源之間的對應關(guān)系,這點(diǎn)對于企業(yè)級應用可能不是太好。一個(gè)集中的系統比如支持基于角色的安全性的關(guān)系數據庫將會(huì )更好。很明顯,擴展JAAS授權以處理不同的來(lái)源的不同的安全標記,我們需要寫(xiě)我們自己的策略實(shí)現。
生成一個(gè)定制的策略實(shí)現的步驟如下:
•擴展java.securety.Policy類(lèi)
•實(shí)現getPermissions()方法
•實(shí)現refresh()方法.
如果你看到我們定制的策略類(lèi)的實(shí)現,你可能注意到我們的AuthPolicy類(lèi)派生在sun.security.provider.PolicyFile而不是java.security.Policy. 為什么?首先,我想要實(shí)現AuthPolicy類(lèi)作為通用的Policy類(lèi),這可以處理默認的策略類(lèi)不需要用任何適配器介入。通過(guò)從PolicyFile類(lèi),我們不需要去實(shí)現策略文件解析和其他相關(guān)的代碼。同時(shí),黨應用運行于一個(gè)安全管理器起作用的情況下,一些權限,比如doAsPrivileged AuthPermission類(lèi)和讀入配置文件的FilePermission(為了載入配置文件),需要被賦權為了執行JAAS.
當然,這些權限可以被存儲在數據源里,但是把它們放入標準Java安全策略文件中可能更為有利??墒?,對于正規開(kāi)發(fā)你應該實(shí)現一個(gè)適配器以應付這些事情。在擴展認證時(shí)要遵循相同的設計模式。我們的策略類(lèi)委托權限請求于
PermisssionAdapter類(lèi)
在權限類(lèi)里,不同的權限保存于自己的PermissionCollection類(lèi)實(shí)例,如果你創(chuàng )建一個(gè)定制的權限類(lèi),你需要生成你自己的PermissionCollection類(lèi)類(lèi)型,否則不能保證你的權限對象將被參考確認。
PermissionAdapter類(lèi)
PermissionAdapter類(lèi)在我們的JAAS擴展組件中是認證過(guò)程可插拔模塊的接口。它從一個(gè)具體的數據源評估策略并且分發(fā)一個(gè)包含一套已賦予的權限的PermissionCollection類(lèi)。PermissionAdapter類(lèi)接口有下面的方法:
• void initialize (Hashtable initParams):initialize方法被調用以相關(guān)的參數初始化適配器。此方法會(huì )被立即調用并且優(yōu)先于任何其它的方法調用。同時(shí),在Policy類(lèi)的refresh方法被執行后它也會(huì )被調用。
• PermissionCollection getPermissions (ProtectionDomain
domain): 本方法只要某種主體權限被請求就會(huì )被調用。
作為一例子,讓我們看看如何實(shí)現一個(gè)基于角色的PermissionAdapter類(lèi)。假設有三個(gè)角色:管理員,用戶(hù),和客人,都擁有不同的權限,并且所有的權限信息被存儲在數據庫中。
首先,在initialize方法中,我們將從數據中取得所有角色的權限信息并且組裝入集合類(lèi)中,比如,Hashtable.接下來(lái),在getPermissions方法中,我們會(huì )收集到相關(guān)主體有關(guān)的權限(這是僅有的會(huì )涉及到基于角色的訪(fǎng)問(wèn)控制)并且返回它們。注意我們可以得到相關(guān)的主體通過(guò)調用ProtectedDomain類(lèi)的getPrincipals方法。它是如此的簡(jiǎn)單,不是嗎?
JaasUtil類(lèi)
對于我們的JAAS擴展組件JaasUtil類(lèi)是主要的紐帶,并且它有一個(gè)構造函數取得用戶(hù)名和密碼。有兩個(gè)關(guān)鍵的方法:
1. boolean authenticate()
2. boolean checkPermission(Subject subject,final Permission perm)
JaasUtil類(lèi)實(shí)際延遲了LoginContext類(lèi)的登陸請求和SecurityManager類(lèi)的權限檢查步驟。 Listing 1 顯示了如何使用JaasUtil類(lèi)。這段代碼首先從HtttpServletRequest類(lèi)取得用戶(hù)名和密碼并且嘗試認證用戶(hù).然后其檢測是否用戶(hù)有權限訪(fǎng)問(wèn)“editReg.jsp”.
配置
現在我們擁有自己的定制的LoginModule,Policy和其他相關(guān)模塊實(shí)現。這些模塊可以委托相關(guān)的數據請求給合適的適配器;這是很好的事情。然而,在JAAS結構中LoginModule類(lèi)和Policy類(lèi)絕對不會(huì )被應用程序直接調用,所以我們怎樣知道那種適配器應該被實(shí)力化和怎樣傳遞需要的參數或者信息,比如數據連接,給適配器?答案是適配器可以通過(guò)更新一個(gè)XML配置文件被動(dòng)態(tài)配置。這個(gè)XML配置文件由兩個(gè)主要的數據段組成:
1、<authentication>:本段內容定義登陸源適配器和認證過(guò)程需要的各種可能的輸入參數。
2、<authorization>:本段內容定義權限適配器和授權過(guò)程序要的各種可能的輸入參數
你可以制定使用哪個(gè)LoginSourceAdapter類(lèi)和PermissionAdapter類(lèi)。在配置文件中傳遞額外的信息也是可能的。讓JaasUtil類(lèi)知道在那里尋找配置文件有兩種途徑:
1、 制定配置文件經(jīng)由命令行屬性開(kāi)關(guān): -Dcon.auth.config
2、 調用JaasUtil.setConfigFile(configFile)方法.
當你部署JAAS擴展組件時(shí),這個(gè)定制安全策略類(lèi)文件必須被加入到Java的jre/lib目錄,這將引起策略類(lèi)文件被bootstrap類(lèi)加載其載入。否則,即便你放置策略文件在你的Java類(lèi)路徑中,它也將不能被檢出并且Sun默認提供的策略類(lèi)將會(huì )代替而被使用。
總結
擴展JAAS是不困難的。JAAS結構提供給你定制實(shí)現認證和授權過(guò)程的彈性。理解這些過(guò)程如何工作是懂得如何替換你自己的實(shí)現的第一步。在本文中,我們重溫JAAS的基礎,并且檢查驗證了如何擴展JAAS使其成為一個(gè)更加具備動(dòng)態(tài)化、靈活化和規?;奶匦缘目蚣?。使用這種擴展框架,你既能夠輕松的生成自己登陸和訪(fǎng)問(wèn)控制機制以支持你自己的企業(yè)級別的安全需求也能夠支持新興的安全標準,或者平衡你們已經(jīng)存在的或定制安全模型作為適配器,然后熱插拔他們進(jìn)入JAAS中。這應該可以給你的企業(yè)應用提供一個(gè)基于標準的同時(shí)高可定制的認證和授權過(guò)程。

