六,存取控制器
来源:互联网 发布:家庭网络布线交换机 编辑:程序博客网 时间:2024/06/05 17:26
安全管理器大部分功能都是在存取控制器基础上实现的,可以说存取控制器是可以取代安全管理器的。
一般来说安全管理器是调用存取控制器的功能!
前面章节介绍的沙箱就是说的存取控制器,存取控制器就是沙箱的实现。回顾一下沙箱的基本要素,这些都是建立存取控制的基础
基本要素:
1,代码源
2,权限
3,策略:管理员可以设置策略文件,策略文件上面描述了所有的权限;在安全管理器中,策略对象表示为对所有权限的封装(内存)
4,保护域:利于权限的检索,指对某代码源相应权限的封装
我们先详细解读每一个要素的实现,然后再解释存取控制器是如何工作的
一,CodeSource类(java.security.CodeSource) —————— 代码源
主要方法:
http://www.yq1012.com/api/java/security/CodeSource.html
二,权限类, Permission类
http://www.yq1012.com/api/java/security/Permission.html
1,权限的三个特性:类型、名、操作
注意:权限是类型的一个实例
如:在策略文件中定义一个权限对象
permission java.util.PropertyPermission "java.version", "read";
上面描述的权限在内存中的表示为:permission p = new java.util.PropertyPermission("java.version", "read");
可以看出对象是java.util.PropertyPermission类型的一个实例,构造时带名和操作参数。
对于我们这些普通java开发者,很少定义权限类,但是我们可以自定义权限类,只不过在实现”名、操作“的通配匹配上算法有点复杂,
另外,BasicPermission类提供了层次式通配匹配操作,我们可以直接继承或依赖他,也可以只继承Permission类来自行完成需要的匹配算法。
以下是参考书籍上的一个例子,
----此例子的名只是一个单值,并不是层次的,所以不需要复杂的匹配,操作只有2个,view和update,操作配置算法用或操作就完成,很简单
----如果名是层次的,要写路径覆盖算法,代码太多,这里只是简单的说明我们如何编写自己的权限类,
----注意equals(Object o),implies(Permission p) ,getActions() 核心方法的实现细节,他们都是抽象的,要自己实现的匹配逻辑
import java.security.*;import java.util.*;public class XYZPayrollPermission extends Permission { protected int mask; static private int VIEW = 0x01; static private int UPDATE = 0x02; public XYZPayrollPermission(String name) { // Our permission must always have an action, so we // choose a default one here. this(name, "view"); } public XYZPayrollPermission(String name, String action) { // Our superclass, however, does not support actions // so we don't provide one to that. super(name); parse(action); } private void parse(String action) { // Look in the action string for the words view and // update, separated by white space or by a comma StringTokenizer st = new StringTokenizer(action, ",\t "); mask = 0; while (st.hasMoreTokens()) { String tok = st.nextToken(); if (tok.equals("view")) mask |= VIEW; else if (tok.equals("update")) mask |= UPDATE; else throw new IllegalArgumentException( "Unknown action " + tok); } } public boolean implies(Permission permission) { if (!(permission instanceof XYZPayrollPermission)) return false; XYZPayrollPermission p = (XYZPayrollPermission) permission; String name = getName(); // The name must be either the wildcard *, which signifies // all possible names, or the name must match our name if (!name.equals("*") && !name.equals(p.getName())) return false; // Similarly, the requested actions must all match actions // that we've been constructed with. if ((mask & p.mask) != p.mask) return false; // Only if both the action and name match do we return true. return true; } public boolean equals(Object o) { if (!(o instanceof XYZPayrollPermission)) return false; // For equality, we check the name and action mask. // We must provide a method definition like this, since // the security system expects us to do a deep check for // equality rather than relying on object reference // equality. XYZPayrollPermission p = (XYZPayrollPermission) o; return ((p.getName().equals(getName())) && (p.mask == mask)); } public int hashCode() { // We must always provide a hash code for permissions, // because the hashes must match if the permissions compare // as equals. The default implementation of this method // wouldn't provide that. return getName().hashCode() ^ mask; } public String getActions() { // This method must return the same string, no matter how // the action list was passed to the constructor. if (mask == 0) return ""; else if (mask == VIEW) return "view"; else if (mask == UPDATE) return "update"; else if (mask == (VIEW | UPDATE)) return "view, update"; else throw new IllegalArgumentException("Unknown mask"); } public PermissionCollection newPermissionsCollection() { // More about this in a later example. return new XYZPayrollPermissionCollection(); } public static void main(String[] args) { XYZPayrollPermission p1 = new XYZPayrollPermission("sdo", "view"); XYZPayrollPermission p2 = new XYZPayrollPermission(args[0], args[1]); System.out.println("P1 is " + p1); System.out.println("P2 is " + p2); System.out.println("P1 -> P2 is " + p1.implies(p2)); System.out.println("P2 -> P1 is " + p2.implies(p1)); }}
2,权限集(抽线类):PermissionCollection类,某一个权限类的所有实例的集合,用途:1-存储权限;2-检查是否包含指定权限
3,权限集集合:Permissions类,他继承权限集PermissionCollection,和权限集表现一样的接口,因此作用一样,只不过他更强,他可以存储多个不同类型的权限集,也可用于不同类型权限的检索
以下是参考书籍上的一个例子,
import java.util.*;import java.security.*;import java.util.*;public class XYZPayrollPermissionCollection extends PermissionCollection { private Hashtable permissions; // We keep track of whether the * name has been added to make // the implies method simpler. private boolean addedAdmin; private int adminMask; XYZPayrollPermissionCollection() { permissions = new Hashtable(); addedAdmin = false; } public void add(Permission p) { // Required test if (isReadOnly()) throw new IllegalArgumentException("Read only collection"); // This is a homogenous collection, as are all // PermissionCollections that you'll implement. if (!(p instanceof XYZPayrollPermission)) throw new IllegalArgumentException("Wrong permission type"); XYZPayrollPermission xyz = (XYZPayrollPermission) p; String name = xyz.getName(); XYZPayrollPermission other = (XYZPayrollPermission) permissions.get(name); if (other != null) xyz = merge(xyz, other); // An administrative permission. The administrative permission // may have only view or only update or both, and multiple // admin permissions may be added, so the masks are OR-ed // together. if (name.equals("*")) { addedAdmin = true; adminMask = xyz.mask | adminMask; } permissions.put(name, xyz); } public Enumeration elements() { return permissions.elements(); } public boolean implies(Permission p) { if (!(p instanceof XYZPayrollPermission)) return false; XYZPayrollPermission xyz = (XYZPayrollPermission) p; // If the admin name is present, then all names are implied; // we need check only the permissions. if (addedAdmin && (adminMask & xyz.mask) == xyz.mask) return true; // Otherwise, we can just see if the given individual is // in our table and if so, see if the permissions match. Permission inTable = (Permission) permissions.get(xyz.getName()); if (inTable == null) return false; return inTable.implies(xyz); } // This is called when the same name is added twice to the // permissions; we merge the action lists and only store the // name once. private XYZPayrollPermission merge(XYZPayrollPermission a, XYZPayrollPermission b) { String aAction = a.getActions(); if (aAction.equals("")) return b; String bAction = b.getActions(); if (bAction.equals("")) return a; return new XYZPayrollPermission(a.getName(), aAction + "," + bAction); }}
三,Policy类 策略
权限集要和代码源相关联,之后我们才能判断出代码具有什么样的权限。策略类定义了这种关联。
如果要自己写策略,
----就需要解读策略文件,或者权限存于数据库,你需要自己的一套解读方式
----需要为代码源关联权限集,注意权限集的创建并不是由策略完成的,策略只是保存数据,创建权限的工作由运行时的类加载器搞定
----策略类需要读文件或网络的权限,往往是特权,特权在本文后面介绍
其实我在读完存取控制后,就开始担心java安全策略的效率,但等到读完类加载器后,这些顾虑都没有了,策略对象里面代码源的权限集并不是启动java的时候就生成的,而是由类加载器实时完成的。
所以我们并不用担心JAVA虚拟机安全的处理速度,更不用担心检索速度(内存速度)
例子:
例子展示了策略对象的主要功能
----存储权限 (具体的权限由类加载器生成,然后抛给策略对象的)
----检索代码基的权限集
import java.security.*;import java.util.*;public class MyPolicy extends Policy { // This inner class defines a simple set of permissions: // either everything is allowed (the implies() method always // returns true, and the collection contains an AllPermission // object) or everything is prohibited (the implies() // method always returns false and the collection is empty). static class SimplePermissions extends PermissionCollection { boolean allow; Permissions perms; SimplePermissions(boolean b) { allow = b; perms = new Permissions(); if (allow) perms.add(new AllPermission()); } public void add(Permission p) { if (isReadOnly()) throw new SecurityException( "Can't add to this collection"); perms.add(p); } public Enumeration elements() { return perms.elements(); } public boolean implies(Permission p) { return allow; } } // We never change the policy public void refresh() {} //If the code was loaded from a file, return a collection // that implies all permissions. Otherwise, return an // empty collection (one that implies no permissions). public PermissionCollection getPermissions(CodeSource cs) { if (cs.getLocation().getProtocol().equals("file")) return new SimplePermissions(true); return new SimplePermissions(false); }}
在虚拟机中,任何时候只有一个策略对象,
我们可以替换系统的策略类,通过程序化或者管理手段配置
程序化: setPolicy(Policy p)
管理手段:
---java.security中 plicy.provider=sun.security.provider.PolicyFile 替换为自己的类
---把自己的类放如rt.jar中,或者在运行虚拟机时正确适合参数以指定引导路径 java -Xbootclasspath:/files/policyfile ...
四,保护域 ProtectionDomain
前面谈过Permissions对象——权限集集和,他和某一个代码基关联起来就是保护域
也就是说,他存储了某个代码基的所有权限集集和
具体核心方法请参考API文档
保护域对开发人员是透明的,我们不需要了解他的API细节,
但我们要知道,每一个java类都属于且仅属于一个保护域,定义类时,保护域可以来自默认的安全模型(策略文件),也可由类加载器拓展(或替换)。
五、存取控制器 AccessController
前面介绍了存取控制器的要素,存取控制器没有实例,构造函数私有,有一组静态方法用于确定是否得到权限以实现某个操作
例子演示了他简单的用法
<span style="font-size:12px;">import java.applet.*;import java.net.*;import java.security.*;public class AccessTest extends Applet { public void init() { SocketPermission sp = new SocketPermission( getParameter("host") + ":6000", "connect"); try { AccessController.checkPermission(sp); System.out.println("Ok to open socket"); } catch (AccessControlException ace) { System.out.println(ace); } }}</span>
1,存取控制是如何工作的——如何检索权限的
----存取控制器方法调用后,存取控制开始工作
----存取控制器检索堆栈中最后压入栈的类,存取控制类除外,检索类代码基是否有相应权限,以上代码是检索是否有套接字权限,host:6000
----有权限,就检测堆栈前一个类,直到堆栈完毕。
----没有权限,就抛出运行时异常,线程完毕。
来自于不同加载器和不同签名jar包的类,由加载器设置权限集合,所以类加载器为了安全考虑,必须首先检索父加载器是否加载了类,
这里不能画图 唉!
2,特权接口,PrivilegedAction 和 PrivilegedExceptionAction 接口
实现特权接口的类,就是特权类,只有一个方法就是run();
如果我们把一段程序封装在特权类中,我们就能让存取控制器网开一面,阻止存取控制递归检索堆栈中的权限
话题:A类有套接字locahost:6000权限,B类没有,如果B调用A,那么网络访问就会失败,但这种情况下,我们希望A能顺利访问网络,怎么办呢?
解答:特权类
我们改造类A,让A访问网络的代码封装在特权类中,这样不管调用A的类是否具备套接字权限,A的对象都能顺利访问网络
<span style="font-size:12px;">import java.net.*;import java.io.*;import java.security.*;public class A { public A() { try { // This class is used by the doPrivilged() method to // open a socket class doSocket implements PrivilegedExceptionAction { public Object run() throws UnknownHostException, IOException { return new Socket("localhost", 6000); } }; doSocket ds = new doSocket(); Socket s = (Socket) AccessController.doPrivileged(ds); } catch (PrivilegedActionException pae) { Exception e = pae.getException(); if (e instanceof UnknownHostException) { // process host exception } else if (e instanceof IOException) { // process IOException } else { // e must be a runtime exception throw (RuntimeException) e; } } }}</span>
我们看看例子堆栈的情况
-----new Socket("localhost",6000) 会在内部调用存取控制器, 存取控制器会递归堆栈检索指定权限 :new java.net.SocketPermission("localhost",6000)
-----存取控制先检索类核心API Socket 是否有套接字权限
------有,继续检索doSocket类套接字权限
-----doSocket为特权类,他会设置断点,阻止存取控制继续检索,从而返回,
-----存取控制器返回“真”,套接字访问顺利完成
如果A类的对象,被任何其他类型的对象调用,A都能有特权访问套接字了
例子的分析,大家可能有疑惑,我们更进一步分析下
-----程序执行首先要进堆栈,然后出栈,
-----语句AccessController.doPrivileged(ds),会让ds.run靠后进栈,之后让new Socket("localhost",6000)最后进栈,也就是说存取控制器回调run,
-----new Socket("localhost",6000)会进一步让AccessController.checkPermission()方法进栈,checkPermission()才是检索类权限的真正指令流
-----等checkPermission()执行完毕后,知道有权限才让new Socket("localhost",6000)正常返回,否则,如果没有权限,抛出运行时异常,堆栈结束了
-----AccessController.doPrivilleged()是很早进入栈的,但他进栈时,在栈中设置了一个断点,断点会阻止checkPermission()方法中检索代码的执行,
-----因此checkPermission()执行中途,检测到堆栈断点,返回,不会去检索栈中其他类的权限了,从而达到了特权的目的。
没法画图,唉
- 六,存取控制器
- 连载六-------视图控制器
- tp控制器------(六)
- 六.控制器调用VIEW视图
- ios学习笔记(六)视图控制器
- XAF应用开发教程(六)控制器
- IOS学习(六)导航视图控制器
- 封装框架(六)加载控制器
- 六、嵌入式学习笔记--存储控制器
- 离线部署额外域控制器,Active Directory系列之六
- AD 实战之六:离线部署额外域控制器
- Spring MVC学习(六)-------注解式控制器详解1
- Spring MVC学习(六)-------注解式控制器详解2
- Spring MVC学习(六)-------注解式控制器详解3
- Spring MVC学习(六)-------注解式控制器详解4
- Spring MVC学习(六)-------注解式控制器详解5
- 离线部署额外域控制器,Active Directory系列之六
- springMVC学习笔记六(注解方式实现控制器)
- WinHTTP如何处理Cookie
- android_BroadcastReceiver 广播机制
- ImageButton focusable="false"不起作用
- C# 调用C++ dll问题总结一 ——无法找到dll
- Oracle_PL-SQL_JavaSource_13
- 六,存取控制器
- WinHTTP错误信息处理
- C++primer 4.3 C风格字符串--字符数组(strlen、strcpy、strcat)上
- 【第二章】 IoC 之 2.2 IoC 容器基本原理 ——跟我学Spring3
- iOS开发利用zbar实现二维码扫描(支持64位) 及二维码生成
- Netty解决半包(TCP粘包/拆包导致)读写问题
- C#配置文件概述
- Android XML视图 平分效果
- 深入理解Java内存模型之系列篇