JAAS之Authentication
                                          
注:主要參考SUN的JAAS tutorial
Introduction(介紹)

    使用JAAS有2個目的:

    * 認證
    for authentication of users, to reliably and securely determine who is currently executing Java code, regardless of whether the code is running as an application, an applet, a bean, or a servlet; and

    * 授權
    for authorization of users to ensure they have the access control rights (permissions) required to do the actions performed.

JAAS是一個可插拔的認證模塊,不管使用何種認證技術,認證程序使用保持獨立,也就是說新增或修改認證技術應用程序不用修改。應用認證是通過實例化一個LoginContext來實現(xiàn)的,并通過一個配置文件來決定使用哪種認證技術或者那些LoginModule去執(zhí)行驗證操作,典型的LoginModules是通過驗證用戶名和密碼,也有可能是通過聲音或者指紋來進行驗證。

一旦用戶或者服務通過認證,接著JAAS授權組件基于JAVA2訪問控制模型(Java 2 access control model)保護敏感的資源。不同的是JDK1.3或更早的版本的訪問控制是基于code的位置和code簽名。JDK1.4是基于執(zhí)行代碼CodeSource和運行這個代碼的用戶或者服務(用Subject表示),驗證成功以后這個Subject被修改,設置相關的Principals 和credentials

JAAS Authentication(JAAS認證)

JAAS認證的操作通俗一點講,無非有三點:

1.       如何獲取驗證數(shù)據(jù)(這里的sample用用戶名和密碼)

2.       進行驗證

3.       保存驗證后的信息。

我們看一下client端調(diào)用的主要代碼如下:


LoginContext lc 
= new LoginContext("Sample"new MyCallbackHandler(username,password));

lc.login()

lc.getSubject();;


這三 行代碼里就包含了上面講的三點,其中:

[a]“sample”是指屬性文件中的信息,指出使用哪個登錄的LoginModule和其它一些參數(shù)。比如:

Sample {

 com.sample.SampleLoginModule required debug
=true;

};

[b] MyCallbackHandler就是如何獲取驗證數(shù)據(jù),其中傳遞了Username和password參數(shù)


public class MyCallbackHandler implements CallbackHandler {

       
private String username;
       
private String password;

       
public MyCallbackHandler(String username, String password) {
              
super();
              
this.username = username;
              
this. password = password;
       }

       
public void handle(Callback callbacks[]) throws IOException,
                     UnsupportedCallbackException {

              
for (int i = 0; i < callbacks.length; i++) {
                    
if (callbacks[i] instanceof NameCallback) {
                            ((NameCallback) callbacks[i]).setName(username);
                     } 
else if (callbacks[i] instanceof PasswordCallback) {
                            ((PasswordCallback) callbacks[i]).setPassword(password);
                     } 
else {
                            
throw new UnsupportedCallbackException(callbacks[i]);
                     }
              }
       }
}


[c] 驗證登錄調(diào)用的是com.sample.SampleLoginModule的login方法
public boolean login() throws LoginException {

              
//.

              Callback[] callbacks 
= new Callback[2];

              callbacks[
0= new NameCallback("user name: ");

              callbacks[
1= new PasswordCallback("password: "false);

              callbackHandler.handle(callbacks);

              String username 
= ((NameCallback) callbacks[0]).getName();

              String password 
= ((PasswordCallback) callbacks[1]).getPassword();

             
//利用回調(diào)獲取用戶名和密碼后,怎么進行驗證都可以.

             
//

[d] 最后保存信息調(diào)用的是commit方法,修改Subject
public boolean commit() throws LoginException {

              
if (succeeded == false) {
                     
return false;
              } 
else {

                     
// add a Principal (authenticated identity)
                     
// to the Subject
                     
// assume the user we authenticated is the SamplePrincipal

                     userPrincipal 
= new SamplePrincipal(username);
                    
if (!subject.getPrincipals().contains(userPrincipal))
                            subject.getPrincipals().add(userPrincipal);

             
//…………………………………………….


運行代碼時,需要加入?yún)?shù)-Djava.security.auth.login.config==sample_jaas.config sample.SampleAzn制定confg的位置


如果需要完整的代碼請參考sun網(wǎng)站的 jaas指南,詳情見文章后的參考資源。


如果這些代碼運行在Security Manager之下則涉及到JAAS授權,下篇文章再關注。




參考資源:

http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/tutorials/GeneralAcnOnly.html

附錄:

LoginModule描述由身份驗證技術提供程序實現(xiàn)的接口。LoginModule 插入到應用程序中以提供特定類型的身份驗證。

當應用程序寫入 LoginContext API 時,身份驗證技術提供程序將實現(xiàn) LoginModule接口。Configuration指定將與特定登錄應用程序一起使用的 LoginModule(s)。因此可以將不同的 LoginModule 插入到應用程序中,而無需修改應用程序本身。

LoginContext負責讀取 Configuration和實例化適當?shù)?nbsp;LoginModule。每個 LoginModule都是使用 Subject、CallbackHandler、共享的 LoginModule狀態(tài)和特定于 LoginModule 的選項來實例化的。 Subject表示當前正進行身份驗證的 Subject,如果身份驗證成功,則使用相關的 Credential 更新它。LoginModule 使用CallbackHandler與用戶進行通信。例如,CallbackHandler可以用于提示要求用戶名和密碼。注意, CallbackHandler可以為 null。確實需要一個 CallbackHandler來對 Subject進行身份驗證的 LoginModule 可以拋出 LoginException。LoginModule 可以有選擇地使用共享狀態(tài)來共享它們之間的信息或數(shù)據(jù)。

特定于 LoginModule 的選項表示由管理員或用戶在 Configuration中為此 LoginModule配置的選項。這些選項由 LoginModule自身定義,并在其中控制其行為。例如,LoginModule可以定義支持調(diào)試/測試功能的選項。這些選項是使用鍵-值語法定義的,例如 debug=true。LoginModule以 Map形式存儲這些選項,因此可以使用鍵來檢索這些值。注意,對 LoginModule選擇定義的選項個數(shù)是沒有限制的。

調(diào)用應用程序將身份驗證過程視為單個操作。但是,LoginModule中的身份驗證過程分兩個不同的階段進行。在第一個階段,LoginModule 的 login方法由 LoginContext 的 login方法調(diào)用。LoginModule的 login方法執(zhí)行實際的身份驗證(例如,提示并驗證密碼),并將身份驗證狀態(tài)作為私有狀態(tài)信息保存。一旦完成上述操作,LoginModule 的 login將返回 true(如果成功)或 false(如果應該忽略它),或拋出 LoginException來指示失敗。在失敗的情況下,LoginModule不必再嘗試進行身份驗證或者引入延遲。由應用程序完成這類任務。如果應用程序試圖重新嘗試身份驗證,將會再次調(diào)用 LoginModule 的 login方法。

在第二個階段,如果 LoginContext 的整個身份驗證成功(相關的 REQUIRED、REQUISITE、SUFFICIENT 和 OPTIONAL LoginModule 成功),則調(diào)用 LoginModule的 commit方法。LoginModule的 commit方法檢查其私有保存狀態(tài),以查看自己的身份驗證是否成功。如果整個 LoginContext身份驗證成功,并且 LoginModule 自己的身份驗證也獲得成功,則 commit方法會將相關的 Principal(已進行身份驗證的身份)和 Credential(身份驗證數(shù)據(jù),如加密密鑰)與位于 LoginModule中的 Subject聯(lián)系在一起。

如果 LoginContext 的整個身份驗證失敗(相關的 REQUIRED、REQUISITE、SUFFICIENT 和 OPTIONAL LoginModule 沒有成功),則調(diào)用每個 LoginModule的 abort方法。在這種情況下,LoginModule移除/銷毀原先保存的任何狀態(tài)。

注銷 Subject只涉及一個階段。LoginContext調(diào)用 LoginModule 的 logout方法。然后 LoginModule的 logout方法執(zhí)行注銷過程,例如從 Subject中移除 Principal 或 Credential,或者記錄會話信息。

LoginModule實現(xiàn)必須有一個無參數(shù)的構造方法。這允許加載 LoginModule的類對其進行實例化