Java: no security manager: RMI class loader disabled
Asked Answered
T

7

32

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!

Trigonal answered 12/6, 2011 at 13:7 Comment(3)
If you embed this call System.getProperty("java.security.policy"); before setting the security manager, what does it return? Somehow, I think you should set the security policy property in code, despite passing it as a command line argument.Steamship
It correctly prints path of policy file. /home/miso/workspace/IndikatoryClient/security.policyTrigonal
No. The problem is the ‘ClassNotFoundException`. The bit in parentheses is just that: parenthetical. It is not a suggestion to add a security manager or use the codebase feature.Sashasashay
A
29

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.

Alexandriaalexandrian answered 14/6, 2011 at 18:27 Comment(3)
Very well sir, I had codebase specified at server, but not at client. That was the issue. Thank you for your help! I'll add bounty later (stackoverflow rules)Trigonal
You are putting the cart before the horse. The OP should ensure that the necessary classes are available to the Registry and the client. The RMI codebase feature is optional, and the security manager feature is only a requirement to use that other optional feature. Don't confuse a parenthetical remark in the error message with the actual problem, which is ClassNotFoundException, and to which there is a far simpler solution than (a) adding a security manager, (b) setting java.rmi.server.codebase, and (c) organizing an HTTP server or whatever to be the recipient of codebase requests.Sashasashay
@user207421what would that simpler solution look like?Kanchenjunga
H
8

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.

Houser answered 29/7, 2013 at 18:29 Comment(1)
In your second bullet: "then either set -Djava.rmi.server.useCodebaseOnly=true to match previous behavior" must be read -Djava.rmi.server.useCodebaseOnly=false. Reference.Middlings
J
7

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.

Jackpot answered 17/1, 2020 at 10:32 Comment(0)
E
3

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?

Escalante answered 14/6, 2011 at 18:18 Comment(5)
Yes I do need classes to be created at client side. How should I create SecurityManager @server side? Same as at client, just set System.setSecurityManager(new RMISecurityManager()); ? ThanksTrigonal
Yes (but you could also simply use new SecurityManager(), or your custom security manager, as the RMISecurityManager does nothing special here). I'm not sure your AllPermission is really what you want on production systems, though.Peria
It is not of course, but the problem lied somewhere else, that server was not aware of client's classes. See my comment to @ericksson.Trigonal
Nah, this may be an additional problem, but not the one indicated by your stack trace. You will need both to transfer classes.Peria
You don't need the SecurityManager at all. The real issue here is the ClassNotFoundException, which is due to mis-deployment, not the parenthetical remark about the security manager in the error message. First things first. The security manager isn't a solution at all unless you also use the codebase feature, for which it is a prerequisite, but you don't have to do that either.Sashasashay
D
2

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.

Digitalize answered 15/3 at 23:12 Comment(0)
N
0

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
Nerynesbit answered 10/2, 2021 at 9:37 Comment(0)
P
-5

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.

Plum answered 21/4, 2014 at 10:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.