【问题标题】:Java RMI Tutorial - AccessControlException: access denied (java.io.FilePermissionJava RMI 教程 - AccessControlException:访问被拒绝 (java.io.FilePermission
【发布时间】:2010-09-15 20:09:43
【问题描述】:

昨天我尝试开始使用 Java RMI。我找到了这个 sun 教程 (http://java.sun.com/docs/books/tutorial/rmi/index.html) 并从服务器实施开始。但是每次我启动 pogram(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.<init>(LoaderHandler.java:1108)
    at sun.rmi.server.LoaderHandler$Loader.<init>(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;
};

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

我使用 Eclipse,我的虚拟机参数是这样的:

-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/”。我将存根实例化并将其重新绑定到注册表的主要方法位于另一个包中,如下所示:

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”;-)。

【问题讨论】:

标签: java rmi policy


【解决方案1】:

授予所有代码的所有权限真的很糟糕。任何 RMI 客户端都可以作为登录用户做它想做的事情。一般来说,尽量限制权限,尤其是当您不知道代码来自何处时。

回到问题...

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

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

即使您向所有代码授予权限,您也会获得安全异常的原因是,RMI 将权限限制在给定所涉及的 URL 的适当位置(使用 AccessController doPrivileged 两个参数形式)。

【讨论】:

  • 嘿!我发现这很有帮助。你能告诉我在哪里存储 server.policy 文本文件吗?
  • @user1799214 原发布者使用了hte服务器的当前工作目录,用-Djava.security.policy=server.policy指定。 (与往常一样,移除对网络可访问代码的限制很难安全地做到。)
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

    好的,我知道了。它不是 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
    

    ... 应该看起来像这样:

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

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

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

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

    【讨论】:

      【解决方案4】:

      您还可以通过编程方式设置 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 服务。

      【讨论】:

      • 我似乎无法设置此属性。我的 Java 似乎不允许我执行 set 操作。
      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 2011-01-26
        • 1970-01-01
        • 2012-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-19
        相关资源
        最近更新 更多