0 策略文件续:
看如下策略文件myPolicy.txt
keystore "ijvmkeys"; grant signedby "friend" { permission java.io.FilePermission "d:/testPolicy.txt", "read,write"; }; grant signedby "stranger" { permission java.io.FilePermission "d:/testPolicy.txt", "read,write"; }; grant codeBase "file:D:/workspace/TestPolicy/bin/*" { permission java.io.FilePermission "d:/testPolicy.txt", "read,write"; };
第一行:keystore "ijvmkeys",这一行的意思,密钥对存放在当前目录一个叫ijvmkeys的文件里(记得笔记八做过的jar包签名实验吗)
第二行:grant signedby "friend",grant是授权的意思,这一行的意思是,给一个被“friend”的密钥对签名的文件授权
第三行:permission java.io.FilePermission "d:/testPolicy.txt", "read,write";这行的意思是对于d:/testPolicy.txt赋予读写的权限
倒数第三行:grant codeBase "file:D:/workspace/TestPolicy/bin/*" ,对D:/workspace/TestPolicy/bin/*下的所有文件赋予权限。
策略文件总结:
a) 策略文件可以给一系列被签名的代码库(“friend”,‘stranger“都是代码库)授权,
也可以给一个代码来源(一个具体的路径或者说url就是一个代码来源)授权。
b) 策略文件不仅可以存储在文件中(后缀名是什么不重要),还可以存放在数据库里。
疑问: 一个应用程序对应一个策略单例,一个策略单例对应一个策略文件,它到底怎么对应的???
1 保护域:
a) 类装载器将class文件load内存的时候会将它放置到一个保护域中,
b) 每一个装入虚拟机的类型都会属于且仅属于一个保护域,
c) 保护域定义了授予代码的执行权限,
d) 一个保护域对应策略文件中的一个或多个Grant字句
下面看类加载器加载类文件到指定保护域的流程:
类装载器知道它装载的所有类或接口的代码库和签名者---> 它利用这些信息来创建一个CodeSource对象
--->将这个CodeSource对象传递个当前Policy对象的getPermissions()方法
--->得到这个抽象类java.security.PermissionCollection的子类实例
--->实例化对象ProtectDomain ---> 传递给defineClass()方法
2 上文涉及的知识点详解:
2.1) codeSource:代码源
签名的版本,签名者,还有被签名的类名,以及这个类的hash摘要
classLoader通过读取class文件,jar包得知谁为这个类签过名(可以有多个签名者)
后封装成一个签名者数组赋给codeSource对象的signers成员,
通过这个类的来源(可能来自一个本地的url或者一个网络的ur)赋给codeSource的location成员,
这个类的公钥证书赋给codeSource的certs成员(常一个jar是能够被多个团体或者机构担保的,也就是我们说的认证)
源码如下:
public class CodeSource implements java.io.Serializable { private static final long serialVersionUID = 4977541819976013951L; /** * The code location. * * @serial */ private URL location;//本地代码库 /* * The code signers. */ private transient CodeSigner[] signers = null;//签名者 /* * The code signers. Certificate chains are concatenated. */ private transient java.security.cert.Certificate certs[] = null;//证书
2.2) Policy:策略, 就是用来读取策略文件的一个单例对象,通过传入的CodeSource对象
(由于codeSource对象里包含了签名者和代码来源),所以他通过读取grant段,
取出一个个的Perssiom然后返回一个PerssiomCollection,这个类有一个很重要的成员变量,
// Cache mapping ProtectionDomain to PermissionCollection private WeakHashMap pdMapping; private static void initPolicy (final Policy p) { ...... if (policyDomain.getCodeSource() != null) { ....... synchronized (p.pdMapping) { // cache of pd to permissions p.pdMapping.put(policyDomain, policyPerms); } } return; }
pdMapping就是把保护域对象当做key将权限集合当做value存在在了这个map里,
所以我们说一个保护域对应多个策略文件的grant子句的permission。
2.3) ProtectionDomain:保护域,他就是用来容纳class文件,还有perssiom,codeSource的一个对象,
代码如下:
public class ProtectionDomain { /* CodeSource */ private CodeSource codesource ;//代码源 /* ClassLoader the protection domain was consed from */ private ClassLoader classloader;//类装载器 /* Principals running-as within this protection domain */ private Principal[] principals; /* the rights this protection domain is granted */ private PermissionCollection permissions;//权限集合
2.4) Permission:权限,它的结构也很简单,权限名和动作,
java.io.FilePermission是一个权限名
而动作则是read和write,
2.5) 总计关系图如下:
3 总结:
类装载器装载类时--->调用安全管理器--->通过判定策略决定我们是否加载这个类/执行某操作
---> 生成ProtectionDomain保护域后,class字节码在内存中被放在了这个保护域中。