我正在尝试了解Java安全性和AccessController.doPrivileged()用法的基础知识
我从一个示例程序开始
import java.security.AccessController;
import java.security.PrivilegedAction;
public class AccessSystemProperty {
public static void main(String[] args) {
System.out.println(System.getSecurityManager());
AccessController.doPrivileged(
new PrivilegedAction<Boolean>(){
public Boolean run(){
System.out.println(System.getProperty("java.home"));
return Boolean.TRUE;
}
}
);
}
}
如果我尝试使用默认的安全性管理来运行以上代码,则会收到AccessControlException
我的堆栈跟踪是
C:\>java -Djava.security.manager AccessSystemProperty
java.lang.SecurityManager@923e30
Exception in thread "main" java.security.AccessControlException: access denied (
java.util.PropertyPermission java.home read)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPropertyAccess(Unknown Source)
at java.lang.System.getProperty(Unknown Source)
at AccessSystemProperty$1.run(AccessSystemProperty.java:9)
at AccessSystemProperty$1.run(AccessSystemProperty.java:8)
at java.security.AccessController.doPrivileged(Native Method)
at AccessSystemProperty.main(AccessSystemProperty.java:6)
请帮助我清楚地了解
1)何时需要使用AccessController.doPrivileged()? (如果存在SecurityManager,我们将使用AccessController.doPrivileged-为何在以上示例中失败)
2)使用AccessController和PrivilegedAction得到的真正好处是什么?
3)是否需要自定义策略文件才能使以上示例正常工作?
谢谢,
保罗
最佳答案
您将使用AccessController.doPrivileged()赋予某些代码特权,这些特权在调用堆栈中较早的代码不具有,但是由于在策略中授予了该特权,所以特权代码具有。
例如,假设ClassA调用ClassB上的方法,并且ClassB需要读取java.home系统属性(以从您的示例中借用),并假定您已指定SecurityManager按照示例进行显示。
还假设从名为“classb.jar”的jar中加载ClassB(但为了使示例工作不从该jar中加载ClassA),安全策略文件中应包含以下内容:
grant codeBase "file:/home/somebody/classb.jar" {
permission java.util.PropertyPermission "java.home", "read";
};
现在,当ClassB运行并尝试执行System.getProperty()时,该类未包装在“java.home”上的AccessController.doPrivileged()中。安全管理器将检查堆栈,以查看堆栈上每个较高的类是否都具有“java.home”的PropertyPermission(无论是直接的还是隐含的)。否则,访问将失败。
但是,如果ClassB将System.getProperty()封装在AccessController.doPrivileged()中,则安全管理器仅关心策略文件赋予ClassB该特权,因此允许访问。
这是显示此内容的片段:
public void doStuff() {
try {
/*
* this will fail even if this class has permission via the policy file
* IF any caller does not have permission
*/
System.out.println(System.getProperty("java.home"));
} catch (Exception e1) {
System.out.println(e1.getMessage());
}
AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
try {
/*
* this will be allowed if this class has permission via the policy
* file even if no caller has permission
*/
System.out.println(System.getProperty("java.home"));
} catch (Exception e) {
System.out.println(e.getMessage());
}
return Boolean.TRUE;
}
});
因此,在您的示例中,您只需要指定一个策略文件,其中包含类似于我上面引用的Grant节的内容。