尝试使用SecurityManager运行Java RMI应用程序时出现了一个奇怪的错误。当服务器启动时,我希望它从作为命令行参数提供的文件中读取文本。我正在使用Eclipse,并且此文件与Java项目的根目录位于同一目录中(因此我只能在命令行参数中提供文件名而不是完整路径)。我知道RMI的SecurityManager默认禁止文件I / O,所以我为我的服务器创建了一个如下所示的策略文件:
grant codeBase "file:///C:/Users/Edward/College/CS197/authmatch/bin/-" {
//Giving the server permission to make connections
permission java.net.SocketPermission "127.0.0.1:1024-", "connect, resolve";
permission java.net.SocketPermission "127.0.0.1:1024-", "accept, resolve";
//File I/O permissions
permission java.io.FilePermission "C:/Users/Edward/College/CS197/authmatch/-", "read,write,delete";
permission java.util.PropertyPermission "user.dir", "read";
permission java.lang.RuntimePermission "readFileDescriptor";
permission java.lang.RuntimePermission "modifyThread";
};
(注意我的Eclipse项目的名称是“authmatch”,这是在Windows上运行的)。在我的Eclipse运行配置中,我使用以下VM标志启用此策略文件:
-Djava.rmi.server.codebase=file:///C:/Users/Edward/Documents/College/CS197/authmatch/bin/
-Djava.security.policy=server.policy
我知道正在解析和加载策略文件,因为如果我在server.policy中引入语法错误,那么当我的应用程序运行时,Java会抱怨它(“错误解析文件”)。但是,安全管理器似乎忽略了我在策略中授予的权限,因为当我运行应用程序时,我收到此错误:
Exception in thread "main" java.security.AccessControlException: access denied ("java.io.FilePermission" "smalltest.txt" "read")
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkRead(Unknown Source)
at java.io.RandomAccessFile.<init>(Unknown Source)
at etremel.authmatch.text.TextFileFormatter.<init>(TextFileFormatter.java:39)
at etremel.authmatch.source.PatternMatcherSource.main(PatternMatcherSource.java:302)
由于我要求它读取的文件(smalltest.txt)位于“authmatch”项目目录中,并且我明确授予我的应用程序权限以使用该行读取该目录
permission java.io.FilePermission "C:/Users/Edward/College/CS197/authmatch/-", "read,write,delete";
为什么它仍然坚持它没有该文件的读取权限?我怀疑这可能是一个Windows问题,因为我在Linux计算机上运行相同的项目,类似的策略文件允许它从本地项目目录中读取就好了。
更新
我使用-Djava.security.debug=access,failure
运行服务器,并在解析策略文件时生成了一堆调试消息。您可以在this pastebin查看整个日志,但似乎有两个重要部分:
access: access allowed ("java.security.SecurityPermission" "getPolicy")
access: access allowed ("java.io.FilePermission" "C:\Users\Edward\Documents\College\CS197\authmatch\bin" "read")
access: domain that failed ProtectionDomain (file:/C:/Users/Edward/Documents/College/CS197/authmatch/bin/ <no signer certificates>)
sun.misc.Launcher$AppClassLoader@74ba86ef
<no principals>
java.security.Permissions@7a8a44a6 (
("java.io.FilePermission" "\C:\Users\Edward\Documents\College\CS197\authmatch\bin\-" "read")
("java.net.SocketPermission" "localhost:1024-" "listen,resolve")
...
......以及很久以后:
access: access allowed ("java.io.FilePermission" "C:\Users\Edward\Documents\College\CS197\authmatch\bin\etremel\authmatch\text\TextFileFormatter.class" "read")
access: access allowed ("java.util.PropertyPermission" "user.dir" "read")
access: access denied ("java.io.FilePermission" "smalltest.txt" "read")
看起来有某种“域名保护”失败,因为我的代码库没有签名,但我认为使用grant codeBase
设置指定没有签名的安全策略是可以接受的。更令人费解的是,它看起来不像是读取根authmatch目录的FilePermission,只是authmatch / bin目录。然后它得出结论,它应该拒绝访问“smalltest.txt”,但它永远不会解析该文件的完整目录路径。
请记住,相同的项目和策略在Linux上运行良好。
答案 0 :(得分:1)
问题出在您拼写代码库网址的方式和拼写方式之间:file:/C:/Users/Edward/Documents/College/CS197/authmatch/bin/
。它们不相同,因此您的grant
块不适用。看看“失败的域名”打印输出的内容:你的.policy内容不在那里。
关于签名者证书的内容不是错误,只是说没有签名者与“失败的域名”相关联。