Liferay 的JAAS權限管理

 

Liferay的權限管理實現了一個典型的JAAS管理策略

JAAS是什麼?

Java Authentication Authorization Service(JAAS,Java驗證和授權API)提供了靈活和可伸縮的機制來保證客戶端或服務器端的Java程序。JAAS強調的是通過驗證誰在運行代碼以及他/她的權限來保護系統面受用戶的攻擊。它能夠將一些標準的安全機制,例如Solaris NIS(網絡信息服務)、Windows NT、LDAP(輕量目錄存取協議),Kerberos等通過一種通用的,可配置的方式集成到系統中,而不改變應用程序級的代碼。

核心JAAS類

JAAS的核心類和接口可以被分爲三種類型,大多數都在javax.security.auth包中,還有一些接口的實現類在com.sun.security.auth包中。

普通類 Subject,Principal,Credential(憑證)

Subject類代表了一個驗證實體,它可以是用戶、管理員、Web服務,設備或者其他的過程。該類包含了三中類型的安全信息:

1)  身份(Identities):由一個或多個Principal對象表示

2)  公共憑證(Public credentials):例如名稱或公共密鑰

3)  私有憑證(Private credentials):例如口令或私有密鑰

Principal對象代表了Subject對象的身份。它們實現了java.security.Principal和java.io.Serializable接口。在Principal類中,最重要的方法是getName()。該方法返回一個身份名稱。在Subject對象中包含了多個Principal對象,因此它可以擁有多個名稱。例如:登錄名稱、身份證號和Email地址都可以作爲用戶的身份標識。

Credential憑證並不是一個特定的類或藉口,它可以是任何對象。憑證中可以包含任何特定安全系統需要的驗證信息,例如標籤(ticket),密鑰或口令。Subject對象中維護着一組特定的私有和公有的憑證,這些憑證可以通過Subject 方法getPrivateCredentials()和getPublicCredentials()獲得。這些方法通常在應用程序層中的安全子系統被調用。

JAAS驗證原理

     驗證 LoginContext,LoginModule,CallBackHandler,Callback

驗證:LoginContext

  在應用程序層中,可以使用LoginContext對象來驗證Subject對象。LoginContext對象同時體現了JAAS的動態可插入性(Dynamic Pluggability),因爲當創建一個LoginContext的實例時,需要指定一個配置。LoginContext通常從一個文本文件中加載配置信息,這些配置信息告訴LoginContext對象在登錄時使用哪一個LoginModule對象。

  下面列出了在LoginContext中經常使用的三個方法:

     login () 進行登錄操作。該方法激活了配置中制定的所有LoginModule對象。如果成功,它將創建一個經過了驗證的Subject對象;否則拋出LoginException異常。

     getSubject () 返回經過驗證的Subject對象

     logout () 註銷Subject對象,刪除與之相關的Principal對象和憑證

驗證:LoginModule

  LoginModule是調用特定驗證機制的接口。包含了下面幾種LoginModule的實現類:

       JndiLoginModule 用於驗證在JNDI中配置的目錄服務

       Krb5LoginModule 使用Kerberos協議進行驗證

       NTLoginModul 使用當前用戶在NT中的用戶信息進行驗證

       UnixLoginModule 使用當前用戶在Unix中的用戶信息進行驗證

   同上面這些模塊綁定在一起的還有對應的Principal接口的實現類,例如NTDomainPrincipal和UnixPrincipal。這些類在com.sun.security.auth包中。

    LoginModule接口中包含了五個方法:

1)   initialize () 當創建一LoginModule實例時會被構造函數調用

2)   login () 進行驗證,通常會按照登錄條件生成若干個Principal對象

3)   commit () 進行Principal對象檢驗,按照預定義Principal條件檢驗Login生成的Principal對象,所有需要的條件均符合後,把若干個生成的Principal對象付給Subject對象,JAAS架構負責回傳給LoginContext.

4)  abort () 當任何一個LoginModule對象驗證失敗時都會調用該方法。任何已經和Subject對象綁定的Principal對象都會被解除綁定。

5)  logout () 刪除與Subject對象關聯的Principal對象和憑證,消除Subject,Principal等認證對象。

驗證:CallbackHandler和Callback

  CallbackHandler和Callback對象可以使LoginModule對象從系統和用戶那裏收集必要的驗證信息,同時獨立於實際的收集信息時發生的交互過程。

   JAAS在javax.sevurity.auth.callback包中包含了七個Callback的實現類和兩個CallbackHandler的實現類:ChoiceCallback、ConfirmationCallback、LogcaleCallback、NameCallback、PasswordCallback、TextInputCallback、TextOutputCallback、DialogCallbackHandler和TextCallBackHandler。Callback接口只會在客戶端使用到。

在應用程序中使用JAAS驗證通常會涉及到以下幾個步驟:

  1. 創建一個LoginContext的實例。

  2. 爲了能夠獲得和處理驗證信息,將一個CallBackHandler對象作爲參數

傳送給LoginContext。

  3. 通過調用LoginContext的login()方法來進行驗證。

  4. 通過使用login()方法返回的Subject對象實現一些特殊的功能(假設

登錄成功)。

  下面是一個簡單的例子:

LoginContext lc = new LoginContext("MyExample");

try {

lc.login();

} catch (LoginException) {

// Authentication failed.

}

// Authentication successful, we can now continue.

// We can use the returned Subject if we like.

Subject sub = lc.getSubject();

Subject.doAs(sub, new MyPrivilegedAction());

  在運行這段代碼時,後臺進行了以下的工作。

  1. 當初始化時,LoginContext對象首先在JAAS配置文件中找到MyExample

項,然後更具該項的內容決定該加載哪個LoginModule對象。

  2. 在登錄時,LoginContext對象調用每個LoginModule對象的login()方法。

  3. 每個login()方法進行驗證操作或獲得一個CallbackHandle對象。

  4. CallbackHandle對象通過使用一個或多個CallBack方法同用戶進行交互,獲得用戶輸入。

  5. 向一個新的Subject對象中填入驗證信息。

 授權 Policy,AuthPermission,PrivateCredentialPermission

與權限管理、用戶認證的主要類包爲:

com.liferay.portal.security.auth.*

com.liferay.portal.service.permission

com.liferay.portal.struts.PortalRequestProcessor

Liferay關於JAAS的實現包都在com.liferay.portal.security.auth.*下,在$catalina_home/conf/jaas.conf中定義了Liferay實現的loginModule,在我使用的版本中,PortalLoginModule將首先通過對象池取出一個自定義Liferay用戶自定義的實現,即也可以在portal中再次自定義loginModule。顯然,如果沒有自定義的實現,將根據用戶所使用的服務器自動進行選擇默認實現。

Liferay自身所實現的user Principals和role Principals也僅僅是保存了用戶的userid,以其作爲自身標識,在登陸成功時賦予了所有用戶“users”角色:

PortalRole role = new PortalRole("users");

getSubject().getPrincipals().add(role);

Liferay的PortalRequestProcessor擴展了TilesRequestProcessor,實現了自定義的請求處理流程。在請求流程中複寫了processRoles(),在這個函數中進行了用戶權限的判斷,從而達到了對web資源的保護。

Permission是Liferay定義的用戶訪問的權限判斷,由processRoles調用進行訪問控制。

值得一提的是,Liferay本身也含有登錄模塊,這個登錄模塊所做的主要工作爲通過認證確定用戶的登錄信息正確,並通過用戶的登錄信息取得用戶userid存放在session中,爲JAAS的登陸模塊提供基礎(即通過登陸的正確用戶id與密碼)。登錄的用戶默認爲LDAP登陸,但是爲默認禁用,所以用戶認證Liferay都通過一個數據庫的認證實現在loginAction中進行的用戶判斷,取出了userid和password存放在session中。

整個過程如下:

如上圖所示,觸發JAAS的登錄模塊的是在登錄成功後轉向了/c/portal/protected,而此路徑爲tomcat的安全域,所以tomcat將調用用戶自定義的登錄模塊進行用戶認證,通過認證後通過對用戶角色的對比,來判斷用戶是否允許訪問。

 圖2 Liferay認證流程

用戶登錄

登錄成功,保存用戶信息

JAAS

LoginModule

副錄:幫助進行相關類查看

SecureFilter->進行訪問地址限制和是使用安全連接轉換。

PropsUtil—〉portal-ejb.jar裏的portal.property

MainServlet 擴展Struts的action Serverlet,進行映射。

liferay-portal-4.1.2的權限管理主要有2部分構成:

1.user的部門歸屬

2.對單個portlet的授權

超級用戶登陸系統後,將進入超級用戶的管理界面,管理界面總共有Guest、Private、CMS、Support 四層組成,即在Myplace中的4種視圖, 現對其進行介紹.

Guest視圖:主要管理普通用戶的所訪問的主頁內容,在此視圖中可以管理展現在主頁上的各個portlet,管理portlet中展現的內容以及portlet的展現形式以及方位。Portlet的內容管理放在稍後的視圖中詳細講解,portlet的方位以及顯示形式後可以通過頁面上直接的拖放進行設置。

默認情況下,我們所列的portlet就是匿名用戶所看到的門戶,在每個portlet的設置中,我們還看到了權限的設置,可以將這個portlet的配置,查看等權限(每個portlet的權限不相同,每個都有配置、查看權限,但是有個複雜的portlet如用戶管理的就有更多的如添加用戶、刪除用戶等權限)授予用戶,這裏權限的授予分6級,直接授予用戶,授予組織、授予地點、授予用戶羣、授予社羣和授予客人(用戶羣和社羣是自定義的)。Liferay的用戶機制爲公司—地點—組織—個人,所以授予某一高級的組,下掛的用戶將都會自動獲得權限。在我的應用中,我將WIKI加入了門戶首頁,同時將察看與刪除授予匿名用戶,所以,首頁就擁有了一個大家參與修改的區域WIKI了!

Private 視圖:這個是超級用戶的私人界面,這裏特別分析了幾個簡單portlet的權限管理的實現。

HelloWorldPortlet。位置Test->helloworld 這個portlet是最簡單的一個展示,而且僅僅只有view的功能,所以這個權限管理就是能否在用戶的視圖中顯示就行了,代碼中的權限代碼無,只是由layout調用HelloWorldPortlet。注:這裏是通過設置直接調用HelloWorldPortlet,沒有經過Struts框架,所以代碼直接繼承GenericPortlet,不能由路徑訪問。

Announcements。位置,這個portlet中訪問路徑由struts配置文件指定,這個portlet代碼ViewAction繼承PortletAction,PortletAction繼承的是Struts Action.在portlet.xml中,

<name>view-action</name>

<value>/wiki/view</value>

指定了這個portlet的view所調用的路徑,portal容器會根據struts的配置調用指定的Action。在進行action調用時,很顯然通過了Liferay擴展的PortalRequestProcessor(上一篇提到),也就進行了權限檢查。配置Announcements的路徑在liferay-portlet.xml中配置,爲/announcements/edit_configuration,同樣這也是一個struts路徑,她的權限管理也同view一樣,在PortalRequestProcessor中完成。

IFramePortlet。這個portlet也是一個簡單標籤的使用例子。在這個portlet中,與HelloWorldPortlet相同,也沒有Struts的路徑配置,而是直接在portlet.xml中定義了接受請求的Action,所繼承的StrutsPortlet由於不是由struts Action而是GenericPortlet擴展而來,所以在訪問的時候沒有通過PortalRequestProcessor,所以其內部明確調用了liferay的權限管理代碼:

PermissionChecker checker = PermissionThreadLocal.getPermissionChecker();

由上面我們所分析的幾個簡單的portlet來看,以後在進行portlet開發時有2種選擇,當邏輯比較少時,我們可以象IFramePortlet一樣,通過對StrutsPortlet的繼承完成。當業務邏輯比較複雜時(多個路徑),採用Struts進行路徑配置時,最好同Announcements一樣,通過繼承PortletAction來將自身開發的portlet納入liferay的權限管理框架中。

CMS視圖:明顯,這個層進行文檔管理,用過Guest視圖就可以知道門戶的所有的新聞文章都在journal中進行管理,對它的使用網上有很多很有用的文章,多用幾次也就熟悉了,強大的文本、圖像編輯功能可以就近使用而不再用自己編碼,肯定也是很愉快的了:)

Support視圖:這個視圖也是其他用戶(非管理員用戶)登陸後的定製頁面,由管理員進行定製,主要操作和上面一致

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章