Java虚拟机体系结构 - 访问策略2

栈检查示例:

friend.jar和stranger.jar文件的签名方法见(Java虚拟机体系结构 - JAR包的签名与认证

策略文件(policyfile.txt):

keystore "ijvmkeys"	//密钥别名,指向存储在名为"ijvmkeys"的文件中的证书
grant signedBy "friend" {	//授予别名为friend的公司或者个人签名的代码读取question.txt和answer.txt的权限
        permission java.io.FilePermission "question.txt"
        permission java.io.FilePermission "answer.txt"
};

grant singedBy "stranger" {
        permission java.io.FilePermission "question.txt"
};

grant codeBase "file:${com.artima.ijvm.cdrom.home}/security/ex2/*" {	//赋予以下两个权限给从一个特定目录装载的代码
        permission java.io.FilePermission "question.txt","read";
        permission java.io.FilePermission "answer.txt","read";
};

接口Doer类(security/ex2/com/artima/security/doer/Doer.java):

package com.artima.security.doer;
public interface Doer {
        void doYourThing();
}

TextFileDisplayer.java实现接口Doer的类(security/ex2/TextFileDisplayer.java),读取并显示文件内容:

import com.artima.security.doer.Doer;
import java.io.FileReader;
import java.io.CharArrayWriter;
import java.io.IOException;

public class TextFileDisplayer implements Doer { 
        private String fileName; 
        public TextFileDisplayer(String fileName){              
                this.fileName = fileName; 
        }
        public void doYourThing(){ 
                try { 
                        FileReader fr = new FileReader(fileName); 
                        try { 
                                CharArrayWriter caw = new CharArrayWriter(); 
                                int c; 
                                while ((c = fr.read()) != -1) { caw.writer(c); }
                                 System.out.println(caw.toString()); 
                                }catch(IOException e){} 
                                finally { 
                                        try { 
                                                fr.close(); 
                                        }catch(IOException e) {} 
                                } 
                        } 
                }
        }

Friend.java以及Stranger.java实现Doer.java接口(位于security/ex2/com/artima/security/friend/目录下):

//security/ex2/com/artima/security/friend/Friend.java
package com.artima.security.friend;
import com.artima.security.doer.Doer;
import java.security.AccessController;
import java.security.PrivilegedAction;

public class Friend implements Doer {
        private Doer next;
        private boolean direct;
        public Friend(Doer next,boolean direct) {
                this.next = next;
                this.direct = direct;
        }
        public void doYourThing() {
                if (direct) {
                        next.doYourThing();
                }
                else {
                        AccessController.doPrivileged(new PrivilegedAction(){
                                public Object run() {
                                        next.doYourThing();
                                        return null;
                                }
                        });
                }
        }
}

//security/ex2/com/artima/security/stranger/Stranger.java
package com.artima.security.stranger;
import com.artima.security.doer.Doer;
import java.security.AccessController;
import java.security.PrivilegedAction;

public class Stranger implements Doer {
        private Doer next;
        private boolean direct;

        public Stranger(Doer next,boolean direct) {
                this.next = next;
                this.direct = direct;
        }

        public void doYourThing() {
                if (direct) {
                        next.doYourThing();
                }
                else {
                        AccessController.doPrivileged(new PrivilegedAction(){
                                public Object run() {
                                        next.doYourThing();
                                        return null;
                                }
                        });
                }
}

可以通过检查的例子:(Example2a.java)

import com.artima.security.friend.Friend;
import com.artima.security.stranger.Stranger;

class Example2a {
        public static void mani(String []args) {
                TextFileDisplayer tfd = new TextFileDisplayer("question.txt");
                Friend friend = new Friend(tfd,true);
                Stranger stranger = new Stranger(friend,true);
                stranger.doYourThing();
        }
}

 
 
 
 
 
 Example2a程序通过stranger引用变量调用Stranger对象的doyourThing( )方法,Stranger对象又调用了Friend对象的doYourThing( )方法,Friend对象又调用了TextFileDisplay的doYourThing( )方法,该方法视图打开并读取当前目录下的question.txt文件,当TextFileDisplay的doYourThing( )方法创建一个新的FileReader对象时,FileReader的构造器创建了一个新的FileInputStream,FileInputStream构造器检查是否已经安全了一个安装管理器,在此例中,已经安装了具体的安全管理器,因此,FileInputStream的构造函数调用具体安全管理器的checkRead( )方法,checkRead()方法实例化了一个新的、代表读取文件question.txt权限的FilePermission对象,并把这个对象传递给具体安全管理器的checkPermission( )方法,这个checkPermission( )方法又把这个对象传递给AccessController的checkPermission( )方法。AccessController的checkPermission( )方法执行栈检查,确定这个县城是否有权限打开并读取question.txt文件。如表1-1显示了AccessController的checkPermission方法调用时,调用栈的情况: 
表1-1 Example2a中的栈检查
方法保护域 
Example2amain()CDROM1栈底
com.artima.security.stranger.StrangerdoYourThing()STRANGER2
com.artima.security.friend.FrienddoYourThing()FRIEND3
TextFileDisplayerdoYourThing()CDROM4
java.io.FileReader<init>()BOOTSTRAP5
java.i.FileInputStream<init>()BOOTSTRAP6
java.lang.SecurityManagercheckRead()BOOTSTRAP7
java.lang.SecurityManagercheckPermission()BOOTSTRAP8
java.security.AccessControllercheckPermission()BOOTSTRAP9
java.security.AccessControlContextcheckPermission()BOOTSTRAP10栈顶
表1-1中的保护域列表明每个栈帧都和下面四个保护域中的一个相关联:FRIEND、STRANGER、CD-ROM、以及的BOOTSTRAP。这些保护域中的三个和policyfile.txt策略文件中的grant子句相对应。其中和CD-ROM相关联的grant子句赋予由目录“${com.artima.ijvm.cdrom.home}/security/ex2"装载的代码读取文件question.txt和answer.txt文件的权限;BOOTSTRAP保护域代表赋予由启动类装载器装载的代码的任何权限,在保护域BOOTSTRAP中的代码被赋予了java.lang.AllPermission权限,该权限允许做任何事。
当AccessController执行它的栈检查时,它从栈帧10开始逐个向下直到栈帧1,栈帧1是由线程调用的第一个方法main方法,在Example2a中,调用栈的每一个栈帧都有权执行读取文件quesion.txt的操作,因此当AccessController执行checkPermission方法到达栈底时,不会抛出任何栈帧无权读取这个文件的情况,它将正常返回,并打印输出从question.txt读取的文件内容。

不能通过检查的例子:(Example2b.java)

import com.artima.security.friend.Friend;
import com.artima.security.stranger.Stranger;

class Example2a {
        public static void main(String []args) {
                TextFileDisplayer tfd = new TextFileDisplayer("answer.txt");
                Friend friend = new Friend(tfd,true);
                Stranger stranger = new Stranger(friend,true);
                stranger.doYourThing();
        }
}
<span style="font-size: 18px; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">Example2b.java与Example2a.java唯一不同之处在于Example2a将名字为question.txt的文件传递给TextFileDisplay构造器,而Example2b则是传递名字为answer.txt的文件,因为在栈中,有一个方法没有访问answer.txt文件的权限,因此该栈检查不能通过而抛出AccessControllerException异常。调用栈检查如表1-2所示:</span>
表1-2 Example2b中的栈检查
方法保护域 
Example2amain()CDROM1栈底
com.artima.security.stranger.StrangerdoYourThing()STRANGER2
com.artima.security.friend.FrienddoYourThing()FRIEND3
TextFileDisplayerdoYourThing()CDROM4
java.io.FileReader<init>()BOOTSTRAP5
java.i.FileInputStream<init>()BOOTSTRAP6
java.lang.SecurityManagercheckRead()BOOTSTRAP7
java.lang.SecurityManagercheckPermission()BOOTSTRAP8
java.security.AccessControllercheckPermission()BOOTSTRAP9
java.security.AccessControlContextcheckPermission()BOOTSTRAP10栈顶

使用doPrivileged() 方法

基本的AccessController算法防止了任何代码执行任何不可信任的代码,因此,一个权限较少的保护域的方法无权调用属于更高权限的保护域的方法,这个基本算法同时隐含了,如果一个属于较高权限保护域的方法调用了属于较低权限保护域的中的方法,它必须自动放弃某些权限。AccessController严格坚持在调用栈中的所有栈帧都必须含有执行被请求操作的权限,而这一点在很多情况下都太苛刻,为了使可信的代码执行不可靠的代码操作,AccessController类重载了四个名为doPrivileged( )静态方法,这四个方法都接收一个实现了java.security.PrivilegedAction接口或者java.security.PrivilegedExceptionAction接口的对象作为它的参数。当调用doPrivileged()方法时,就像调用其他任何方法一样,都会将一个新的栈帧压入栈。在由AccessController执行的栈检查中,一个doPrivileged()方法调用的栈帧标志了检查过程提前终止点。如果和调用doPr
ivileged()方法相关联的保护域拥有被请求操作权限,AccessController将立即返回,这样的操作就被允许,及时在栈下层的代码可能没有执行这个操作的权限。例如Example2c.java:
import com.artima.security.friend.Friend;
import com.artima.security.stranger.Stranger;

class Example2a {
        public static void mani(String []args) {
                TextFileDisplayer tfd = new TextFileDisplayer("answer.txt");
                Friend friend = new Friend(tfd,false);
                Stranger stranger = new Stranger(friend,true);
                stranger.doYourThing();
        }
}

调用栈检查如表1-3所示:

表1-3  Example2c中的栈检查
在Example2c中要被检查的调用栈中加入了另外两个栈帧:栈帧4代表了doPrivileged()调用,栈帧5代表了PrivilegedAction对象的run()方法调用。当AccessController进行栈检查时,当它遇到栈帧4,发现是一个doPrivileged()调用,以此,AccessController又进行了一个检查:检查由栈帧3代表的代码,也就是调用了doPrivilegedd()的代码,是否有读取文件answer.txt的权限。因为栈帧3是和FRIEND保护域相关联的,而FRIEND保护域拥有读取文件answer.txt的权限,所以AccessController的checkPermission()方法正常返回,停止了栈帧3以后的栈帧检查。
执行(须将以上文件移到 d:\books\InsideJVM\manuscript\cdrom目录下):
java -Djava.security.manager -Djava.security.policy=policyfile.txt -Dcom.artima.ijvm.cdrom.home=d:\books\InsideJVM\manuscript\cdrom -cp .;jars/friend.jar;jars/stranger.jar Example2a


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值