嘗試運行帶有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