尽管授予了适当的文件权限,但 Java AccessControlException

Posted

技术标签:

【中文标题】尽管授予了适当的文件权限,但 Java AccessControlException【英文标题】:Java AccessControlException despite granting appropriate file permission 【发布时间】:2012-10-29 20:10:49 【问题描述】:

我在尝试使用 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 上也可以正常工作。

【问题讨论】:

-Djava.security-debug=access,failure 运行它,你会看到到底发生了什么。在此处发布它的最后一点,即包含失败的那一点。但你并不真的需要在 RMI 服务器中使用 SecurityManager,除非客户端使用 java.rmi.server.codebase 功能为服务器提供 .class 文件。 【参考方案1】:

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

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

【讨论】:

我将 server.policy 的第一行更改为 grant codeBase "file:/C:/Users/Edward/College/CS197/authmatch/bin/-" 并将 VM 运行时参数更改为 -Djava.rmi.server.codebase=file:/C:/Users/Edward/Documents/College/CS197/authmatch/bin/,但这似乎没有什么不同 - 我得到了完全相同的“域failed”调试打印输出中的错误。 @Edward 你真的需要代码库字符串中的 - 吗?当然,这个目录要么包含大量 .jar 文件,要么是包结构的头部?当您按照“失败的域”日志中列出的方式尝试时会发生什么? 我去掉了“-”,但这并没有改变任何东西。然后我尝试从列出“失败的域”的日志中复制和粘贴,并且成功了。事实证明,我在codeBase 行中使用的路径中有错字——请注意,它不包括“Documents”文件夹,而实际的代码库路径却包含。好吧,我觉得自己很笨。 @Edward 所以基本上我的回答中的第一句话是正确的?

以上是关于尽管授予了适当的文件权限,但 Java AccessControlException的主要内容,如果未能解决你的问题,请参考以下文章

IOS Facebook SDK:尽管授予权限,但登录不返回电子邮件

在 java 中授予在硬盘驱动器上随处写入的权限

尽管没有超级用户,如何在 MYSQL 中向(root)用户授予超级权限?

Oracle Java 存储过程命令行交互

ORACLE - 已授予创建过程但无法创建过程

如何在使用 .NET 安装期间授予对文件夹的读/写权限