欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
定制自己的WebLogic LDAP Authentication Provider
目錄

1 J2EE Security 和 LDAP Security
2 JAAS和WebLogic Security Framework
3 了解WebLogic LDAP Authentication Provider
4 定制自己的Custom LDAP Authentication Provider
5 部署中的注意事項
6 結束語(yǔ)
7 參考資料

  從WebLogic Server 7.0開(kāi)始,WebLogic Server的安全機制有了全面的改變,實(shí)現了一個(gè)更加規范的基于JAAS的Security Framework,以及提供了一系列設計良好的Security Service Provider Interface。這樣我們可以根據自己的具體需求,通過(guò)Custom Security Authentication Provider來(lái)實(shí)現安全上的定制功能。

  本文將以WebLogic(WebLogic Server 8.1) Security和 LDAP為基礎,介紹Custom LDAP Authentication Provider如何給我們帶來(lái)更多的靈活性,和系統安全設計上更多的空間;以及討論如何實(shí)現一個(gè)Custom LDAP Authentication Provider和部署過(guò)程中的一些良好經(jīng)驗。

  由于本文涉及到的范圍太廣,不可能一一詳細討論;為了使沒(méi)有相關(guān)基礎的讀者也能夠閱讀理解本文,因此我將在文章前半部分,試圖通過(guò)最簡(jiǎn)潔扼要的描述,來(lái)使大家對于J2EE Security,WebLogic Security Framework以及LDAP 等有一個(gè)初步的清晰認識;進(jìn)而可以開(kāi)發(fā)出自己的LDAP Authentication Provider。因此很多地方做了比較有限的描述或者介紹,更多詳細的內容可以參考文后附帶的參考資料或者文中給出的鏈接。

1 J2EE Security 和 LDAP Security
  Sun J2EE推出以來(lái),其安全部分的規范就一直倍受關(guān)注。我們最常見(jiàn)到安全規范的兩個(gè)方面分別是Servlet Security 和 EJB Security。目前絕大多數的Servlet容器,J2EE容器都能很好的支持這些安全規范。

  WebLogic Server作為業(yè)界領(lǐng)先的J2EE服務(wù)器對J2EE Security的支持是非常優(yōu)秀的。我們這里將結合WebLogic Security和使用越來(lái)越廣泛的LDAP做一個(gè)簡(jiǎn)要的介紹,這些是設計開(kāi)發(fā)Custom LDAP Authentication Provider的技術(shù)基礎。

1.1 Authentication 和Authorization
  這里需要大家先明確安全上的兩個(gè)重要名詞:一個(gè)是認證(Authentication),一個(gè)是授權(Authorization)。認證是回答這個(gè)人是誰(shuí)的問(wèn)題,即完成用戶(hù)名和密碼的匹配校驗;授權是回答這個(gè)人能做什么的問(wèn)題。我們討論的J2EE Security包括Declarative Authorization和Programmatic Authorization,即一個(gè)是通過(guò)web.xml,ejb-jar.xml等部署描述符中的安全聲明通過(guò)容器提供的服務(wù)來(lái)完成權限控制的;一個(gè)是通過(guò)HttpServletRequest.isUserInRole()和EJBContext.isCallerInRole()這樣的編程接口在應用中自己完成權限控制的。

1.2 資源(Resource)和Security Role
  
資源原本只包括 Web Resource和EJB Resource,但在WebLogic Security中擴展到幾乎任何一個(gè)WebLogic Platform中的資源,具體可以參考http://e-docs.bea.com/wls/docs81/secwlres/types.html#1213777。授權就是針對資源的訪(fǎng)問(wèn)控制。

  J2EE Security是基于Security Role的。我們可以將一組資源與一個(gè)Security Role進(jìn)行關(guān)聯(lián)來(lái)達到控制的目的——只有擁有該Role權限的用戶(hù)才能夠訪(fǎng)問(wèn)這些資源。簡(jiǎn)單的說(shuō),我們可以通過(guò)給用戶(hù)分配不同的Security Role來(lái)完成權限的控制。復雜的情況下包括用戶(hù)/用戶(hù)組,以及Principal和Role的映射關(guān)系等等。下面是一個(gè)聲明性安全在web application(war包中WEB-INF/web.xml)中的示例:

<web-app>
 <security-constraint>
 <web-resource-collection>
  <web-resource-name>Success</web-resource-name>
  <url-pattern>/welcome.jsp</url-pattern>
   <http-method>GET</http-method>
   <http-method>POST</http-method>
 </web-resource-collection>
 <auth-constraint>
  <role-name>webuser</role-name>
 </auth-constraint>
 </security-constraint>
 <login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>default</realm-name>
 </login-config>
 <security-role>
  <role-name>webuser</role-name>
 </security-role>
</web-app>

  只有擁有角色webuser的用戶(hù)才能夠訪(fǎng)問(wèn)welcome.jsp頁(yè)面,否則容器會(huì )返回401無(wú)權訪(fǎng)問(wèn)的錯誤。更多信息請參考http://e-docs.bea.com/wls/docs81/security/index.html。

  同時(shí)我們需要在weblogic.xml(war包中WEB-INF/weblogic.xml)中對security role和principal進(jìn)行映射關(guān)系的配置:

<weblogic-web-app>
 <security-role-assignment>
  <role-name>PayrollAdmin</role-name>
  <principal-name>Tanya</principal-name>
 </security-role-assignment>
</weblogic-web-app>

  這樣擁有Principal “Tanya”的用戶(hù)(Principal將封裝到Subject中,用戶(hù)將和Subject關(guān)聯(lián))將會(huì )擁有PayrollAdmin的權限。

  注意:一般情況下為了簡(jiǎn)化設計,本文中將假設security role即是principal name(如果不配置security-role-assignment,WebLogic會(huì )默認做此假設)。即上例中Principal-name也為PayrollAdmin。

1.3 LDAP Security
  
LDAP是輕量級目錄服務(wù)(Lightweight Directory Access Protocol)。越來(lái)越多的應用開(kāi)始采用LDAP作為后端用戶(hù)存儲。在安全上,LDAP Security是基于A(yíng)CL(Access Control List)的,它通過(guò)給一個(gè)用戶(hù)組分配LDAP 操作資源(比如對一個(gè)子樹(shù)的查詢(xún),修改等)來(lái)最終完成權限的控制。因此在LDAP中,授權工作是以用戶(hù)組為單位進(jìn)行的。一個(gè)用戶(hù)組一般來(lái)說(shuō)是擁有如下一組屬性的LDAP Entry:


圖1-3-1

  其中objectclass可以為groupOfUniqueNames或者groupOfNames,它們對應的組成員屬性分別是uniquemember和member。如果是動(dòng)態(tài)組,objectclass為groupOfURLs。動(dòng)態(tài)組一般應用在成員可以通過(guò)某種業(yè)務(wù)邏輯運算來(lái)決定的情況下。比如,經(jīng)理為ZHANGSAN的全部員工。下面是一個(gè)典型的動(dòng)態(tài)組,memberURL屬性定義了哪些entry屬于該組:


圖1-3-2

  從圖1-3-1中我們可以看出,用戶(hù)WANTXIAOMING,ZHANGSAN,LISI屬于組HR Managers。這種組和成員的關(guān)系是通過(guò)屬性uniquemember來(lái)決定的。同時(shí)LADP Group 支持嵌套,即一個(gè)組可以是另外一個(gè)組的成員,比如我們將Accounting Managers組分配給HR Managers組作為其成員:


圖1-3-3

  這樣將表示Accounting Managers中的成員,同時(shí)也是組HR Managers的成員。通過(guò)這種層級關(guān)系可以使權限分配變的更加靈活。

  下面是一些名詞的解釋?zhuān)M蠹覍DAP有更好的理解:
  a) Objectclass —— LDAP對象類(lèi),抽象上的概念類(lèi)似與一般我們理解的class。根據不同的objectclass,我們可以判斷這個(gè)entry是否屬于某一個(gè)類(lèi)型。比如我們需要找出LDAP中的全部用戶(hù):(objectclass=person)再比如我們需要查詢(xún)全部的LDAP組:(objectclass=groupOfUniqueNames)

  b) Entry —— entry可以被稱(chēng)為條目,或者節點(diǎn),是LDAP中一個(gè)基本的存儲單元;可以被看作是一個(gè)DN和一組屬性的集合。 屬性可以定義為多值或者單值。

  c) DN —— Distinguished Name,LDAP中entry的唯一辨別名,一般有如下的形式:uid=ZHANGSAN, ou=staff, ou=people, o=examples。LDAP中的entry只有DN是由LDAP Server來(lái)保證唯一的。

  d) LDAP Search filter ——使用filter對LDAP進(jìn)行搜索。 Filter一般由 (attribute=value) 這樣的單元組成,比如:(&(uid=ZHANGSAN)(objectclass=person)) 表示搜索用戶(hù)中,uid為ZHANGSAN的LDAP Entry.再比如:(&(|(uid= ZHANGSAN)(uid=LISI))(objectclass=person)),表示搜索uid為ZHANGSAN, 或者LISI的用戶(hù);也可以使用*來(lái)表示任意一個(gè)值, 比如(uid=ZHANG*SAN),搜索uid值以 ZHANG開(kāi)頭SAN結尾的Entry。更進(jìn)一步,根據不同的LDAP屬性匹配規則,可以有如下的Filter: (&(createtimestamp>=20050301000000)(createtimestamp<=20050302000000)),表示搜索創(chuàng )建時(shí)間在20050301000000和20050302000000之間的entry。
  Filter中 “&” 表示“與”;“!”表示“非”;“|”表示“或”。根據不同的匹配規則,我們可以使用“=”,“~=”,“>=”以及“<=”,更多關(guān)于LDAP Filter讀者可以參考LDAP相關(guān)協(xié)議:http://www.ietf.org/rfc/rfc2254.txt。

  e) Base DN —— 執行LDAP Search時(shí)一般要指定basedn,由于LDAP是樹(shù)狀數據結構,指定basedn后,搜索將從BaseDN開(kāi)始,我們可以指定Search Scope為:只搜索basedn(base),basedn直接下級(one level),和basedn全部下級(sub tree level)。

  下面是一個(gè)典型的LDAP Tree結構,右側顯示Entry uid=ZHANGSAN, ou=staff, ou=people, o=examples的屬性,該entry代表了一個(gè)名字叫張三的用戶(hù):


圖1-3-4

2 JAAS和WebLogic Security Framework
  現在越來(lái)越多的人開(kāi)始了解JAAS,使用JAAS。WebLogic Security Framework就是基于JAAS的。因此我們需要對此有一個(gè)非常準確的理解才能夠設計開(kāi)發(fā)Custom Authentication Provider。

  下面我們從幾個(gè)名詞入手,了解JAAS和 WebLogic Security Framework的關(guān)鍵之處:

2.1 Principal,Subject和LoginModule
  
a) Principal
  當用戶(hù)成功驗證后,系統將會(huì )生成與該用戶(hù)關(guān)聯(lián)的各種Principal。我們這里將Principal進(jìn)行簡(jiǎn)化的設計,認為一個(gè)Principal就是用戶(hù)登錄賬號和它所屬于的組(LDAP Group)。這樣當用戶(hù)登錄成功后,我們將會(huì )在LDAP中執行搜索,找出用戶(hù)屬于哪些組,并將這些組的名字,或者其標識作為Principal返回。這樣,當用戶(hù)在LDAP中屬于某一個(gè)組,并且這個(gè)組的名字對應到 web.xml (或者ejb-jar.xml)中的Security role,那么這個(gè)用戶(hù)就可以看作擁有訪(fǎng)問(wèn)這個(gè)Security Role定義的資源的權限。
  在WebLogic Security Framework中,這個(gè)LDAP Group的名字(Principal)和Security Role的映射關(guān)系,可以通過(guò)一個(gè) Role Mapping Provider來(lái)實(shí)現動(dòng)態(tài)的匹配,即用戶(hù)的動(dòng)態(tài)權限控制。比如在運行時(shí)根據某一個(gè)業(yè)務(wù)邏輯來(lái)決定用戶(hù)是否擁有某一個(gè)權限。關(guān)于Role Mapping Provider,讀者可以參考下面鏈接的內容:http://e-docs.bea.com/wls/docs81/dvspisec/rm.html#1145542。

  b) Subject
  JAAS規定由Subject封裝用戶(hù)以及用戶(hù)認證信息,其中包括Principals。下面是WebLogic Security Framework中Subject的組成圖示:


圖2-1-1

  這樣當用戶(hù)試圖訪(fǎng)問(wèn)一個(gè)受限的J2EE資源時(shí),比如一個(gè)web URL,或者一個(gè) EJB Method(可以在web.xml或者ejb-jar.xml中定義,由Security Role控制),WebLogic Security Framework將會(huì )通過(guò) Authorization Provider檢查用戶(hù)當前的Subject中是否包含有是否可以訪(fǎng)問(wèn)受限資源的Principals。由于Principals將和J2EE Security Role在weblogic.xml中定義一個(gè)映射關(guān)系(或者通過(guò)其他業(yè)務(wù)邏輯來(lái)確定這種關(guān)系),因此通過(guò)這樣的關(guān)系,可以最終知道用戶(hù)是否有某一個(gè)J2EE Resource的訪(fǎng)問(wèn)權限。

  c) LoginModule
  JAAS LoginModule是一個(gè)Authentication Provider必須的組成部分。LoginModule是認證的核心引擎,它負責對用戶(hù)身份進(jìn)行驗證,同時(shí)將返回與用戶(hù)關(guān)聯(lián)的Principals(用戶(hù)登錄賬號,以及LDAP Groups),然后放入Subject中,供后續的訪(fǎng)問(wèn)控制使用。
  我們將在LoginModules中完成LDAP的相關(guān)認證,查詢(xún)操作,將用戶(hù)在LDAP中所屬于的組搜索出來(lái),作為認證后的結果封裝到Subject中返回。

2.2 WebLogic Authentication認證過(guò)程
  下面我們了解一下WebLogic的認證過(guò)程。以下圖片來(lái)自http://e-docs.bea.com/wls/docs81/dvspisec/atn.html 我將其中主要部分進(jìn)行說(shuō)明。


圖2-2-1

  Security Framework在WebLogic Server啟動(dòng)時(shí)初始化Authentication Provider(5)。當有認證請求進(jìn)入時(shí),Security Framework首先將通過(guò)AuthenticationProvider.getLoginModuleConfiguration()來(lái)獲取一個(gè)AppConfigurationEntry對象。通過(guò)AppConfigurationEntry(詳見(jiàn)http://java.sun.com/security/jaas/apidoc/javax/security/auth/login/AppConfigurationEntry.html )可以初始化一個(gè)LoginModule。初始化LoginModule的方法為:public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options),可以看到里面有Subject, CallbackHandler等等重要參數。
  被實(shí)例化的JAAS LoginModule將完成用戶(hù)的一系列驗證任務(wù)。驗證完成后,在(6a)中principals將被Principal Validation Provider簽名,在( 6b)中存放到與用戶(hù)關(guān)聯(lián)的Subject里面。Security Framework最后將拿著(zhù)該用戶(hù)的Subject去完成其他權限控制等任務(wù)。

3 了解WebLogic LDAP Authentication Provider
  現在我們有信心了解一下WebLogic LDAP Authentication Provider的工作原理了。這里將以WebLogic提供的iPlanet Authentication Provider的配置為例進(jìn)行說(shuō)明。在這里也需要明確說(shuō)明一下,為了方便進(jìn)行描述,我們將實(shí)際屬于LoginModule的行為也一并歸結到Provider中。沒(méi)有單獨將兩個(gè)的行為分開(kāi),目的是為了突出整個(gè)完整的過(guò)程。

3.1 iPlanet Authentication Provider配置


圖3-1-1

  從上圖可以看出我們需要指定LDAP服務(wù)器的地址,端口,連接LDAP使用的Principal(不同于前面討論的Principal,這個(gè)Principal實(shí)際是一個(gè)連接LDAP的用戶(hù),也就是一個(gè)LDAP 中用戶(hù)Entry的 DN,它必須要有相關(guān)的LDAP 搜索等權限)和Credential(一般來(lái)說(shuō)就是口令)。
  再看下面關(guān)于Users的配置:


圖3-1-2

3.1.1 User Object Class —— 前面已經(jīng)對objectclass進(jìn)行過(guò)說(shuō)明,指明LDAP Entry屬于哪一類(lèi)
3.1.2 User Name Attribute —— 用戶(hù)登錄賬號在LDAP Entry中的屬性,一般為UID或者cn
3.1.3 User Base DN —— 所有的用戶(hù)將會(huì )放置到這個(gè)子樹(shù)下面,因此在Provider中對用戶(hù)進(jìn)行的搜索將會(huì )從這個(gè)basedn開(kāi)始
3.1.4 User Search Scope —— 指定搜索范圍為Basedn的直接一級或者全部下級
3.1.5 User From Name Filter —— 使用這個(gè)filter可以搜索出用戶(hù)信息。其中%u將會(huì )被用戶(hù)輸入的登錄賬號替換,從而查詢(xún)中LDAP中的用戶(hù)信息


圖3-1-3

3.1.6 Group Base DN —— 從該Base DN開(kāi)始搜索用戶(hù)組
3.1.7 Group From Name Filter —— %g將會(huì )被組的名字替換,通過(guò)該filter可以搜索出符合條件的LDAP Group
3.1.8 Static group name attribute —— 組名字的屬性,屬性cn對應的值就是組的名字


圖3-1-4

3.1.9 Static Member DN Attribute —— 靜態(tài)成員屬性,通過(guò)該屬性可以判斷一個(gè)Entry是否屬于一個(gè)組
3.1.10 Static Group DNs From Member DN Filter —— 通過(guò)該filter可以找出用戶(hù)屬于哪些組
3.1.11 Dynamic Group —— 動(dòng)態(tài)組是在運行時(shí)根據某種業(yè)務(wù)邏輯,來(lái)決定成員隸屬關(guān)系的LDAP Group

3.2 iPlanet Authentication Provider的工作原理
  從上面配置的介紹中可以看出,后端存儲為L(cháng)DAP的情況下,在Console中我們需要配置的參數已經(jīng)清楚的表明它所要完成工作的內容。
  首先,它使用配置的User BaseDN和Filter,來(lái)根據用戶(hù)輸入的登錄賬號進(jìn)行搜索,找出存放在LDAP中的用戶(hù)Entry。如果找到一個(gè)用戶(hù),那么Provider就使用該用戶(hù)的DN和用戶(hù)輸入的口令,進(jìn)行驗證。驗證可以使用LDAP Bind和LDAP Compare,這需要根據不同LDAP的特點(diǎn)來(lái)進(jìn)行選擇。

  A. LDAP Bind —— 將當前的LDAP Connection綁定到一個(gè)用戶(hù)身份上。這樣后續的使用該Connection的LDAP Operation都將以該身份進(jìn)行。LDAP Bind需要兩個(gè)重要參數,一個(gè)是用戶(hù)Entry的DN,一個(gè)是該用戶(hù)的口令。

  B. LDAP Compare —— LDAP Compare是一個(gè)為兼容X.500的古老操作,它用于檢查一個(gè)屬性值是否包含在指定Entry中的屬性里。這樣我們可以在知道用戶(hù)password存放在哪個(gè)屬性的前提下,對該屬性進(jìn)行compare。如果成功,表明口令正確。如果屬性值為散列后的口令(絕大多數情況),有的LDAP Server支持這樣的驗證,有的不支持,比如iPlanet LDAP Server 5。

  驗證成功后,Provider將使用Console中關(guān)于Groups和Memberships中的配置,查找用戶(hù)屬于哪些LDAP Group,而且由于這些組本身可能會(huì )有一些嵌套,因此對于搜索到的組還需要進(jìn)行查詢(xún)。即使用filter: (&(uniquemember=uid=ZHANGSAN,ou=staff,ou=people,o=examples)(objectclass=groupOfUniqueNames))從Group Base DN開(kāi)始搜索,將返回用戶(hù)所屬的第一層次Group;然后對于這些返回的組DN,仍然需要使用上面的Filter進(jìn)行搜索(uniquemember值替換為組的DN),找出嵌套關(guān)系,直到查詢(xún)完成沒(méi)有組嵌套為止(此處需要防止陷入嵌套的循環(huán)中,比如Group A 包含了Group B; Group B又包含了Group A,有的LDAP Server可以自動(dòng)檢測出,有的需要我們程序來(lái)判斷)。

  然后將用戶(hù)登錄的賬號,用戶(hù)所屬組的名字(屬性CN的值或其他),放入Subject中。最后調用Principal Validator Provider,對Subject中的principals進(jìn)行簽名,來(lái)表明該Subject是這個(gè)Provider生成的。這樣防止其他攻擊者偽造Subject以及Principal進(jìn)行欺騙。此處也可以解釋為何在不同的WLS Domain間不能夠傳遞Subject,我們可以通過(guò)設置域信任來(lái)完成這種Subject的傳遞。設置域信任使用的Credential就是簽名用的Key。

  圖3-1-5表明了如何設置WebLogic Domain Credential,默認情況下WebLogic Server會(huì )在啟動(dòng)的時(shí)候隨即生成一個(gè)Credentials(在WLS6.1時(shí),這個(gè)值就是system用戶(hù)的口令):

  可以想見(jiàn)如果我們實(shí)現自己的Principal Validator Provider,讓它去一個(gè)集中的驗證服務(wù)器中對Subject進(jìn)行簽名,或者驗證Subject,這樣就可以實(shí)現域信任,進(jìn)而完成Application(EJB Tier)層的SSO。

  通過(guò)以上的討論,我們對于實(shí)現自己的LDAP Authentication Provider是不是又增加了一份信心?

4 定制自己的Custom LDAP Authentication Provider

  為何要定制自己的Authentication Provider? 由于WebLogic Server已經(jīng)提供了很多默認的Authentication Provider在一般情況下我們確實(shí)沒(méi)有必要實(shí)現自己的Provider。但是面對某些針對安全方面的復雜需求時(shí),WebLogic Server提供的Provider很有可能不滿(mǎn)足這些需求,此時(shí)就需要我們定制自己的Provider。

  在這一章的開(kāi)頭部分中我需要簡(jiǎn)要討論關(guān)于WebLogic MBean Types,以及WebLogic Console擴展等內容,目的在于讓讀者了解到我們通過(guò)WebLogic Console可以完成對Custom Security Provider的配置和部署,我將以WebLogic 提供的Sample Security Provider為示例進(jìn)行說(shuō)明。詳細的信息可以參考以下的一些資源:

http://e-docs.bea.com/wls/docs81/dvspisec/atn.html#1106272
http://e-docs.bea.com/wls/docs81/dvspisec/atn.html#1106241

  上面兩個(gè)鏈接描述了如何創(chuàng )建MBean Types以及在控制臺上配置Custom Authentication Provider.下面這個(gè)鏈接中專(zhuān)門(mén)介紹了WebLogic Console的擴展:

http://dev2dev.bea.com.cn/techdoc/webser/2005012102.html

  讀者可以從http://dev2dev.bea.com/codelibrary/code/security_prov81.jsp下載WLS提供的Sample Security Provider。

4.1 MBean Types和WebLogic Console
  一般情況下,人們可能更習慣通過(guò)WebLogic Console對Security Provider進(jìn)行配置。這里我將簡(jiǎn)要描述這個(gè)過(guò)程,以及可以到達的一個(gè)效果。限于篇幅就不詳細討論了。

  從weblogic.management.security.authentication.Authenticator擴展MBean Types。 MBean Types是MBean(http://java.sun.com/products/JavaManagement/wp/)的工廠(chǎng),我們擴展SampleSecurityProviders81 包中的SimpleSampleAuthenticator.xml(MBean Definition File),增加一個(gè)我們自定義的參數LDAP Server IP:

<MBeanAttribute
  Name = "LDAPServerIP"
  Type = "java.lang.String"
  Writeable = "true"
  Default = ""127.0.0.1""
/>

  這樣在Provider中我們將通過(guò)MbeanMaker(WLS提供)生成的SimpleSampleAuthenticatorMBean中取到這個(gè)屬性:SimpleSampleAuthenticatorMBean.getLDAPServerIP()。MBean將在初始化Provider的時(shí)候作為參數傳入。這樣我們就可以通過(guò)MBean中的參數控制Provider的行為。

  當然這個(gè)參數是可以在WebLogic Console中設置的,通過(guò)對MBean Types的擴展,在WebLogic Console上看到的畫(huà)面如下:


圖4-1-1

  這樣我們可以通過(guò)Console修改配置參數(修改的Security Provider參數將保存在config.xml中,默認的值將保存在MBean Jar File中)。

4.2 為何定制LDAP Authentication Provider
  
當我們面臨越來(lái)越復雜的安全方面的業(yè)務(wù)需求時(shí),或者面臨較高的性能要求,需要根據目標LDAP做針對性的優(yōu)化時(shí),或者需要將我們已有的認證,或授權模塊集成到WebLogic平臺時(shí),WebLogic提供的現成的Provider往往不能滿(mǎn)足我們的需求。

4.2.1 復雜的業(yè)務(wù)需求
  當系統要求用戶(hù)不僅僅輸入用戶(hù)名(j_username),口令(j_password),還需要輸入其他信息,比如登錄的地點(diǎn),系統的名字,用戶(hù)的類(lèi)型等等。如果是采用基于J2EE Form的驗證方式, 登錄信息需要提交到j(luò )_security_check(Servlet規范定義由容器負責實(shí)現的Servlet),導致我們沒(méi)法處理更多的信息。

  這個(gè)時(shí)候,如果能夠實(shí)現我們自己的 Authentication Provider,那么我們就可以通過(guò)TextInputCallback來(lái)獲取登錄表單中更多的信息了;進(jìn)而通過(guò)這些信息在Provider中完成符合我們需要的處理。

  比如搜狐的登錄頁(yè)面上需要選擇用戶(hù)的類(lèi)型:


圖4-2-1

4.2.2 性能需求或者調優(yōu)
  有時(shí),有的用戶(hù)會(huì )比較困惑為何WebLogic LDAP Security Provider在壓力測試中的表現不很理想,用戶(hù)需要較長(cháng)時(shí)間的等待,才能夠登錄到系統中。由于這些Provider是 WebLogic產(chǎn)品的一部分,因此缺乏對不同目標LDAP Server的有針對性的優(yōu)化。這樣就使得我們無(wú)法充分發(fā)揮具體LDAP Server的性能調優(yōu)。

  比如,有的LDAP Server支持動(dòng)態(tài)組(LDAP Dynamic Group,成員關(guān)系是運行時(shí)根據ldap server,basedn,filter等動(dòng)態(tài)決定的),可以使用如下的Filter查詢(xún)用戶(hù)屬于哪些動(dòng)態(tài)組:

  (uniquemember=uid=MAXQ,ou=staff,ou=people,o=examples)

  有的LDAP Server雖然支持動(dòng)態(tài)組,但是支持的有限,不能使用上面的Filter獲取用戶(hù)屬于哪些動(dòng)態(tài)組。在WebLogic iPlanet Authentication Provider的實(shí)現中,它先是搜索出全部的動(dòng)態(tài)組,然后再遍歷這些動(dòng)態(tài)組,依次去LDAP中檢查用戶(hù)是否屬于一個(gè)組;很明顯,這樣雖然最大程度的滿(mǎn)足了不同LDAP Server的要求(從產(chǎn)品的角度講可能是必須的),但是與LDAP交互的次數大增,并發(fā)用戶(hù)量一大性能下降的比較明顯。

  此時(shí),如果系統中的LDAP支持上面的Filter或者有更好的搜索方式,那么完全可以通過(guò)定制Provider完成對性能的優(yōu)化。

4.2.3 已有權限控制的集成
  如果系統中已經(jīng)存在了現成的滿(mǎn)足需求的認證模塊,并且已經(jīng)很好的工作;在系統轉向J2EE架構,并使用WebLogic Server做J2EE容器時(shí),我們可能會(huì )更愿意直接在Provider中加入這個(gè)認證模塊。

  綜上,我只是列舉了一些可以驅動(dòng)我們開(kāi)發(fā)自己Provider的需求,相信在讀者實(shí)際工作中可能會(huì )面臨更復雜的情況,開(kāi)發(fā)自己的Provider將是一個(gè)非常好的選擇。

4.3 LDAP Authentication Provider實(shí)現
  本文之前為了表述的方便沒(méi)有單獨提到LoginModule,認為L(cháng)oginModule的行為就是LDAP Authentication Provider的行為。到了目前的具體實(shí)現階段,我們必須分開(kāi)Authentication Provider和JAAS LoginModule。最終部署到WebLogic上的實(shí)際只是LDAP AuthenticationProvider Implements。

  WebLogic SecurityFramework通過(guò)Authentication Provider獲取具體的JAAS LoginModule。通過(guò)LoginModule完成最終登錄的工作。因此我們必須先實(shí)現一個(gè)AuthenticationProvider。

  我們一般通過(guò)weblogic.security.spi.AuthenticationProvider 來(lái)實(shí)現自己的AuthenticationProvider。這里介紹其中的幾個(gè)重要方法:

  a) public void initialize(ProviderMBean mbean, SecurityServices services)
初始化一個(gè)Provider。通過(guò)參數MBean我們可以獲取到在WebLogic Console中配置的各項參數。進(jìn)而初始化我們的Provider,然后通過(guò)Provider傳遞到LoginModule中。

  b) public void shutdown()
釋放一些與Provider,LoginModule等相關(guān)的資源。

  c) public AppConfigurationEntry getLoginModuleConfiguration()
這個(gè)方法非常重要,通過(guò)該方法,WebLogic Security Framework可以獲取用于初始化LoginModule的AppConfigurationEntry。AppConfigurationEntry中存放了LoginModule的類(lèi)名等信息,比如使用如下代碼返回一個(gè)AppConfigurationEntry:

  return new AppConfigurationEntry(
    "examples.security.providers.authentication.SampleLoginModuleImpl",
    controlFlag,
  options);

  其中LoginModule Name就

是"examples.security.providers.authentication.SampleLoginModuleImpl",我們通過(guò)它就可以實(shí)例化一個(gè)LoginModule并通過(guò)LoginModule.initialize()方法進(jìn)行初始化。

  d) public AppConfigurationEntry getAssertionModuleConfiguration()
該方法將返回一個(gè)與Identity Assertion Provider關(guān)聯(lián)的LoginModule。這個(gè)Assertion LoginModule,將只會(huì )驗證用戶(hù)是否存在,以及如果存在返回用戶(hù)的Principals。 該方法也比較重要,需要正確實(shí)現,比如我們使用CLIENT-CERT這種WEB認證方式,該方法就會(huì )被調用。

  Provider的實(shí)現比較簡(jiǎn)單,讀者可以在http://dev2dev.bea.com/codelibrary/code/security_prov81.jsp下載WebLogic提供的Samples,查看SampleAuthenticationProviderImpl的代碼。

4.4 LDAP LoginModule 邏輯流程
  實(shí)現了Provider后,必須擁有我們自己的LDAP LoginModule。下面是一個(gè)簡(jiǎn)單的用于演示的驗證邏輯流程圖。實(shí)際的一個(gè)LoginModule由于不同的業(yè)務(wù)需求,情況可能會(huì )復雜得多。這里只是描述了最核心最基本的邏輯,使讀者能有一個(gè)清晰的思路。后面我將以這個(gè)流程為例進(jìn)行實(shí)現。

4.5 LoginModule代碼示例和講解
  這里我將使用Netscape LDAP SDK for java作為開(kāi)發(fā)工具實(shí)現LDAP相關(guān)的操作,讀者可以到http://docs.sun.com/db/doc/816-6402-10 下載開(kāi)發(fā)手冊,從http://www.mozilla.org/directory/ 下載SDK 包。一般來(lái)說(shuō)還可以通過(guò)JNDI來(lái)操作LDAP,我個(gè)人認為Sun LDAP JNDI Provider中關(guān)于Connection Pool的實(shí)現非常優(yōu)秀。但不管使用哪種SDK,對LDAP的編程原理上基本都是相同的(因為基于同樣的LDAP協(xié)議),不同的可能僅僅是接口,類(lèi)的名字而已。

4.5.1 初始化Connection Pool
  為了有效使用寶貴,并且有限的LDAP連接,必須使用連接池。下面的代碼初始化了一個(gè)LDAP連接池:

/**
*
*/
static ConnectionPool pool;
/** * * LDAPException
*/ public LdapClient()
  throws LDAPException
    {
      pool= new ConnectionPool(
        1, 150, "127.0.0.1", 389, "cn=Directory Manager", "88888888");
}

  Sun JNDI LDAP Service Provider(JDK1.4)中可以通過(guò)在環(huán)境變量中設置具體的參數來(lái)啟用連接池,達到復用連接的目的。具體可以參考鏈接:http://java.sun.com/products/jndi/tutorial/ldap/connect/index.html,下面是示例代碼:

Hashtable env= new Hashtable();

env.put("com.sun.jndi.ldap.connect.pool", "true");
DirContext ctx= new InitialDirContext( env);

4.5.2 根據用戶(hù)輸入的登錄賬號,搜索用戶(hù)Entry
  下面這個(gè)方法實(shí)現了從LDAP中搜索用戶(hù)Entry DN的最簡(jiǎn)單的過(guò)程。實(shí)際上我們可以在其中實(shí)現很多定制的功能。比如允許用戶(hù)使用多于一個(gè)的賬號登錄,只要這些賬號能夠通過(guò)LDAP Searche最終返回一個(gè)唯一的用戶(hù)DN即可。

  *
   * LDAPException
   */
  public String getUserDN( String uid) throws LDAPException{
    LDAPConnection conn= pool.getConnection();
    try {
      String[] attrs= new String[]
{};
      LDAPSearchResults sr= conn.search("o=examples", 2, "(uid="+ uid +")", attrs, false);
      if ( sr.hasMoreElements()) {
        LDAPEntry entry= sr.next();
        return entry.getDN();
}
    throw new LDAPException("No Such Object:"+ uid,
        LDAPException.NO_SUCH_OBJECT);
    }catch ( LDAPException ex) {
      throw ex;
    }finally {
      try {
        if (conn!= null) pool.close(conn);
      }catch ( Exception ex)
{}
    }
  }

  首先需要從池中獲取一個(gè)LDAP連接,然后使用LDAPConnection.search方法進(jìn)行搜索。我這里以一個(gè)典型的LDAP Search接口為例進(jìn)行說(shuō)明,其他API比如JNDI等,基于同樣的LDAP協(xié)議,接口中同樣參數的含義都是相同的。

public LDAPSearchResults search(java.lang.String base,
  int scope,
  java.lang.String filter,
  java.lang.String[] attrs,
  boolean attrsOnly)

  1) Base: 表明從該Basedn開(kāi)始搜索,可以通過(guò)MBean獲取

  2) Scope: 搜索的范圍:

    a) LDAPv2.SCOPE_BASE, 只搜索basedn指定的entry
    b) LDAPv2.SCOPE_ONE, 在basedn的下一級entry中搜索,不包括basedn
    c) LDAPv3.SCOPE_SUB,在basedn的全部下級entry中搜索,包括basedn

  3) Filter:過(guò)慮條件。比如uid=ZHANGSAN,搜索UID為ZHANGSAN的用戶(hù);再比如uid=ZHANG*,搜索 ZHANG開(kāi)頭的賬號;或者uid=Z*S,搜索以Z開(kāi)頭S結尾的賬號。前面已經(jīng)介紹過(guò)這里就不多說(shuō)了。

  4) attrs:返回該attrs數組中指定的屬性,比如new String[]{“uid”},只返回屬性uid,其他屬性將會(huì )不在結果中返回。 一般來(lái)說(shuō)我們會(huì )要求開(kāi)發(fā)人員只將需要的屬性返回,這樣避免返回無(wú)用的屬性,降低網(wǎng)絡(luò )和Server等方面的資源開(kāi)銷(xiāo);而且如果存在一個(gè)有較大屬性集合的Entry,并且你并不使用到這個(gè)較大的屬性集合。舉個(gè)實(shí)際例子來(lái)說(shuō),比如你的系統中擁有很多成員數目超過(guò)2萬(wàn)或者更多的LDAP Groups,并且你希望通過(guò)LDAP Search找出某一個(gè)用戶(hù)屬于的組CN,那么搜索結果只返回組的CN已經(jīng)可以滿(mǎn)足你的要求了,這時(shí)就沒(méi)有必要將全部member屬性也返回了。這在后面我會(huì )有代碼來(lái)說(shuō)明。

  這里還有一點(diǎn)很重要的細節,相信對讀者會(huì )有幫助。比如,你希望搜索到modifytimestamp等Operational Attributes。這些屬性(LDAP Server自己負責維護的,用戶(hù)無(wú)法修改的)必須要在參數attrs中指定,LDAP Server才會(huì )返回給客戶(hù)端。如果用戶(hù)希望返回全部User Attributes的同時(shí),返回指定的 Operational Attributes那該怎么辦?不在attrs列表中的屬性將不會(huì )被返回,一旦我指定了attrs,是否需要將全部的屬性都列在attrs參數中?實(shí)際上此時(shí)只需要傳入 new String[]{ “*”, “createtimestamp”}這樣的參數即可;“*”號即代表了全部的User Attributes。在Sun JNDI LDAP Service Provider中也是這樣,盡管找遍Sun關(guān)于JNDI的文檔也找不到這樣的說(shuō)明。LDAP協(xié)議對此的說(shuō)明在 http://www.ietf.org/rfc/rfc2251.txt 第28頁(yè)。

  5) attrsOnly:只返回屬性名稱(chēng),不包含值。我們一般設置為false。

  我們下面看一下Sun JNDI中關(guān)于LDAP Search的接口:

public NamingEnumeration search(String name,
  String filter,
  SearchControls cons)
  throws NamingException
name參數就是上面的basedn,SearchControls中封裝更多的設置,比如:SearchControls. setSearchScope(int scope)其中的scope對應上面的2); SearchControls.setReturningAttributes(String[] attrs),設置指定返回的屬性,對應上面的4)。

  其他的參數還包括Size Limit,即限制搜索結果的數目(LDAP返回的Entry一般情況下是沒(méi)有排序的,除非使用一些Sort Control),當你的搜索可能會(huì )返回成千上萬(wàn)的Entry時(shí),限制搜索的數目是非常明智也是必須的。關(guān)于這些,讀者可以參考API文檔或者LDAP協(xié)議。

4.5.3 根據用戶(hù)的Entry DN,和用戶(hù)輸入的口令完成身份驗證
  
下面的方法實(shí)現了到LDAP的身份驗證。LDAP中的用戶(hù)實(shí)際上就是一個(gè)LDAP Entry,一次驗證實(shí)際是將Connection與這個(gè)Entry進(jìn)行綁定,因此驗證時(shí)我們需要兩個(gè)必須的參數,一個(gè)是Entry的DN,一個(gè)是口令。LDAP的身份驗證方式有多種,包括SASL以及基于證書(shū)的驗證等,我們這里只介紹Simple Authentication。關(guān)于SASL更多信息讀者可以參考:http://www.ietf.org/rfc/rfc2222.txt。

  /**
   *
   * dn
   * pwd
   *
   * LDAPException
   */
  public boolean authentication( String dn, String pwd) throws LDAPException {
    LDAPConnection conn= pool.getConnection();
    try {
      conn.authenticate( dn, pwd);
      return true;
    }catch ( LDAPException ex) {
      if ( ex.getLDAPResultCode()== LDAPException.INVALID_CREDENTIALS) {
        return false; // 用戶(hù)口令錯誤 }
      if ( ex.getLDAPResultCode()== LDAPException.NO_SUCH_OBJECT) {
        return false; // 用戶(hù)不存在 }
      throw ex;
    }finally {
      try {
        if ( conn!= null) pool.close(conn);
      }catch ( Exception ex) {
      }
    }
  }


  我們這里使用 LDAP Bind操作完成對用戶(hù)的身份驗證。本文前面曾提到也可以使用LDAP Compare,通過(guò)比較口令屬性(userpassword)中的值來(lái)完成驗證。我們需要根據不同的LDAP Server選擇合適的驗證方法。

  比如iPlanet LDAP Server 5,只能通過(guò)Bind完成認證;而Oracle Internet Directory可以通過(guò)LDAP Compare完成驗證,而且還支持口令策略。

  如果我們使用了連接池,連接池中的連接一般都是使用權限較大的用戶(hù)初始化的,這樣這些連接才可以完成對LDAP的搜索操作;而當通過(guò)這些連接對普通用戶(hù)進(jìn)行身份驗證時(shí),如果通過(guò)驗證,連接的身份將被改變?yōu)槠胀ǖ挠脩?hù)(或稱(chēng)為與普通用戶(hù)的身份關(guān)聯(lián))。普通用戶(hù)很可能沒(méi)有除了bind以外的任何權限,所以在連接被放入池中前,我們必須要恢復連接的身份。

  這樣我們必須執行兩次LDAP Bind,一次用于對普通用戶(hù)驗證身份;一次用于恢復連接的較大權限的用戶(hù)身份。我們看到這樣效率是比較低的,可能你在LDAP Server端統計有2萬(wàn)次bind請求,實(shí)際上只有1萬(wàn)人次登錄。

  對于特定的LDAP Server,比如 Oracle Internet Directory,可以通過(guò)LDAP Compare對用戶(hù)身份進(jìn)行驗證,并且不會(huì )改變連接關(guān)聯(lián)的用戶(hù)身份。這樣我在使用池的情況下只需要一次LDAP Compare即可。效率有很大提高。如果不通過(guò)定制LDAP Authentication Provider,這樣的調優(yōu)是沒(méi)法實(shí)現的。

  Netscape LDAP SDK的ConnectionPool的實(shí)現中,在連接放入池中前會(huì )檢查連接的身份,如果身份被改變,那么會(huì )重新進(jìn)行bind。所以我們沒(méi)有必要在代碼中再做bind。

4.5.4 根據用戶(hù)的DN搜索用戶(hù)屬于的組列表
  
有了上面的基礎后,這個(gè)方法就很容易理解了。下面我們來(lái)看看如何返回用戶(hù)所屬的組。

/**
   *
   * groupbasedn
   * memberDn
   *
   * LDAPException
   */
  public List getGroupMembership( String groupbasedn, String memberDn) throws LDAPException {
    LDAPConnection conn= pool.getConnection();
    try {
      LDAPSearchResults sr= conn.search(
          groupbasedn,
          2,
          "(uniquemember="+ memberDn +")",
          new String[] {"cn"},
          false);
      List groups= new java.util.ArrayList();
      while ( sr.hasMoreElements()) {
        LDAPEntry entry= sr.next();
        LDAPAttribute attr= entry.getAttribute("cn");
        if ( attr!= null) {
          String[] values= attr.getStringValueArray();
          if ( values!= null && values.length>0) groups.add( values[0]);
        }
      }
      return groups;
    }catch ( LDAPException ex) {
      throw ex;
    }finally {
      try {
        if ( conn!= null) pool.close(conn);
      }catch ( Exception ex) {
      }
    }
  }

  成員和組的membership主要是通過(guò)uniquemember或者 member屬性來(lái)定義的。成員不僅僅可以使用用戶(hù),也可以是組,因為組可以嵌套。

  a) 上面的方法中只實(shí)現了一個(gè)層次的搜索,即用戶(hù)——組的搜索,而組間的嵌套搜索沒(méi)有實(shí)現。讀者可以根據系統內的具體情況,在此處也可以做一些優(yōu)化。

  b) 組成員的數量可能比較大,為了避免不必要的開(kāi)銷(xiāo),我們指定只返回組的cn屬性。

  c) 動(dòng)態(tài)組的優(yōu)化。在WebLogic默認的實(shí)現中,Provider(實(shí)際為L(cháng)oginModule)會(huì )不斷的拿動(dòng)態(tài)組中定義的URL中的filter和用戶(hù)的DN去LDAP做搜索,來(lái)看用戶(hù)是否屬于該組。本文前面也討論了,這樣效率很低,完全可以放在Provider本地實(shí)現URL和Entry的匹配。

4.5.5 LoginModule中的login()方法實(shí)現
  
一切準備就緒后,我們就可以完成LoginModule.login()這個(gè)最核心的方法了。下面我根據代碼中的注釋逐條說(shuō)明。

  // A
  boolean loginSucceeded;
  // B
  List principals= new java.util.ArrayList();
  /**
   *
   *
   * LoginException
   */
  public boolean login() throws LoginException {
    // C
    Callback[] callbacks= new Callback[] {
        new NameCallback("username: "),
        new PasswordCallback("password: ",false)};
    try {
      callbackHandler.handle( callbacks);
    }catch (IOException e) {
      throw new LoginException(e.toString());
    }catch (UnsupportedCallbackException e) {
      throw new LoginException(e.toString() + " " +e.getCallback().toString());     }
    //
    String userName = ((NameCallback)callbacks[0]).getName();
    if ( userName== null || userName.length()== 0) {
      throw new LoginException("User login name is empty!");
    }
    //
    PasswordCallback passwordCallback= (PasswordCallback)callbacks[1];     char[] password = passwordCallback.getPassword();
    passwordCallback.clearPassword();
    if ( password== null || password.length== 0) {
      throw new LoginException("User password is empty!");
    }
    try {
      // D
      String dn= this.getUserDN( userName);
      if ( dn== null) {
        throw new LoginException("User "+ userName +" doesn‘t exist.");
      }
      // E
      boolean authResult= this.authentication( dn, String.valueOf( password));       if ( authResult== false) {
        throw new FailedLoginException("User login failed.");
      }
      // F
      principals.add( new WLSUserImpl( userName));
      // G
      List groups= this.getGroupMembership( "ou=groups,o=examples", dn);       for ( int i=0, n=groups.size(); i<n; i++) {
        String cn= String.valueOf(groups.get(i));
        // H
        principals.add( new WLSGroupImpl(cn));
      }
    }catch ( LDAPException ex) {
      java.io.StringWriter sw = new java.io.StringWriter();  
     ex.printStackTrace(new java.io.PrintWriter(sw));
      sw.flush();
      throw new LoginException( sw.toString());
    } 
       return loginSucceeded= true;
  }

  a) 用于保存驗證結果,在后續方法(commit等)中使用

  b) 用于保存和用戶(hù)關(guān)聯(lián)的Principal,在后續方法(commit等)中使用

  c) 在JAAS中通過(guò)CallbackHandler來(lái)完成用戶(hù)和底層安全認證系統間信息的交換,這里我們通過(guò)CallbackHandler獲取用戶(hù)輸入的登錄賬號和口令。CallbackHandler將在初始化LoginModule時(shí)由WebLogic Security Framework傳入。讀者可能會(huì )問(wèn),我是否可以在此要求WebLogic Security Framework傳入我自己實(shí)現的CallbackHandler,進(jìn)而獲取更多的信息,支持更多的Callback?很遺憾,不可以。只有在一種情況下(本文前面也提到)有一個(gè)變通,就是在Web應用中,通過(guò)Form Based這種認證方式進(jìn)行用戶(hù)身份驗證時(shí),可以獲取更多的登錄表單中提交的cgi變量。

  下面的代碼將演示這種技術(shù):

    Callback[] callbacks= new Callback[] {
        new NameCallback("username: "),
        new PasswordCallback("password: ",false),
        new TextInputCallback("my_hidden_field")};
    try {
      callbackHandler.handle( callbacks);
    }catch (IOException e) {
      throw new LoginException(e.toString());
    }catch (UnsupportedCallbackException e) {
      throw new LoginException(e.toString() + " " +e.getCallback().toString());     }
    String value= ((TextInputCallback)callbacks[2]).getText();

  這樣我們通過(guò)((TextInputCallback)callbacks[2]).getText()來(lái)獲取表單中更多的信息。其中TextInputCallback的Prompt必須要和表單中對應域的名字一致,否則取不到信息。如果有多個(gè)域,則需要傳入多個(gè)TextInputCallback。

  同時(shí)如果登錄表單中沒(méi)有這些對應TextInputCallback的域,或者使用JNDI方式驗證,那么會(huì )拋出UnsupportedCallbackException。

  下面是一個(gè)符合Servlet安全規范的登錄表單,其中域my_hidden_field的值將通過(guò)CallbackHandler傳遞到的TextInputCallback中:

<html>
  <form method=”POST” action=”j_security_check”>
    <input type=”text” name=”j_username”>
    <input type=”password” name=”j_password”>
    <input type=”hidden” name=”my_hidden_field”value=”Hello Callback!”>
  </form>
</html>

  d) 生成一個(gè)用于存放Principal的集合對象
  e) 通過(guò)登錄賬號獲取LDAP中的Entry DN
  f) 通過(guò)DN和用戶(hù)口令進(jìn)行身份驗證
  g) 將通過(guò)驗證的用戶(hù)名加入到Principal列表中,這些以后都將代表用戶(hù)的一定權限
  h) 查找用戶(hù)屬于哪些組
  i) 將這些組的名字加入到Principal列表中

4.5.6 LoginModule中的commit()和abort()方法實(shí)現
  
完成了以上的驗證后,我們需要通過(guò)LoginModule.commit()方法提交驗證結果;或者abort()方法取消驗證結果。

  // A
  private Subject subject;
    /**
   *
   *
   * LoginException
   */
  public boolean commit() throws LoginException { if (loginSucceeded) {
  // B
      subject.getPrincipals().addAll(principals);
      return true;
    }else {
      return false;
    }
  }
    /**
   *
   *
   * LoginException
   */
    public boolean abort() throws LoginException {
    // C
    subject.getPrincipals().removeAll(principals);
    return true;
  }    

 

  我這里仍然通過(guò)代碼中的注釋進(jìn)行相應的說(shuō)明:

  a) JAAS Subject,在LoginModule初始化時(shí),由WebLogic Security Framework負責傳入,用戶(hù)的權限信息(Principals等)都將封裝到該Subject中。同時(shí)Principal Validator會(huì )對Subject中的Principals進(jìn)行簽名,防止被黑客纂改。

  b) 用戶(hù)認證成功的情況下,將用戶(hù)關(guān)聯(lián)的Principals加入到Subject中。這樣用戶(hù)在進(jìn)行后續的訪(fǎng)問(wèn)時(shí),WebLogic Security Framework會(huì )檢查與用戶(hù)關(guān)聯(lián)的Subject中是否有可以訪(fǎng)問(wèn)受限資源的Principal。

  c) 用戶(hù)登錄失敗的情況下(有可能是其他的LoginModule導致的整體登錄失敗,具體參考JAAS Control Flag),我們在commit中添加的Principals必須從Subject中刪除。


  通過(guò)上面的描述和討論,相信讀者已經(jīng)對如何實(shí)現一個(gè)LDAP AuthenticationProvider/LoginModule有了比較清楚的了解。限于篇幅省略了很多細節,對此有需要的讀者可以根據文中給出的相關(guān)鏈接做進(jìn)一步的了解;或者與我交流。從這里我們也可以看到核心的邏輯還是比較簡(jiǎn)單的。其中將LDAP Group作為用戶(hù)的Principal,是J2EE Security與LDAP Security結合的非常重要的一步。通過(guò)這種結合,我們可以將LDAP作為后端,設計出基于J2EE,JAAS的用戶(hù)身份驗證,權限管理等系統。

5 部署中的注意事項
  開(kāi)發(fā)完成LDAP Authentication Provider后,需要將通過(guò)WebLogic MBean Maker生成的MBean Jar File放到/server/lib/mbeantypes目錄下。由于WebLogic Server在啟動(dòng)時(shí)會(huì )加載這些Provider,因此在一個(gè)分布式的環(huán)境中,WebLogic Domain內的全部WLServer(包括Managed Server)均需要部署該Jar包。

  同時(shí)由于使用了Provider MBean,因此,當你刪除了MBean Types中定義的,并且通過(guò)修改保存在config.xml(WebLogic Domain配置文件)中的屬性時(shí),重新部署的Jar包會(huì )導致WebLogic Server無(wú)法正常啟動(dòng),因為它沒(méi)有辦法按照config.xml中配置的屬性初始化MBean。此時(shí)需要手工修改config.xml,刪除相關(guān)的屬性即可。

<examples.security.providers.authentication.simple.SimpleSampleAuthenticator
  ControlFlag="OPTIONAL"
  Name="Security:Name=myrealmSimpleSampleAuthenticator"
  UserBaseDN="ou=people, o=examples" Realm="Security:Name=myrealm"/>

  比如UserBaseDN已經(jīng)不需要通過(guò)MBean來(lái)管理,并且在MBean Types中已經(jīng)刪除,那么直接刪除這里的UserBaseDN="ou=people, o=examples" 就可以了。

6 結束語(yǔ)
  本文所討論的內容有些過(guò)于廣泛,從我個(gè)人角度講,寫(xiě)起來(lái)也比較困難,很多技術(shù)問(wèn)題沒(méi)有進(jìn)行深入的討論。其實(shí)只是希望通過(guò)本文,能夠幫助讀者對WebLogic Security,J2EE Security,LDAP Security以及JAAS有一個(gè)初步的認識;能夠給希望實(shí)現LDAP Authentication Provider,或者被WebLogic LDAP Authentication Provider困惑的讀者一些啟示。只要能夠對讀者有所幫助,本文的目的就算達到了。

  限于篇幅,本文很多地方的表述可能并不清晰,也可能會(huì )有一些錯誤,如果在閱讀過(guò)程中產(chǎn)生任何疑問(wèn)或者有任何看法都可以通過(guò)E-mail來(lái)與我交流,我也非常希望能和大家交流。

7 參考資料
a) http://e-docs.bea.com/wls/docs81/secwlres/types.html#1213777 關(guān)于WebLogic Resource的更多說(shuō)明
b) http://e-docs.bea.com/wls/docs81/security/index.html 關(guān)于WebLogic Security的全部?jì)热?br>c) http://e-docs.bea.com/wls/docs81/dvspisec/rm.html#1145542 關(guān)于Role Mapping Provider的更多內容
d) http://dev2dev.bea.com.cn/techdoc/webser/2005012102.html 關(guān)于WebLogic Console的擴展
e) http://dev2dev.bea.com/codelibrary/code/security_prov81.jsp Custom Seuciryt Provider的Samples
f) http://java.sun.com/products/JavaManagement/wp/ 更多關(guān)于Sun JMX
g) http://java.sun.com/products/jndi/tutorial/ldap/connect/index.html 關(guān)于如何使用Sun JNDI LDAP Service Provider中提供的連接池
h) http://www.ietf.org/rfc/rfc2254.txt 更多關(guān)于LDAP Filter
i) http://www.ietf.org/rfc/rfc2251.txt LDAP V3協(xié)議
j) http://www.ietf.org/rfc/rfc2222.txt 更多關(guān)于SASL

 作者簡(jiǎn)介
馬曉強是高級軟件工程師,現在廣東從事J2EE,LDAP相關(guān)的設計開(kāi)發(fā)工作。對WebLogic,LDAP以及Single Sign-On等產(chǎn)品、技術(shù)很感興趣。

  作者其它文章
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
JAAS基礎認證和授權機制
JavaEye - portal sso
How WebLogic Portal Uses the WebLogic Server Security Framework
Spring Security3 使用中心認證服務(wù)(CAS)進(jìn)行單點(diǎn)登錄
用于跨域啟用集中式身份驗證的面向服務(wù)架構
tomcat下jaas配置實(shí)例
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久