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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/179799/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:57:57  来源:igfitidea点击:

Java RMI Tutorial - AccessControlException: access denied (java.io.FilePermission

javarmipolicy

提问by user25913

Yesterday I tried to get started with Java RMI. I found this sun tutorial (http://java.sun.com/docs/books/tutorial/rmi/index.html) and started with the server implemantation. But everytime I start the pogram (the rmiregistry is running) I get an AccessControlException with the following StackTrace:

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

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.access0(LoaderHandler.java:52)
    at sun.rmi.server.LoaderHandler$Loader.<init>(LoaderHandler.java:1108)
    at sun.rmi.server.LoaderHandler$Loader.<init>(LoaderHandler.java:1089)
    at sun.rmi.server.LoaderHandler.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.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.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)

My server.policy file looks like this:

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

grant {
    permission java.security.AllPermission;
};

But I′ve also tried this one ...

但我也试过这个...

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

... and this one (and several others :-():

......还有这个(以及其他几个:-():

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

But in every case the result is the same. And yes, the policy file is in path (I see a Parse Exception, when I write wrong statments into the policy-file). I tried out several other "/" and "\" constellations but it has no effect.

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

I use Eclipse and my VM-Parameters are like this:

我使用 Eclipse,我的 VM 参数是这样的:

-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

The compiled Remote-Interface and the interface-implementation class (LoginImpl) classes are in this path: "C:/ProjX/server/serverProj/bin/usermanager/". The main method, where I instanciate and rebind the stub to the registry is in another package and looks like this:

已编译的远程接口和接口实现类 (LoginImpl) 类位于以下路径中:“C:/ProjX/server/serverProj/bin/usermanager/”。我将存根实例化并将其重新绑定到注册表的主要方法位于另一个包中,如下所示:

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();
    }
}

Does anybody have an advice for me? Thank you for help.

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



So the question is the same (the java.rmi.UnmarshalException shows that changing the codebase is not the solution of my AccessControlException). And no: I don′t want to buy a plugin "G B" ;-).

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

回答by Tom Hawtin - tackline

Grant of all permissions to all code is a really bad. Any RMI client could do what it wanted as logged in user. In general try to restrict permissions as much as reasonable, particularly when you don't know where the code has come from.

授予所有代码的所有权限是非常糟糕的。任何 RMI 客户端都可以以登录用户的身份做它想做的事情。一般来说,尽量限制权限,特别是当你不知道代码来自哪里时。

Back to the question...

回到问题...

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

That should be either "file:///C:/..."or "file:/C:/...". Think of http. "http://C:/..."refers to a host named C. Note that the exception message has dropped the colon, because that's just syntax for port number.

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

The reason why you get a security exception even if you grant permissions to all code, is that RMI is restricting permissions to that appropriate given the URLs involved (using AccessController doPrivileged two argument form).

即使授予对所有代码的权限,也会出现安全异常的原因是 RMI 将权限限制为给定所涉及的 URL(使用 AccessController doPrivileged 两个参数形式)。

回答by bhavanki

I think the exception is actually coming out of rmiregistry. This part of the stack trace is what makes me think so. The stub for rmiregistry is receiving the exception and passing it back up as the result of the attempt to rebind.

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

    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)

Try running rmiregistry with -J-Djava.security.policy=all.policy, where the policy file grants all permissions (at least to get things going).

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

Eventually you may also wish to switch to an HTTP codebase URL, just so that you can run clients on a machine separate from your server's.

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

回答by user25913

Ok, I have it. It wasn´t the rmiregistry property (works without any parameters). There were two errors in my codebase VM-Parameter:

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

-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

... should instead look like this:

... 应该是这样的:

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

=> file:/ (only one slash) + wrong package ending.

=> 文件:/(只有一个斜杠)+ 错误的包结尾。

But the trace was so confusing, my first thought was, that somthing must be wrong with the policy-file or policy-configuration.

但是跟踪如此混乱,我的第一个想法是,策略文件或策略配置一定有问题。

Nevertheless: Thank you for help and happy hacking. ;-)

尽管如此:感谢您的帮助和愉快的黑客攻击。;-)

回答by Piotr Kochański

You can also set programatically java.rmi.server.codebase property:

您还可以以编程方式设置 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();
}

for some hypothetical HelloRMI service.

对于一些假设的HelloRMI 服务。

回答by Tarek

It just works fine when I fixed the CLASSPATH variable before starting the rmi registry. I think the idea is that the RMI Registry will load your remote stubs and it should has access. That's was easy by putting my classes on the CLASSPATH before running the registry. So it is not related to any other reason such as JDK 7 or file:/ protocol.

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