Java RMI Tutorial - AccessControlException: access denied (java.io.FilePermission
Asked Answered
B

5

15

Yesterday I tried to get started with Java RMI. I found this sun tutorial (http://java.sun.com/docs/books/tutorial/rmi/index.html) and started with the server implemantation. But everytime I start the pogram (the rmiregistry is running) I get an AccessControlException with the following StackTrace:

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)

My server.policy file looks like this:

grant {
    permission java.security.AllPermission;
};

But I have also tried this one:

grant {
    permission java.security.AllPermission;
    permission java.io.FilePermission "file://C:/ProjX/server/serverProj/bin/usermanager", "read";
};

... and this one (and several others :-():

grant codeBase "file:///-" {
    permission java.security.AllPermission;
};

But in every case the result is the same. And yes, the policy file is in path (I see a Parse Exception, when I write wrong statments into the policy-file). I tried out several other "/" and "" constellations but it has no effect.

I use Eclipse and my VM-Parameters are like this:

-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

The compiled Remote-Interface and the interface-implementation class (LoginImpl) classes are in this path: "C:/ProjX/server/serverProj/bin/usermanager/". The main method, where I instanciate and rebind the stub to the registry is in another package and looks like this:

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();
    }
}

Does anybody have an advice for me?


So the question is the same (the java.rmi.UnmarshalException shows that changing the codebase is not the solution of my AccessControlException). And no: I don't want to buy a plugin "G B".

Beecher answered 7/10, 2008 at 18:41 Comment(1)
I had a similar issue. I resolved it via this approach - https://mcmap.net/q/825012/-reading-a-file-in-an-elasticsearch-pluginPutup
M
7

Grant of all permissions to all code is a really bad. Any RMI client could do what it wanted as logged in user. In general try to restrict permissions as much as reasonable, particularly when you don't know where the code has come from.

Back to the question...

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

That should be either "file:///C:/..." or "file:/C:/...". Think of http. "http://C:/..." refers to a host named C. Note that the exception message has dropped the colon, because that's just syntax for port number.

The reason why you get a security exception even if you grant permissions to all code, is that RMI is restricting permissions to that appropriate given the URLs involved (using AccessController doPrivileged two argument form).

Mintz answered 7/10, 2008 at 20:14 Comment(2)
Hey! I found this to be very helpful. Could you please tell me where to store server.policy text file?Cheka
@Cheka The original poster used the current working directory of hte server, specifying with -Djava.security.policy=server.policy. (As always, removing restrictions on network-accessible code is tricky to do safely.)Mintz
B
7

Ok, I have it. It wasn´t the rmiregistry property (works without any parameters). There were two errors in my codebase VM-Parameter:

-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

... should instead look like this:

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

=> file:/ (only one slash) + wrong package ending.

But the trace was so confusing, my first thought was, that somthing must be wrong with the policy-file or policy-configuration.

Nevertheless: Thank you for help and happy hacking. ;-)

Beecher answered 14/10, 2008 at 18:10 Comment(0)
H
2

You can also set programatically java.rmi.server.codebase property:

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();
}

for some hypothetical Hello RMI service.

Hickie answered 12/11, 2008 at 18:18 Comment(1)
I seem to be unable to set this property. My Java seems to disallow me to execute the set operation.Abecedary
E
0

I think the exception is actually coming out of rmiregistry. This part of the stack trace is what makes me think so. The stub for rmiregistry is receiving the exception and passing it back up as the result of the attempt to rebind.

    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)

Try running rmiregistry with -J-Djava.security.policy=all.policy, where the policy file grants all permissions (at least to get things going).

Eventually you may also wish to switch to an HTTP codebase URL, just so that you can run clients on a machine separate from your server's.

Ez answered 14/10, 2008 at 16:40 Comment(0)
L
0

It just works fine when I fixed the CLASSPATH variable before starting the rmi registry. I think the idea is that the RMI Registry will load your remote stubs and it should has access. That's was easy by putting my classes on the CLASSPATH before running the registry. So it is not related to any other reason such as JDK 7 or file:/ protocol.

Lavoisier answered 22/8, 2013 at 9:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.