1

我在尝试使用 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它在解析策略文件时生成了一堆调试消息。您可以在这个 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 上运行良好。

4

1 回答 1

2

问题在于您拼写代码库 URL 的方式和它的拼写方式:file:/C:/Users/Edward/Documents/College/CS197/authmatch/bin/. 它们不一样,所以你的grant块不适用。查看“失败的域”打印输出的内容:您的 .policy 内容不在其中。

关于签名者证书的内容不是错误,它只是说没有与“失败的域”关联的签名者。

于 2012-10-30T05:52:23.027 回答