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来实现的,并通过一个配置文件来决定使用哪种认证技术或者那些LoginModule去执行验证操作,典型的LoginModules是通过验证用户名和密码,也有可能是通过声音或者指纹来进行验证。

一旦用户或者服务通过认证,接着JAAS授权组件基于JAVA2访问控制模型(Java 2 access control model)保护敏感的资源。不同的是JDK1.3或更早的版本的访问控制是基于code的位置和code签名。JDK1.4是基于执行代码CodeSource和运行这个代码的用户或者服务(用Subject表示),验证成功以后这个Subject被修改,设置相关的Principals 和credentials

JAAS Authentication(JAAS认证)

JAAS认证的操作通俗一点讲,无非有三点:

1.       如何获取验证数据(这里的sample用用户名和密码)

2.       进行验证

3.       保存验证后的信息。

我们看一下client端调用的主要代码如下:


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

lc.login()

lc.getSubject();;


这三 行代码里就包含了上面讲的三点,其中:

[a]“sample”是指属性文件中的信息,指出使用哪个登录的LoginModule和其它一些参数。比如:

Sample {

 com.sample.SampleLoginModule required debug
=true;

};

[b] MyCallbackHandler就是如何获取验证数据,其中传递了Username和password参数


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] 验证登录调用的是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();

             
//利用回调获取用户名和密码后,怎么进行验证都可以.

             
//

[d] 最后保存信息调用的是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);

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


运行代码时,需要加入参数-Djava.security.auth.login.config==sample_jaas.config sample.SampleAzn制定confg的位置


如果需要完整的代码请参考sun网站的 jaas指南,详情见文章后的参考资源。


如果这些代码运行在Security Manager之下则涉及到JAAS授权,下篇文章再关注。




参考资源:

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

附录:

LoginModule描述由身份验证技术提供程序实现的接口。LoginModule 插入到应用程序中以提供特定类型的身份验证。

当应用程序写入 LoginContext API 时,身份验证技术提供程序将实现 LoginModule接口。Configuration指定将与特定登录应用程序一起使用的 LoginModule(s)。因此可以将不同的 LoginModule 插入到应用程序中,而无需修改应用程序本身。

LoginContext负责读取 Configuration和实例化适当的 LoginModule。每个 LoginModule都是使用 Subject、CallbackHandler、共享的 LoginModule状态和特定于 LoginModule 的选项来实例化的。 Subject表示当前正进行身份验证的 Subject,如果身份验证成功,则使用相关的 Credential 更新它。LoginModule 使用CallbackHandler与用户进行通信。例如,CallbackHandler可以用于提示要求用户名和密码。注意, CallbackHandler可以为 null。确实需要一个 CallbackHandler来对 Subject进行身份验证的 LoginModule 可以抛出 LoginException。LoginModule 可以有选择地使用共享状态来共享它们之间的信息或数据。

特定于 LoginModule 的选项表示由管理员或用户在 Configuration中为此 LoginModule配置的选项。这些选项由 LoginModule自身定义,并在其中控制其行为。例如,LoginModule可以定义支持调试/测试功能的选项。这些选项是使用键-值语法定义的,例如 debug=true。LoginModule以 Map形式存储这些选项,因此可以使用键来检索这些值。注意,对 LoginModule选择定义的选项个数是没有限制的。

调用应用程序将身份验证过程视为单个操作。但是,LoginModule中的身份验证过程分两个不同的阶段进行。在第一个阶段,LoginModule 的 login方法由 LoginContext 的 login方法调用。LoginModule的 login方法执行实际的身份验证(例如,提示并验证密码),并将身份验证状态作为私有状态信息保存。一旦完成上述操作,LoginModule 的 login将返回 true(如果成功)或 false(如果应该忽略它),或抛出 LoginException来指示失败。在失败的情况下,LoginModule不必再尝试进行身份验证或者引入延迟。由应用程序完成这类任务。如果应用程序试图重新尝试身份验证,将会再次调用 LoginModule 的 login方法。

在第二个阶段,如果 LoginContext 的整个身份验证成功(相关的 REQUIRED、REQUISITE、SUFFICIENT 和 OPTIONAL LoginModule 成功),则调用 LoginModule的 commit方法。LoginModule的 commit方法检查其私有保存状态,以查看自己的身份验证是否成功。如果整个 LoginContext身份验证成功,并且 LoginModule 自己的身份验证也获得成功,则 commit方法会将相关的 Principal(已进行身份验证的身份)和 Credential(身份验证数据,如加密密钥)与位于 LoginModule中的 Subject联系在一起。

如果 LoginContext 的整个身份验证失败(相关的 REQUIRED、REQUISITE、SUFFICIENT 和 OPTIONAL LoginModule 没有成功),则调用每个 LoginModule的 abort方法。在这种情况下,LoginModule移除/销毁原先保存的任何状态。

注销 Subject只涉及一个阶段。LoginContext调用 LoginModule 的 logout方法。然后 LoginModule的 logout方法执行注销过程,例如从 Subject中移除 Principal 或 Credential,或者记录会话信息。

LoginModule实现必须有一个无参数的构造方法。这允许加载 LoginModule的类对其进行实例化