尝试运行带有SecurityManager的Java RMI应用程序时出现了一个奇怪的错误。当服务器启动时,我希望它从作为命令行参数提供的文件中读取文本。我使用的是Eclipse,并且这个文件和Java项目的根目录在同一个目录下(所以我可以在命令行参数中给出文件名而不是完整的路径)。我知道,RMI公司的安全管理器默认禁止的文件I/O,所以我创造了我的服务器策略文件看起来像这样:尽管授予适当的文件权限,但Java AccessControlException
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计算机上运行相同的项目,并且类似的策略文件允许它从本地项目目录中读取就好了。
UPDATE
我跑了服务器-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>)
[email protected]
<no principals>
[email protected] (
("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上运行良好。
使用'-Djava.security-debug = access,failure'运行它,您将看到到底发生了什么。在这里发布最后一点,这是包含失败的一点。但是,除非客户端使用java.rmi.server.codebase功能向服务器提供.class文件,否则在RMI服务器中并不需要'SecurityManager'。 – EJP