我写了一个简单的RMI服务器并给它一个默认的RMISecurityManager
:
System.setSecurityManager (new RMISecurityManager());
当我尝试运行服务器时,它会引发异常:
java.security.AccessControlException
:访问被拒绝(“java.net.SocketPermission”“127.0.0.1:1099”“connect,resolve”)
我认为如果任何下载的代码试图连接某个地方,安全管理器会抛出异常。但是,当服务器本身尝试执行某些操作时,安全管理器正在抱怨。为什么呢?
这是服务器的代码(来自Oracle RMI教程,但我添加了RMISecurityManager):
package example.hello;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RMISecurityManager;
public class Server implements Hello {
public Server() {}
public String sayHello() {
return "Hello, world!";
}
public static void main(String args[]) {
try {
Server obj = new Server();
// * Addition *
System.setSecurityManager (new RMISecurityManager());
// Create object that will provide the remote service
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);
// Bind the remote object's stub in the registry
Registry registry = LocateRegistry.getRegistry();
registry.bind("Hello", stub);
System.err.println("Server ready");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
}
我这样做:
$ javac -d classes example / * java
$ java -cp pwd
/ classes -Djava.rmi.server.codebase = file:pwd
/ classes / example.hello.Server
服务器异常:java.security.AccessControlException:拒绝访问(“java.net.SocketPermission”“127.0.0.1:1099”“connect,resolve”) java.security.AccessControlException:拒绝访问(“java.net.SocketPermission”“127.0.0.1:1099”“connect,resolve”) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:372) at java.security.AccessController.checkPermission(AccessController.java:559) 在java.lang.SecurityManager.checkPermission(SecurityManager.java:549) 在java.lang.SecurityManager.checkConnect(SecurityManager.java:1051) 在java.net.Socket.connect(Socket.java:574) 在java.net.Socket.connect(Socket.java:528) 在java.net.Socket。(Socket.java:425) 在java.net.Socket。(Socket.java:208) at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:40) at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:146) at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613) at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216) at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202) at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:340) at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source) 在example.hello.Server.main(Server.java:66)
更新
我对RMISecurityManager的理解不正确。我假设它的沙箱仅自动应用于外部代码,即客户端提交的代码以供执行(如Oracle RMI教程中的“计算引擎”示例)。创建以下策略允许服务器在启动时与RMI注册表通信,异常消失:
grant codeBase "file:/path/to/classes/" {
permission java.net.SocketPermission "127.0.0.1:1099", "connect, resolve";
};
但是如何使用安全管理器创建特定于下载代码的规则?
答案 0 :(得分:1)
如果您使用安全管理器,则还需要提供.policy文件,该文件为您提供所需的权限。
除非您使用代码库功能,否则您不需要使用RMI的安全管理器。当使用它时,它通常为客户端而不是服务器提供类,因此客户端需要安全管理器而不是服务器。你可能不必要地安装它。