Java:无安全管理器:RMI 类加载器已禁用

发布于 2024-11-15 05:08:39 字数 4436 浏览 5 评论 0原文

您好,我有 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;
}

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

Hi I have RMI application and now I try to invoke some methods at server from my client. I have following code:

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 Is correctly loaded, but when I am trying to call server.registerOHLCProvider(provider); I get these errors:

     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

I have added my policy file as VM argument, here is how it looks like:

grant {
    permission java.security.AllPermission;
}

It keeps saying something about disabled classloading, so I guess problem is somewhere there ...
Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

最冷一天 2024-11-22 05:08:39

远程类加载可能很棘手。

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

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

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

Remote class loading can be tricky.

The original post doesn't include any information about the code base. It may be that the client's security configuration is correct, but it has no access to the remote code. The classes are loaded directly from the "code base" by the client. They are not presented to the client by the service over the RMI connection. The service merely references an external source for the classes.

The server should specify the system property java.rmi.server.codebase. The value must be a URL that is accessible to the client, from which the necessary classes can be loaded. If this is a file: URL, the file system must be accessible to the client.

And the other way around: If the server should be able to load classes from the client (like here), the client must set the code base property to a URL that is accessible to the server.

后来的我们 2024-11-22 05:08:39

每次在 RMI 动态代理上调用方法时, MarshalInputStream (扩展了 ObjectInputStream 覆盖 < code>resolveClass 和 resolveProxyClass) 委托给 <代码> LoaderHandler 在 3 个位置查找要使用的 ClassLoader

  1. 正在调用的代理的 ClassLoader(从技术上讲,它使用了名为latestUserDefinedLoader():它沿着堆栈向上查找,查找堆栈上第一个不属于 JRE 的方法)。
  2. 调用者 Codebase ClassLoader 的线程本地 contextClassLoader
  3. 如果启用了 SecurityManager,则
    1. 如果系统属性 java.rmi.server.useCodebaseOnly=false,则代码库类加载器使用远程 java.rmi.server.codebase< 中的 URL /代码>。请注意,useCodebaseOnly 的默认值已更改在 JDK 7u21 中,这样就不再使用远程代码库,除非您更改它
    2. 否则,代码库 ClassLoader 使用本地 java.rmi.server.codebase 中的 URL。

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

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

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

Every time you invoke a method on an RMI dynamic proxy, the MarshalInputStream (which extends ObjectInputStream to override resolveClass and resolveProxyClass) delegates to LoaderHandler to look in 3 places for the ClassLoader to use:

  1. The ClassLoader of the proxy that is being invoked (technically, it uses a hack called latestUserDefinedLoader(): it walks up the stack, looking for the first method on the stack that is not part of JRE).
  2. Thread-local contextClassLoader of the caller
  3. Codebase ClassLoader if SecurityManager is enabled
    1. If System property java.rmi.server.useCodebaseOnly=false, then the codebase ClassLoader uses URLs in the remote java.rmi.server.codebase. Note that the default value of useCodebaseOnly changed in JDK 7u21 so that remote codebase is not used anymore unless you change it!
    2. Otherwise, the codebase ClassLoader uses URLs in the local java.rmi.server.codebase.

So there are a few possible reasons that you would get a ClassNotFoundException when invoking a Remote method:

  • If stack contains “no security manager: RMI class loader disabled”, then make sure to set a SecurityManager as described by others if you need remote class loading for both sides to get all the Remote interfaces and serializable classes.
  • If you are using remote class loading and it stopped working when you upgraded to JRE 7u21, then either set -Djava.rmi.server.useCodebaseOnly=true to match previous behavior, or set -Djava.rmi.server.codebase to a space-separated list of URLs on both the local and the remote sides. And make sure that computer can access those URLs.
  • If you are using a custom ClassLoader locally whose parent classloader defines some Remote interfaces, then make sure to call Thread.setContextClassLoader(ClassLoader) so that RMI will use that ClassLoader. (This was my problem: I had a SwingWorker that happened to be scheduled onto a worker thread that was created before the contextClassLoader was set on the EventDispatchThread). For example, A and C belong to your custom ClassLoader but B belongs to the parent ClassLoader, then when you call a.getB().getC(), the getB() call will use the custom classloader, but the getC() call will fail to find C in the latestUserDefinedClassLoader and will have to fall back to the contextClassLoader.

All of this is a cautionary tale on poor API design of ObjectInputStream. ObjectInputStream should have required you to pass a ClassLoader parameter, not try to find one haphazardly using latestUserDefinedLoader, contextClassLoader, and codebase.

鱼窥荷 2024-11-22 05:08:39

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

例子:
如果您想要从服务器向客户端发送 MeductionDTO 类型的对象(可序列化),请确保它位于同一包路径中。
就我而言,在服务器应用程序中,该对象位于 com.example.springdemo.dto 中,而在客户端应用程序中,该对象位于 com.example.springdemo.service.dto 中code>.. 问题是,使用 IntelliJ 时,由于 service 包中没有任何内容,而是另一个包,因此它们的名称被连接起来(service.dto)并且我看不到这条路不是 相同。
因此,请确保您的类具有相同的包路径。 (我的案例的解决方案:MeductionDTO类必须位于包中的两个应用程序中:com.example.springdemo.dto

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

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

I want to add something which may be helpful for some people, especially begginers.
I came here and searched for a solution for the above error, but being a beginner, I didn't know how to use security policies and specify the "java.rmi.server.codebase" attribute.
The simplest way to fix that error is to make sure that the classes of the objects to be sent over RMI are in the same path of packages.. In this way, both applications have the class in the same location relative to their main folder and the error will solve.

Example:
If you want to send an object of type MedicationDTO (which is serializable) from server to client, make sure that it is in the same package path.
In my case, in the server app, the object was in com.example.springdemo.dto and in the client app, it was in com.example.springdemo.service.dto.. The problem was that, using IntelliJ, because the service package had nothing in it, but an other package, their name was concatenated (service.dto) and I could not see that the path was not the same.
So, make sure that your classes have the same package path. (Solution for my case: MedicationDTO class has to be in both application in package: com.example.springdemo.dto.

I know this is not the best solution, it's just a 'little trick', but I would have been extremely happy to find this solution then, because it had saved me from a lot of wasted time to solve the problem.

I hope this will be helpful for those who want a quick fix to that error, because I think learning to use security managers and including codebase could be a little tricky and will take time.

禾厶谷欠 2024-11-22 05:08:39

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

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

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

You need the security manager at the server side, not only at the client side.

Without this, the server's RMI engine refuses to load classes from the client, as it can't guarantee that these won't do evil things on the server.

Do you need the RMI class loading at all? Couldn't the server already have the classes which the client tries to send?

凹づ凸ル 2024-11-22 05:08:39

也许这不是原始问题的解决方案,但对我来说,该错误与我在客户端和服务器项目中没有相同的包名称有关。
请务必检查您的包是否具有相同的名称。

Maybe it's not the solution for the original question, but for me the error was related to the fact I didn't have the package's names equal in both client and server projects.
Always check if your packages have the same name.

戒ㄋ 2024-11-22 05:08:39

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

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

I know my case is extremely special but maybe it helps others. I had the case that there were multiple applications on one server sharing the same registry with different paths of course. Wherever this registry is created (usually from the first application) the full classpath of all later applications must be specified in this first application. To sum it up:

  1. Make sure policy is provided
  2. Make sure classpath is full specified for all applications, clients and server
花开雨落又逢春i 2024-11-22 05:08:39

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

I know why it happens.
for example you start server in the project A,
but you use the Client in the project B to request this server,this is wrong.
So you should put the server and client in the same project.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文