AccessController.checkPermission和AccessController.doPrivileged的示例
目录
先来看普通情况
checkPermission
public class TestManager{
public static void main(String[] args) throws FileNotFoundException {
FileInputStream in = new FileInputStream(new File("D:\\1.txt"));
System.out.println("有权限了!");
}
}
在启动参数中使用-Djava.security.manager 之后,开启了SecurityManager,FileInputStream实例化时获取SecurityManager并检验是否有权限操作
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
// 这里边封装了一个new FilePermission(file,“read”)
// 调用AccessController.checkPermission进行检验
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
fd = new FileDescriptor();
fd.incrementAndGetUseCount();
open(name);
}
报错如下
Exception in thread "main" java.security.AccessControlException: access denied (java.io.FilePermission D:\1.txt read)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:374)
at java.security.AccessController.checkPermission(AccessController.java:549)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.checkRead(SecurityManager.java:871)
at java.io.FileInputStream.<init>(FileInputStream.java:113)
at com.dw.acc.auto.tysl.TestManager.main(TestManager.java:11)
权限从哪来,从JAVA_HOME\jre\lib\security路径下java.policy设置,初始如下
grant codeBase "file:${{java.ext.dirs}}/*" {
permission java.security.AllPermission;
};
grant {
permission java.lang.RuntimePermission "stopThread";
permission java.net.SocketPermission "localhost:1024-", "listen";
permission java.util.PropertyPermission "java.version", "read";
permission java.util.PropertyPermission "java.vendor", "read";
permission java.util.PropertyPermission "java.vendor.url", "read";
permission java.util.PropertyPermission "java.class.version", "read";
permission java.util.PropertyPermission "os.name", "read";
permission java.util.PropertyPermission "os.version", "read";
permission java.util.PropertyPermission "os.arch", "read";
permission java.util.PropertyPermission "file.separator", "read";
permission java.util.PropertyPermission "path.separator", "read";
permission java.util.PropertyPermission "line.separator", "read";
permission java.util.PropertyPermission "java.specification.version", "read";
permission java.util.PropertyPermission "java.specification.vendor", "read";
permission java.util.PropertyPermission "java.specification.name", "read";
permission java.util.PropertyPermission "java.vm.specification.version", "read";
permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
permission java.util.PropertyPermission "java.vm.specification.name", "read";
permission java.util.PropertyPermission "java.vm.version", "read";
permission java.util.PropertyPermission "java.vm.vendor", "read";
permission java.util.PropertyPermission "java.vm.name", "read";
};
现报错D:\1.txt没有读权限,给他最后一添上
permission java.io.FilePermission "D:\\1.txt", "read";
之后就不报错了,要是一劳永逸,则改成
permission java.security.AllPermission;
所有权限支持
doPrivileged
情景:程序A调用了Bjar包来读取1.txt文件
在开启了安全管理器的情况下,只有当A和B都具有1.txt的操作权限时,才能过检测,安全检测是从调用栈顶到栈底依次检测,此情景下就是先检测Bjar包是否有操作这个文件的权限,再检测程序A是否有,两个都有,则过检测,否则报错
程序A代码如下:
public class MainTest {
public static void main(String[] args) throws Exception {
Test1 test1 = new Test1();
test1.test();
System.out.println("有权限");
}
}
Bjar包代码:写两个类是当时想测试同包下两个类保护域是怎么情况
public class Test1 {
public void test() throws FileNotFoundException {
Test2 d = new Test2();
d.test();
}
}
public class Test2 {
public void test() throws FileNotFoundException {
FileInputStream fin = new FileInputStream(new File("D:\\1.txt"));
}
}
程序A引入Bjar包,当然直接运行是不行的,会报错access denied ,在java.policy文件中配置如下才能正确运行
grant codeBase "file:/D:/Workspaces/XXX/target/classes/*" {
permission java.io.FilePermission "D:\\1.txt", "read";
};
grant codeBase "file:/D:/java/maven/repository/com/X/B.jar" {
permission java.io.FilePermission "D:\\1.txt", "read";
};
为什么要配置两个codeBase,因为程序A和jar包B,属于两个保护域(这玩意是啥我暂时说不清楚.......),这也可以Debug在检测权限那段代码发现,context数组是两个保护域,循环检测当前这个保护域是否有这个权限
public final class AccessControlContext {
private ProtectionDomain context[];
public void checkPermission(Permission perm) throws AccessControlException{
for (int i=0; i< context.length; i++) {
if (context[i] != null && !context[i].implies(perm)) {
throw new AccessControlException("access denied "+perm, perm);
}
}
}
}
再继续改造,将B包内的代码改改重新打包引入
public class Test2{
public void test() throws FileNotFoundException, PrivilegedActionException {
// FileInputStream fin = new FileInputStream(new File("D:\\1.txt"));
FileInputStream fin2 = AccessController.doPrivileged(new PrivilegedExceptionAction<FileInputStream>(){
@Override
public FileInputStream run() throws FileNotFoundException {
// TODO Auto-generated method stub
return new FileInputStream(new File("D:\\1.txt"));
}
});
}
}
AccessController.doPrivileged可以中断栈检查过程,B中调用这个操作,检查了B中是否有权限,如果B有就认为当前操作没问题,不再检查程序A中是否有权限,这种情况java.policy文件就可以只配置一个
grant codeBase "file:/D:/java/maven/repository/com/X/B.jar" {
permission java.io.FilePermission "D:\\1.txt", "read";
};
这样即使A中没有1.txt的操作权限,程序也能正常运行
另
如果想要查看程序运行时,都检测了哪些权限,可以自定义SecurityManager类,如下操作
首先自定义类,调用父类方法,加个打印
public class MySecurityManager extends SecurityManager {
public void checkPermission(Permission perm) {
System.out.println("perm=" + perm);
super.checkPermission(perm);
}
}
java.policy文件加上
permission java.security.AllPermission;
main方法启动时参数
-Djava.security.manager=com.xxxx.xxx.MySecurityManager
接下来就可以看到打印出的各种权限
perm=(java.util.PropertyPermission java.system.class.loader read)
perm=(java.lang.RuntimePermission modifyThreadGroup)
perm=(java.lang.RuntimePermission modifyThread)
perm=(java.lang.RuntimePermission modifyThreadGroup)
perm=(java.lang.RuntimePermission modifyThread)
perm=(java.lang.RuntimePermission modifyThreadGroup)
perm=(java.lang.RuntimePermission modifyThread)
perm=(java.lang.RuntimePermission modifyThreadGroup)
perm=(java.lang.RuntimePermission modifyThread)
perm=(java.lang.RuntimePermission modifyThreadGroup)
perm=(java.lang.RuntimePermission modifyThread)
perm=(java.util.PropertyPermission java.vm.specification.version read)
perm=(java.util.PropertyPermission java.vm.specification.name read)
perm=(java.util.PropertyPermission java.vm.specification.vendor read)
perm=(java.util.PropertyPermission java.vm.version read)
perm=(java.util.PropertyPermission java.vm.name read)
perm=(java.util.PropertyPermission java.vm.vendor read)
perm=(java.util.PropertyPermission java.vm.info read)
perm=(java.util.PropertyPermission java.library.path read)
perm=(java.util.PropertyPermission java.class.path read)
perm=(java.util.PropertyPermission java.endorsed.dirs read)
perm=(java.util.PropertyPermission java.ext.dirs read)
perm=(java.util.PropertyPermission java.version read)
perm=(java.util.PropertyPermission java.home read)
perm=(java.util.PropertyPermission sun.boot.class.path read)
perm=(java.util.PropertyPermission sun.boot.library.path read)
perm=(java.util.PropertyPermission java.home read)
perm=(java.util.PropertyPermission com.oracle.usagetracker.config.file read)
perm=(java.io.FilePermission D:\JDK6\jre\lib\management\usagetracker.properties read)
perm=(java.io.FilePermission D:\JDK6\jre\lib\management\usagetracker.properties read)
perm=(java.util.PropertyPermission sun.jnu.encoding read)
perm=(java.io.FilePermission D:\MyEclipse\WorkSpaces*****\tysl\TestManager.class read)
perm=(java.io.FilePermission D:\MyEclipse\WorkSpaces*****\tysl\TestManager.class read)
perm=(java.io.FilePermission D:\MyEclipse\WorkSpaces*****\tysl\TestManager.class read)
perm=(java.io.FilePermission D:\MyEclipse\WorkSpaces*****\tysl\TestManager.class read)
perm=(java.io.FilePermission D:\MyEclipse\WorkSpaces*****\tysl\TestManager.class read)
perm=(java.io.FilePermission D:\1.txt read)
perm=(java.io.FilePermission D:\1.txt read)
perm=(java.io.FilePermission D:\1.txt read)
有权限了!