Java:无安全管理器:RMI 类加载器已禁用
您好,我有 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
远程类加载可能很棘手。
原始帖子不包含有关代码库的任何信息。可能客户端的安全配置是正确的,但它无法访问远程代码。这些类由客户端直接从“代码库”加载。服务不会通过 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 afile:
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.
每次在 RMI 动态代理上调用方法时,
MarshalInputStream
(扩展了ObjectInputStream
覆盖 < code>resolveClass 和resolveProxyClass
) 委托给 <代码> LoaderHandler 在 3 个位置查找要使用的ClassLoader
:latestUserDefinedLoader()
:它沿着堆栈向上查找,查找堆栈上第一个不属于 JRE 的方法)。contextClassLoader
java.rmi.server.useCodebaseOnly=false
,则代码库类加载器使用远程java.rmi.server.codebase< 中的 URL /代码>。请注意,useCodebaseOnly 的默认值已更改在 JDK 7u21 中,这样就不再使用远程代码库,除非您更改它!
java.rmi.server.codebase
中的 URL。因此,在调用远程方法时,有几个可能的原因会导致您收到
ClassNotFoundException
:-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 extendsObjectInputStream
to overrideresolveClass
andresolveProxyClass
) delegates toLoaderHandler
to look in 3 places for theClassLoader
to use:latestUserDefinedLoader()
: it walks up the stack, looking for the first method on the stack that is not part of JRE).contextClassLoader
of the callerjava.rmi.server.useCodebaseOnly=false
, then the codebase ClassLoader uses URLs in the remotejava.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!java.rmi.server.codebase
.So there are a few possible reasons that you would get a
ClassNotFoundException
when invoking a Remote method:-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.Thread.setContextClassLoader(ClassLoader)
so that RMI will use that ClassLoader. (This was my problem: I had aSwingWorker
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.
我想添加一些可能对某些人,尤其是初学者有帮助的内容。
我来到这里寻找上述错误的解决方案,但作为初学者,我不知道如何使用安全策略并指定“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 incom.example.springdemo.service.dto
.. The problem was that, using IntelliJ, because theservice
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.
您需要服务器端的安全管理器,而不仅仅是客户端。
如果没有这个,服务器的 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?
也许这不是原始问题的解决方案,但对我来说,该错误与我在客户端和服务器项目中没有相同的包名称有关。
请务必检查您的包是否具有相同的名称。
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.
我知道我的情况非常特殊,但也许对其他人有帮助。我遇到过这样的情况:一台服务器上有多个应用程序共享相同的注册表,当然路径不同。无论在何处创建此注册表(通常从第一个应用程序),所有后续应用程序的完整类路径都必须在第一个应用程序中指定。总结一下:
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:
我知道为什么会这样。
例如你在项目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.