JAAS简介
   JAAS(JavaTM Authentication and Authorization Service)可以分为两个主要部分:认证(authentication)部分和授权(authorization)部分。JAAS的认证部分提供了安全可靠的 能力,决定谁在运行代码的能力,而无需考虑当前的代码是Application,Applet,Bean,还是servlet。而JAAS的授权部分作为现有的JAVA 2的安全框架的补充,运行关键任务的代码受到了一定的限制,只有codesourse(如同Java 2) 和经过授权的人才有此权限。
一 JAAS认证
  《一》 主要概念   JAAS认证是通过插入(pluggable)方式实现的。这就允许了JAVA 程序可以保持了和底层认证技术无关的独立性。因此新的认证技术可以被插入到程序中,而不需要对程序自己做任何的修改。Subject 和Principal的概念。Subject 是一种 Java 对象,它表示单个实体,如个人。一个 Subject 可以有许多个相关身份,每个身份都由一个 Principal 对象表示。那么,比方说一个 Subject 表示要求访问电子邮件系统和财务系统的雇员。该 Subject 将有两个 Principal,一个与用于电子邮件访问的雇员的用户标识关联,另一个与用于财务系统访问的用户标识关联。Principal 不是持久性的,所以每次用户登录时都必须将它们添加到 Subject。Principal 作为成功认证过程的一部分被添加到 Subject。同样,如果认证失败,则从 Subject 中除去 Principal。不管认证成功与否,当应用程序执行注销时,将除去所有 Principal。
《二》主要接口
  JAAS认证需要用到如下几个类或者接口。
1. LoginModule 
该接口主要实现用户的验证。它包括如下几种认证方式。
(1) KerberosLoginModule
(2) NtLoginMoudle
该类主要包括如下几个方法
   A  Initialize()  
B  Login()
   C  Commit()
   D  Abort()
 E  Logout()
2.Callback回调处理程序。
   该接口主要实现与用户的交互。
    主要包括一下几种接口
    A  TextOutCallbackHandler
    B  NameCallback   获取用户名称
    C  PasswordCallback  获取用户密码
    D  ChoiceCallbackr
    E  ConfirmCallbackr
   主要方法是Handle();
2. Subject 对象
主要有如下几个方法
●subject.getPrincipals() 返回一组 Principal 对象。因为结果是 Set,所以适用操作 remove()、add() 和 contains()。
• subject.getPublicCredentials() 返回一组与 Subject 相关的公用可访问凭证。
• subject.getPrivateCredentials() 返回一组与 Subject 相关的专用可访问凭证。 
3.Principal 接口
 Principal 是一个 Java 接口。程序员编写的 PrincipalImpl 对象与 Serializable 接口、名称字符串、返回该字符串的 getName() 方法以及其它支持方法(如 hashCode()、toString() 和 equals())一起实现 Principal 接口。在登录过程期间,Principal 被添加到 Subject。
4 登陆配置
JAAS 使用 login.config 文件来指定每个登录模块的认证项。login.config 文件是在 Java 执行命令行上用特性 -Djava.security.auth.login.config==login.config 指定的。Java 有缺省登录配置文件,所以双等于号(==)替换系统登录配置文件。如果使用一个等于号,login.config 文件将被添加到(而不是替换)系统登录配置文件 
login.config 文件包含 LoginContext 构造器中引用的文本字符串和登录过程列表。几个参数用于指定一个给定的登录过程的成功或失败对总体认证过程的影响。有如下参数:
• required 表示登录模块必须成功。即使它不成功,还将调用其它登录模块。
• optional 表示登录模块可以失败,但如果另一个登录模块成功,总体登录仍可以成功。如果所有登录模块都是可选的,那么要使整个认证成功至少必须有一个模块是成功的。
• requisite 表示登录模块必须成功,而且如果它失败,将不调用其它登录模块。
• sufficient 表示如果登录模块成功,则总体登录将成功,同时假设没有其它必需或必不可少的登录模块失败。 §
login.config 文件示例:
    JAASExample {
      AlwaysLoginModule required;
      PasswordLoginModule optional;
};
5 LoginContext类
LoginContext 是一种用于设置登录过程的 Java 类,它进行实际的登录,如果登录成功,获取 Subject。它主要有如下几种方法。
•  LoginContext("JAASExample", newUsernamePasswoerdCallbackHandler()) 是构造器。它把 login.config 文件中使用的字符串作为其第一个参数,把执行实际任务的回调处理程序作为其第二个参数。(接下来,我们将讨论回调处理程序。)
• login(),它根据 login.config 文件中指定的规则实际尝试登录。
• getSubject(),如果登录总体成功,它返回经认证的 Subject。
• logout(),它向 LoginContext 注销 Subject
综上,为了实现JAAS在项目中的应用,我们可以修改LoginModule中的Login()方法以及Callback的Handle()方法,以适应项目的需要。将用户名和密码和数据库中的用户名和密码做比较来实现用户的认证。
二 JAAS 授权
将包含在访问控制环境中的权限特征与策略文件中的 Java 权限 grant 语句进行比较,以表明是否允许敏感操作。这是由名为 AccessController 的 Java 实用程序完成的,它的接口用于通过程序检查特权以及将当前的 Subject 与活动的访问控制环境相关联。
      我们可以使用doAs(Subject sub,PrivilegedAction action)将具有特殊权限才能访问的代码与Subject联系起来。也可以使用doAs(Subject sub,PrivilegedAction action,AccessController acc).我们可以将PrivilegedAction里面的类的Run方法修改,加入需要保护的代码,就可以实现相应的授权机制。这种方法属于程序性授权。比如如下程序。
Public 0class PayrollAction  implements PrivilegedAction {
     public Object run() {
       // Get the passed in subject from the DoAs
       AccessControlContext context = AccessController.getContext();
       Subject subject = Subject.getSubject(context );
       if (subject == null ) {
         throw new AccessControlException("Denied");
       }
       //
       // Iterate through the principal set looking for joeuser.  If
       // he is not found,
       Set principals = subject.getPrincipals();
       Iterator iterator = principals.iterator();
       while (iterator.hasNext()) {
         PrincipalImpl principal = (PrincipalImpl)iterator.next();
         if (principal.getName().equals( "joeuser" )) {
           System.out.println("joeuser has Payroll access\n");
           return new Integer(0);
         }
       }
       throw new AccessControlException("Denied");
}
还有一种声明性授权方式,使用方法如下:
import java.io.*;
import java.security.*;
//
// This class is a sensitive Personnel function that demonstrates 
// the use of declarative authorization using the user defined 
// permission PersonnelPermission, which throws an exception 
// if it not granted 
class PersonnelAction implements PrivilegedAction {
     public Object run() {
       AccessController.checkPermission(new PersonnelPermission("access"));
       System.out.println( "Subject has Personnel access\n");
       return new Integer(0);
     }
}
策略文件的格式比如:
grant {
     permission javax.security.auth.AuthPermission "createLoginContext";
     permission javax.security.auth.AuthPermission "doAs";
     permission javax.security.auth.AuthPermission "doAsPrivileged";
     permission javax.security.auth.AuthPermission "modifyPrincipals";
     permission javax.security.auth.AuthPermission "getSubject"; };grant      principal PrincipalImpl "Brad" {
     permission PersonnelPermission "access";
};

解决方案 »

  1.   

    Appendix
        15.4.5 Client/Server Authentication
    JAAS is designed to allow you to perform authentication in a client and pass the subject to a server. For that reason, the Subject class and all the principal classes used by JAAS are serializable. And your own Principal classes should also be serializable.
    Using JAAS in a client-server environment poses no special challenges, though it does require some forethought. One scheme is to perform authentication on the client: in the client code, create the LoginContext and invoke the login( ) method on it. Then call the getSubject( ) method on the context object and send the subject as a serialized object to the server. The server can then use the subject as a parameter to the doAs( ) method.
    The challenge with this method is that you must set up the login configuration file and JAAS environment on the client. If you write your own login module, you must distribute it as well. And you must be careful about environmental issues: if the Subject class is loaded on the server from the Java extensions directory (which is what we usually recommend), your own principal classes must also be loaded from that directory by the server, or object deserialization will fail. This is a property of how object serialization handles class loading; if
    you're not serializing the Subject object, it's not a requirement. The alternate method is to provide authentication on the server. In that case, you must determine how to obtain callback information from the user. If all you need are the user ID and password, the client can simply
    send that information to the server, which can store it in the necessary callback objects. If you have to handle other callbacks, you must devise your own scheme in order to pass the information between the client and server. Fortunately, you can usually rely only on a user ID and password. 
    15.4.6 Groups and Roles
    JAAS places a large burden on the administrator of a system. One technique that can lessen this burden is to rely on groups or roles. If your system has 1,000 users, you don't want to have 1,000 different entries in the policy file; if you can assemble those users into a few groups, setting up the policy file is much easier. If your application runs on a platform that already supports groups, this is trivial. On Solaris, you can use the SolarisNumericGroupPrincipal class to authenticate users based on the Solaris group to which they belong; you can perform a similar technique using the NTSidGroupPrincipal class on NT systems. If you're writing your own login module, the classes you write to implement the Principal interface can also implement the PrincipalComparator interface (com.sun.security.auth.PrincipalComparator). This allows those classes to implement their own group or role checking. 
    The PrincipalComparator interface contains a single method:
    public boolean implies(Subject s)
    Determine if the given subject is implied by this principal.
    Say that you write a principal class called DBPrincipal for database administrators. You could implement  the implies( ) method such that if the name is "DBA," it implies every other DBPrincipal: 
    package javasec.samples.ch15;
    import java.io.*;
    import java.util.*;
    import java.security.*;
    import javax.security.auth.*;
    import com.sun.security.auth.*;
    public class DBPrincipal implements Principal,
    PrincipalComparator, Serializable {
    private String name;
    public DBPrincipal(String name) {
    this.name = name;
    }
    public String getName( ) {
    return name;
    }
    public boolean implies(Subject s) {
    Set set = s.getPrincipals(DBPrincipal.class);// getPrincipals(class) 方法的含有: Return a Set of Principals //associated  with this Subject that are instances or subclasses of the specified //Class.Iterator i = set.iterator( );
    if (i.hasNext( ) && name.equals("DBA")) {
    // If the subject has any DBPrincipal,
    // they are implied by us (if we're DBA)
    return true;
    }
    // Otherwise, we have to look for an exact match
    try {
    while (true) {
    DBPrincipal p = (DBPrincipal) i.next( );
    if (p.equals(this))
    return true;
    }
    } catch (NoSuchElementException nsee) {
    return false;
    }
    }
    public boolean equals(Object o) {
    if (!(o instanceof DBPrincipal))
    return false;
    return ((DBPrincipal) o).name.equals(name);
    }
    }
      

  2.   

    最好有个例子,我现在手头的项目是用JSP+STRUTS+EJB来做,后来看到STRUTS支持JAAS,又叫我们用上这技术,项目又急,所以只好求救各位,有例子的最好!!!!!!