13.3.4 访问控制上下文
在一个线程的执行过程中,该线程维护了与它所具有的访问控制权限相关的上下文信息。当前线程在新线程创建时的访问控制上下文信息会被保存下来,并作为被继承的上下文信息与新创建的线程关联起来。在调用方法时的访问控制权限检查会先按照正常的方式检查当前线程中方法的调用栈,再使用继承的上下文信息来进行检查。
访问控制上下文由java.security.AccessControlContext类表示。通过AccessController类的getContext方法可以得到当前线程所使用的访问控制上下文信息的一个快照,将其封装在AccessControlContext类的对象中。如果希望在其他线程中使用当前线程的访问控制上下文来进行权限检查,那么可以把该AccessControlContext类的对象传递给另外一个线程,并通过checkPermission方法来进行检查。AccessController类的doPrivileged方法在执行特权动作时,也可以指定一个AccessControlContext类的对象。在特权动作的执行过程中,不仅会考虑当前线程的访问控制上下文,还会考虑AccessControlContext类中封装的上下文信息。实际上,在AccessController类的checkPermission方法的实现中,也是先得到当前线程对应的AccessControlContext类的对象,再使用该对象的checkPermission方法来进行权限检查。
每个AccessControlContext类的对象是与一组ProtectionDomain类的对象关联在一起的。在AccessControlContext类的checkPermission方法的实现中,作为参数传递的Permission类的对象会被传递给所有关联的ProtectionDomain类的对象的implies方法。只有当所有的ProtectionDomain类的对象调用implies方法的返回值都为true时,需要检查的权限才是具备的。如果AccessControlContext类的对象所关联的ProtectionDomain类的对象需要被动态修改,那么可以在创建时传入一个java.security.DomainCombiner接口的实现对象。在获取AccessControlContext类的对象时,DomainCombiner接口的combine方法会被调用,用来对所关联的ProtectionDomain类的对象进行修改。
在有些情况下,需要以特定的主体身份标识来执行某些操作。如果在策略声明中为某个主体分配了相应的权限,那么只有以该主体作为身份标识时才能运行。使用Subject类的静态方法doAs和doAsPrivileged可以将调用参数中给出的Subject类的对象作为主体来执行特权动作。两个方法的区别在于doAsPrivileged方法不像doAs方法一样使用的是当前线程的访问控制上下文信息,而是使用作为参数传递的AccessControlContext类的对象。代码清单13-12给出了Subject类的doAsPrivileged方法的使用示例。在实际的程序中,Subject类中的身份标识信息应该通过登录过程来添加。
代码清单13-12 Subject类的doAsPrivileged方法的使用示例
public void doAs(){
Subject subject=new Subject();
UserPrincipal principal=new UserPrincipal("Alex");
subject.getPrincipals().add(principal);
subject.setReadOnly();
String userHome=Subject.doAsPrivileged(subject, new PrivilegedAction<String>(){
public String run(){
return System.getProperty("user.home");
}
},null);
}
与doAsPrivileged方法调用对应的策略文件如代码清单13-13所示。
代码清单13-13 与doAsPrivileged方法调用对应的策略文件
grant principal com.java7book.chapter13.auth.UserPrincipal"Alex"{
permission java.util.PropertyPermission"user.*","read";
};
grant{
permission javax.security.auth.AuthPermission"*";
};
在doAsPrivileged方法的实现中使用了DomainCombiner接口的实现类javax.security.auth.SubjectDomainCombiner,在获取AccessControlContext类的对象时,SubjectDomainCombiner类的对象会找到当前Subject类的对象中的身份标识所关联的ProtectionDomain类的对象,并把这些ProtectionDomain类的对象合并到AccessControlContext类的对象中。