【问题标题】:Java: no security manager: RMI class loader disabledJava:没有安全管理器:禁用 RMI 类加载器
【发布时间】:2011-09-13 09:45:54
【问题描述】:

您好,我有 RMI 应用程序,现在我尝试从客户端调用服务器上的一些方法。我有以下代码:

public static void main(final String[] args) {
    try {
        //Setting the security manager

        System.setSecurityManager(new RMISecurityManager());
        IndicatorsService server = (IndicatorsService) Naming
                .lookup("rmi://localhost/" + IndicatorsService.SERVICE_NAME);
        DataProvider provider = new OHLCProvider(server);
        server.registerOHLCProvider(provider);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (RemoteException e) {
        e.printStackTrace();
    } catch (NotBoundException e) {
        e.printStackTrace();
    }
}

服务器已正确加载,但当我尝试调用 server.registerOHLCProvider(provider); 时出现以下错误:

     java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:336)
    at sun.rmi.transport.Transport$1.run(Transport.java:159)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142)
    at sk.fri.statistics.service.impl.IndicatorsServiceImpl_Stub.registerOHLCProvider(Unknown Source)
    at sk.fri.statistics.service.Client.main(Client.java:61)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:296)
    at sun.rmi.transport.Transport$1.run(Transport.java:159)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
    at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:375)
    at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:165)
    at java.rmi.server.RMIClassLoader$2.loadClass(RMIClassLoader.java:620)
    at java.rmi.server.RMIClassLoader.loadClass(RMIClassLoader.java:247)
    at sun.rmi.server.MarshalInputStream.resolveClass(MarshalInputStream.java:197)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
    at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:306)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:290)
    ... 9 more

我已将我的策略文件添加为 VM 参数,如下所示:

grant {
    permission java.security.AllPermission;
}

它一直在说禁用类加载,所以我猜问题出在某个地方...... 谢谢!

【问题讨论】:

  • 如果你在设置安全管理器之前嵌入了这个调用System.getProperty("java.security.policy");,它会返回什么?不知何故,我认为你应该在代码中设置安全策略属性,尽管它作为命令行参数传递。
  • 正确打印策略文件的路径。 /home/miso/workspace/IndikatoryClient/security.policy

标签: java networking remoting rmi securitymanager


【解决方案1】:

远程类加载可能很棘手。

原始帖子不包含有关代码库的任何信息。可能是客户端的安全配置是正确的,但是它无法访问远程代码。这些类由客户端直接从“代码库”加载。服务不会通过 RMI 连接将它们呈现给客户端。该服务仅引用类的外部源。

服务器应指定系统属性java.rmi.server.codebase。该值必须是客户端可访问的 URL, 可以从该 URL 加载必要的类。如果这是一个file: URL,则文件系统必须可供客户端访问。

反之亦然:如果服务器应该能够从客户端加载类(如这里),则客户端必须将代码库属性设置为服务器可访问的 URL。

【讨论】:

  • 很好,先生,我在服务器指定了代码库,但在客户端没有指定。这就是问题所在。谢谢您的帮助!稍后我会添加赏金(stackoverflow 规则)
【解决方案2】:

每次调用 RMI 动态代理上的方法时,MarshalInputStream(扩展 ObjectInputStream 以覆盖 resolveClassresolveProxyClass)代表 LoaderHandler 在 3 个位置查找 ClassLoader使用:

  1. 正在调用的代理的 ClassLoader(从技术上讲,它使用称为 latestUserDefinedLoader() 的 hack:它在堆栈中向上遍历,寻找堆栈上不属于 JRE 的第一个方法)。
  2. 调用者的线程本地contextClassLoader
  3. 代码库类加载器(如果启用了 SecurityManager)
    1. 如果系统属性java.rmi.server.useCodebaseOnly=false,则代码库类加载器使用远程 java.rmi.server.codebase 中的URL。请注意default value of useCodebaseOnly changed in JDK 7u21 so that remote codebase is not used anymore unless you change it!
    2. 否则,代码库 ClassLoader 会使用 local java.rmi.server.codebase 中的 URL。

因此,在调用 Remote 方法时,有几个可能的原因会导致您收到 ClassNotFoundException

  • 如果堆栈包含“无安全管理器:RMI 类加载器已禁用”,如果您需要为双方加载远程类以获取所有远程接口和可序列化类,请确保按照其他人的描述设置 SecurityManager。
  • 如果您正在使用远程类加载,并且在升级到 JRE 7u21 后它停止工作,则将 -Djava.rmi.server.useCodebaseOnly=true 设置为匹配以前的行为,或者将 -Djava.rmi.server.codebase 设置为本地和本地 URL 的空格分隔列表遥远的一面。并确保计算机可以访问这些 URL。
  • 如果您在本地使用自定义 ClassLoader,其父类加载器定义了一些远程接口,请确保调用 Thread.setContextClassLoader(ClassLoader) 以便 RMI 将使用该 ClassLoader。 (这是我的问题:我有一个 SwingWorker 恰好被安排到一个工作线程上,该工作线程是在 EventDispatchThread 上设置 contextClassLoader 之前创建的)。比如A和C属于你自定义的ClassLoader,而B属于父ClassLoader,那么当你调用a.getB().getC()时,getB()调用会使用自定义的classloader,但是getC()调用将无法在 latestUserDefinedClassLoader 中找到 C,将不得不退回到 contextClassLoader。

所有这些都是对 ObjectInputStream 糟糕的 API 设计的警示。 ObjectInputStream 应该要求您传递一个 ClassLoader 参数,而不是尝试使用 latestUserDefinedLoader、contextClassLoader 和代码库随意查找。

【讨论】:

  • 在您的第二个项目符号中:“然后将-Djava.rmi.server.useCodebaseOnly=true 设置为匹配先前的行为”必须阅读-Djava.rmi.server.useCodebaseOnly=falseReference.
【解决方案3】:

我想添加一些可能对某些人有帮助的东西,尤其是初学者。 我来到这里,寻找解决上述错误的方法,但是作为初学者,我不知道如何使用安全策略并指定“java.rmi.server.codebase”属性。 修复该错误的最简单方法是确保要通过 RMI 发送的对象的类位于相同的包路径中。这样,两个应用程序的类相对于它们的主文件夹位于相同的位置,并且错误将解决。

示例: 如果要从服务器向客户端发送MedicationDTO 类型的对象(可序列化),请确保它位于相同的包路径中。 在我的情况下,在服务器应用程序中,对象位于 com.example.springdemo.dto 中,而在客户端应用程序中,它位于 com.example.springdemo.service.dto.. 问题是,使用 IntelliJ,因为 service 包中没有任何内容,但是另一个包,它们的名称是连接的(service.dto),我看不出路径不一样。 因此,请确保您的类具有相同的包路径。 (我的情况的解决方案:MedicationDTO 类必须在包中的两个应用程序中:com.example.springdemo.dto

我知道这不是最好的解决方案,它只是一个“小技巧”,但我会非常高兴找到这个解决方案,因为它让我免于浪费大量时间来解决问题。

我希望这对那些想要快速修复该错误的人有所帮助,因为我认为学习使用安全管理器和包含代码库可能有点棘手并且需要时间。

【讨论】:

    【解决方案4】:

    您需要服务器端的安全管理器,而不仅仅是客户端。

    如果没有这个,服务器的 RMI 引擎会拒绝从客户端加载类,因为它不能保证这些不会在服务器上做坏事。

    您是否需要加载 RMI 类?服务器不能已经有客户端尝试发送的类吗?

    【讨论】:

    • 是的,我确实需要在客户端创建类。我应该如何创建 SecurityManager @server 端?与客户端相同,只需设置 System.setSecurityManager(new RMISecurityManager()); ?谢谢
    • 是的(但您也可以简单地使用new SecurityManager() 或您的自定义安全管理器,因为RMISecurityManager 在这里没有什么特别之处)。不过,我不确定您的 AllPermission 是否真的是您在生产系统上想要的。
    • 当然不是,但问题出在其他地方,服务器不知道客户端的类。请参阅我对@ericksson 的评论。
    • 不,这可能是一个额外的问题,但不是您的堆栈跟踪所指示的问题。您将需要两者来转移课程。
    【解决方案5】:

    我知道我的情况非常特别,但也许它可以帮助其他人。我的情况是,一台服务器上的多个应用程序当然以不同的路径共享同一个注册表。无论在何处创建此注册表(通常从第一个应用程序开始),所有后续应用程序的完整类路径都必须在此第一个应用程序中指定。总结一下:

    1. 确保提供政策
    2. 确保为所有应用程序、客户端和服务器指定完整的类路径

    【讨论】:

      【解决方案6】:

      我知道为什么会这样。 例如,您在项目 A 中启动服务器, 但是您使用项目B中的客户端请求此服务器,这是错误的。 所以你应该把服务端和客户端放在同一个项目中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-21
        • 2023-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-26
        • 2010-10-20
        • 2017-03-06
        相关资源
        最近更新 更多