前面一节我们做了一个简单的实验来说明什么是策略文件在文章的最后也顺带的讲了一下什么是策略还有策略的作用 为了引出另外一个很重要的概念ProtectionDomain(保护域)所以我们还是要先来回顾一下什么是策略 首先什么是策略今天的东西纯粹是比较概念的当然如果你读过笔记九今天的东西就真的是soso 策略与策略文件 java对应用程序的访问控制策略是由抽象类javasecurityPolicy的一个子类的单例所表示任何时候每个应用程序实际上只有一个Policy对象Policy对象对应着策略文件类装载器利用这个Policy对象来帮助他们决定在把一段代码导入虚拟机时应该给予什么权限 上面那段话告诉我们一个应用程序对应一个策略对象一个策略对象对应一个策略文件 那么策略文件除了对我们笔记九中一个文件夹下的所有文件起限制作用外还能对什么主体起作用呢?先来看看下面的策略文件myPolicytxt keystore ijvmkeys grant signedby friend { permission javaioFilePermission d:/testPolicytxt readwrite; }; grant signedby stranger { permission javaioFilePermission d:/testPolicytxt readwrite; }; grant codeBase file:D:/workspace/TestPolicy/bin/* { permission javaioFilePermission d:/testPolicytxt readwrite; }; 简单的解读一下 第一行keystore ijvmkeys这一行的意思密钥对存放在当前目录一个叫ijvmkeys的文件里(记得笔记八做过的jar包签名实验吗) 第二行grant signedby friendgrant是授权的意思这一行的意思是给一个被friend的密钥对签名的文件授权 第三行permission javaioFilePermission d:/testPolicytxt readwrite;这行的意思是对于d:/testPolicytxt赋予读写的权限 倒数第三行grant codeBase file:D:/workspace/TestPolicy/bin/* 这一句我们笔记九的时候见过就是对D:/workspace/TestPolicy/bin/*下的所有文件赋予权限 重点一到这里我们应该可以知道策略文件可以给一系列被签名的代码库(friendstranger都是代码库)授权也可以给一个代码来源(一个具体的路径或者说url就是一个代码来源)授权 重点二策略文件不仅可以存储在文件中(后缀名是什么不重要)还可以存放在数据库里 到了这里我们对策略有一个比较完整的概念了但是你有没有这么一个疑问前面我们总说一个应用程序对应一个策略单例一个策略单例对应一个策略文件它到底怎么对应的?下面我们就来探究一下 在探究之前我们先引入一个新的概念叫保护域(ProtectionDomain)在笔记三的时候我们提到过类装载器将class文件load内存的时候会将它放置到一个保护域中是滴今天我就来说说什么是保护域 什么是保护域 当类装载器将类型装入Java虚拟机时它们将为每个类型指派一个保护域保护域定义了授予一段特定代码的所有权限(一个保护域对应策略文件中的一个或多个Grant子句)装载入Java虚拟机的每一个类型都属于一个且仅属于一个保护域 类装载器知道它装载的所有类或接口的代码库和签名者它利用这些信息来创建一个CodeSource对象它将这个CodeSource对象传递个当前Policy对象的getPermissions()方法得到这个抽象类javasecurityPermissionCollection的子类实例这个PermissinCollection包含了到所有Permission对象的引用(这些Permission对象由当前策略授予指定代码来源)利用它创建的CodeSource和它沖Policy对象得到的PermissionCollection它可以实例化一个新的ProtectDomain对象它通过将合适的ProtectionDomain对象传递给defineClass()方法来将这段代码放到一个保护域中 如果你对上面这段话理解不了看下面这个图 好了看完上面的这整个过程之后你是否已经理解什么是保护域了 下面我们在整理一下内容概念有点多一个一个的来 codeSource:代码源这个是类装载器生成的javasecurityCodeSource的一个对象classLoader通过读取class文件jar包得知谁为这个类签过名(可以有过个签名者关于签名请查看笔记七和八)而封装成一个签名者数组赋给codeSource对象的signers成员通过这个类的来源(可能来自一个本地的url或者一个网络的ur对应了grant笔记九里myPollicy里的friend或者file::…l)赋给codeSource的location成员还有这个类的公钥证书赋给codeSource的certs成员(通常一个jar是能够被多个团体或者机构担保的也就是我们说的认证在java的默认安全管理器还有访问控制体系结构都只能对证书起作用而不能对赤裸的公钥起作用而实际上我们用keytool生成密钥对时同时会生成一个自签名证书所以keytool生成的密钥对并不是赤裸的)如果你有疑问我们看一下jdk里的代码 public class CodeSource implements javaioSerializable { private static final long serialVersionUID = L; /** * The code location * * @serial */ private URL location;//本地代码库 /* * The code signers */ private transient CodeSigner[] signers = null;//签名者 /* * The code signers Certificate chains are concatenated */ private transient javasecuritycertCertificate certs[] = null;//证书 Policy:策略就是用来读取策略文件的一个单例对象通过传入的CodeSource对象(由于codeSource对象里包含了签名者和代码来源)所以他通过读取grant段取出一个个的Perssiom然后返回一个PerssiomCollection这个类里有一个很重要的成员变量 // Cache mapping ProtectionDomain to PermissionCollection private WeakHashMap pdMapping; 这个成员为什么重要我们来看一个方法 private static void initPolicy (final Policy p) { …… if (policyDomaingetCodeSource() != null) { …… synchronized (ppdMapping) { // cache of pd to permissions ppdMappingput(policyDomain policyPerms) } } return; } 我们主要看关键代码这个pdMapping就是把保护域对象当做key将权限集合当做value存在在了这个map里所以我们说一个保护域对应多个策略文件的grant子句的permission ProtectionDomain:保护域前面我们已经介绍过了他就是用来容纳class文件还有perssiomcodeSource的一个对象如果你对此还有什么疑问我们也看看它的代码来验证一下我们的结论 public class ProtectionDomain { /* CodeSource */ private CodeSource codesource ;//代码源 /* ClassLoader the protection domain was consed from */ private ClassLoader classloader;//类装载器 /* Principals runningas within this protection domain */ private Principal[] principals; /* the rights this protection domain is granted */ private PermissionCollection permissions;//权限集合 Permission:权限这个对应了我们笔记九里的grant子句里的一个permission它的结构也很简单权限名和动作就好像我们笔记九里的javaioFilePermission是一个权限名 而动作则是read和write在Permission中它对应一个字符串 现在我们用一张图来把上面几个概念串联起来 到这里我们已经有一条比较完整的思路了从笔记四到这一节的笔记十我们所要说的都只有一件事情类装载器在装载类的时候(或者执行类)会调用安全管理器安全管理器则通过判断策略来判断我们是不是允许加载这个类或者执行某些操作笔记某个文件的读写啊之类的(这个在笔记九的时候我们已经做过实验了) |