Java RMI教程 – AccessControlException:拒绝访问(java.io.FilePermission

昨天我试着开始使用Java RMI。 我找到了这个sun教程( http://java.sun.com/docs/books/tutorial/rmi/index.html )并从服务器实现开始。 但每次我启动程序(rmiregistry正在运行)时,我会得到一个带有以下StackTrace的AccessControlException:

LoginImpl exception: java.security.AccessControlException: access denied (java.io.FilePermission \\\C\ProjX\server\serverProj\bin\usermanager read) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:264) at java.security.AccessController.checkPermission(AccessController.java:427) at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) at java.lang.SecurityManager.checkRead(SecurityManager.java:871) at java.io.File.exists(File.java:700) at sun.net.www.protocol.file.Handler.openConnection(Handler.java:80) at sun.net.www.protocol.file.Handler.openConnection(Handler.java:55) at java.net.URL.openConnection(URL.java:943) at sun.rmi.server.LoaderHandler.addPermissionsForURLs(LoaderHandler.java:1020) at sun.rmi.server.LoaderHandler.access$300(LoaderHandler.java:52) at sun.rmi.server.LoaderHandler$Loader.(LoaderHandler.java:1108) at sun.rmi.server.LoaderHandler$Loader.(LoaderHandler.java:1089) at sun.rmi.server.LoaderHandler$1.run(LoaderHandler.java:861) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.server.LoaderHandler.lookupLoader(LoaderHandler.java:858) at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:541) at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:628) at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:294) at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:238) at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1494) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1457) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1693) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1299) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:339) at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source) at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:375) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:240) at sun.rmi.transport.Transport$1.run(Transport.java:153) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:149) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:460) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:701) at java.lang.Thread.run(Thread.java:595) at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source) at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source) at sun.rmi.server.UnicastRef.invoke(Unknown Source) at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source) at startserver.StartServer.main(StartServer.java:22) 

我的server.policy文件如下所示:

 grant { permission java.security.AllPermission; }; 

但我也试过这个……

 grant { permission java.security.AllPermission; permission java.io.FilePermission "file://C:/ProjX/server/serverProj/bin/usermanager", "read"; }; 

……而这一个(以及其他几个:-():

 grant codeBase "file:///-" { permission java.security.AllPermission; }; 

但在每种情况下结果都是一样的。 是的,策略文件在路径中(当我在策略文件中写入错误的语句时,我看到了Parse Exception)。 我尝试了其他几个“/”和“\”星座,但它没有效果。

我使用Eclipse,我的VM-Parameters是这样的:

 -cp C:\ProjX\server\serverProj\bin\usermanager\ -Djava.rmi.server.codebase=file://C:/ProjX/server/serverProj/bin/usermanager/ -Djava.rmi.server.hostname=XYZ (anonymized) -Djava.security.policy=server.policy 

编译的Remote-Interface和接口实现类(LoginImpl)类在此路径中:“C:/ ProjX / server / serverProj / bin / usermanager /”。 我将instub实例化并重新绑定到注册表的主要方法是在另一个包中,如下所示:

 public static void main(String[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); } try { String name = "Login"; Login login = new LoginImpl(); Login stub = (Login) UnicastRemoteObject.exportObject(login, 0); Registry registry = LocateRegistry.getRegistry(); registry.rebind(name, stub); System.out.println("LoginImpl bound"); } catch (Exception e) { System.err.println("LoginImpl exception:"); e.printStackTrace(); } } 

有人对我有建议吗? 谢谢你的帮助。


所以问题是一样的(java.rmi.UnmarshalException表明更改代码库不是我的AccessControlException的解决方案)。 不,我不想买插件“GB”;-)。

授予所有代码的所有权限非常糟糕。 任何RMI客户端都可以像登录用户那样执行所需操作。 通常尝试尽可能合理地限制权限,尤其是当您不知道代码的来源时。

回到问题……

 -Djava.rmi.server.codebase=file://C:/ProjX/server/serverProj/bin/usermanager/ 

那应该是"file:///C:/...""file:/C:/..." 。 想想http。 "http://C:/..."是指名为C的主机。 请注意,exception消息已删除冒号,因为这只是端口号的语法。

即使您授予所有代码权限,您获得安全性exception的原因是,RMI会根据所涉及的URL限制权限(使用AccessController doPrivileged两个参数forms)。

好的,我有它。 它不是rmiregistry属性(没有任何参数工作)。 我的代码库VM-Parameter中有两个错误:

 -cp C:\ProjX\server\serverProj\bin\usermanager\ -Djava.rmi.server.codebase=file://C:/ProjX/server/serverProj/bin/usermanager/ -Djava.rmi.server.hostname=XYZ (anonymized) -Djava.security.policy=server.policy 

……应该看起来像这样:

 -Djava.rmi.server.codebase=file:/C:/ProjX/server/serverProj/bin/ -Djava.rmi.server.hostname=XYZ (anonymized) -Djava.security.policy=server.policy 

=> file:/(只有一个斜杠)+错误的包结束。

但是我的第一个想法是,跟踪是如此令人困惑,政策文件或政策配置必定是错误的。

不过:谢谢你的帮助和快乐的黑客攻击。 😉

您还可以以编程方式设置java.rmi.server.codebase属性:

 Hello h = null; Properties props = System.getProperties(); System.setProperty("java.rmi.server.codebase", "file:/C:/PROJECTX/bin/"); try { h = new HelloImpl(); Naming.bind("//localhost:1099/HelloService", h); System.out.println("Serwis gotów..."); } catch (RemoteException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (AlreadyBoundException e) { e.printStackTrace(); } 

对于一些假设的Hello RMI服务。

我认为这个例外实际上来自于rmiregistry。 堆栈跟踪的这一部分让我这么想。 rmir​​egistry的存根正在接收exception并将其作为重新绑定尝试的结果传回。

    在sun.rmi.transport.StreamRemoteCall。  exceptionReceivedFromServer (未知来源)
     at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
     at sun.rmi.server.UnicastRef.invoke(Unknown Source)
     at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)

尝试使用-J-Djava.security.policy=all.policy运行rmiregistry,其中策略文件授予所有权限(至少是为了让事情顺利进行)。

最后,您可能还希望切换到HTTP代码库URL,以便您可以在与服务器分开的计算机上运行客户端。

我的问题非常简短……

为什么他使用这条路径:“file:// C:/ ProjX / server / serverProj / bin / usermanager”我猜他是在windows中,windows中的路径写成C:\ ProjX ……我问,因为我也有一些RMI的问题,但我有这样的政策文件:

 grant codebase "file:///C:\Users\anna\Desktop\lab5\Eclipse\ProgramareServer\programare.jar-" { permission java.security.AllPermission; }; 

是错的吗?

当我在启动rmi注册表之前修复CLASSPATH变量时,它工作正常。 我认为这个想法是RMI注册表将加载你的远程存根,它应该有访问权限。 通过在运行注册表之前将我的类放在CLASSPATH上,这很容易。 因此它与任何其他原因无关,例如JDK 7或file:/ protocol。