Tomcat access control exceptions (binding to RMI) with no Security Manager running (Ubuntu)

javapermissionstomcatubuntu-10.04

I'm encountering some strange access control exceptions from a Tomcat servlet (when it tries to bind to an RMI server). I'm running without a Security Manager, and this whole application worked fine previously on essentially the same setup.

It's a java.io.FilePermission access denied to the classes folder of the webapp I'm in. The error occurs when I'm rebinding my RMI stub to an RMI registry (which is after I've accessed some other classes in the same webapp, and after I've exported the stub and located the registry; did some log messages to prove this). Any help would be brilliant because I'm now dead in the water on this one…

Update: OK, made some progress (this update overwrites previous suppositions). It's to do with the codebase access by the RMI registry and probably some quirks of OpenJDK.

When I bind the server to the registry, it tries to access the relevant classes via what it thinks is the codebase. It appears that, using whatever under-the-covers RMI magic the registry uses to get the codebase location, it's somehow not getting the one in the JVM property and is trying to look in the webapp's classpath(??).

Reasoning(!): This used to work fine with a file URL for the codebase (and no Java security policy). I tested the RMI server setup outside of Tomcat (just as a POJO), and it worked with an HTTP URL but not a file one. The latter gives the same access permission errors as in Tomcat, but shows it trying to access this particular file location (unlike in Tomcat where it is trying to access a completely different location). I suspect this failure of file URLs might be down to differences between OpenJDK and the Sun JDK. (I was using the Sun one before; I just remembered.)

However, when I tried the working HTTP URL with the Tomcat setup (ensuring my Web server serving it was on a different port to Tomcat), it still fails as before trying to access the webapp's classpath area. I've confirmed in the servlet code that the java.rmi.server.codebase property is set properly (so it's getting through to the servlet code OK). Perhaps a bug in the OpenJDK rmiregistry (seems rather unlikely)?

Does this help anyone have some more thoughts? Is this better placed on StackOverflow (one could argue for it to be on either location I think)?

Using Tomcat 6.0.24 local environment, as created by the tomcat6-instance-create cmd on Ubuntu 10.04 x64 with OpenJDK 1.6.0_20. (All the Ubuntu 10.04 defaults.)

The exceptions trace is as below:

 simHAWSER.core.exceptions.HAWSER_RMI_ConfigurationException: Error setting up observer gateway server HAWSER_ObserverGateway
    at simHAWSER.core.internal.yawlInterface.HAWSER_ObserverGateway.announceEngineInitialised(HAWSER_ObserverGateway.java:1404)
    at org.yawlfoundation.yawl.engine.ObserverGatewayController$8.run(ObserverGatewayController.java:278)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)
Caused by: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: access to class loader denied
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:419)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:267)
    at sun.rmi.transport.Transport$1.run(Transport.java:177)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:273)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:251)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:377)
    at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
    at simHAWSER.core.internal.yawlInterface.HAWSER_ObserverGateway.announceEngineInitialised(HAWSER_ObserverGateway.java:1400)
    ... 4 more
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: access to class loader denied
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:409)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:267)
    at sun.rmi.transport.Transport$1.run(Transport.java:177)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
    ... 3 more
Caused by: java.lang.ClassNotFoundException: access to class loader denied
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:603)
    at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:646)
    at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:311)
    at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:255)
    at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1548)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1510)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1749)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1346)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
    ... 12 more
Caused by: java.security.AccessControlException: access denied (java.io.FilePermission /home/rigsby/Build/yawl/r1803/tomcat6/webapps/yawl/WEB-INF/classes/- read)
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:393)
    at java.security.AccessController.checkPermission(AccessController.java:553)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
    at sun.rmi.server.LoaderHandler$Loader.checkPermissions(LoaderHandler.java:1173)
    at sun.rmi.server.LoaderHandler$Loader.access$000(LoaderHandler.java:1127)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:569)
    ... 20 more

The originating simHAWSER class is my app (runs as part of the yawl webapp). If it's of any bearing, my code runs as a separate JAR in the webapp lib directory, and is called out to by the yawl servlet (which is deployed to the normal classes directory).

In semi-desperation, I tried to start Tomcat with a Security Manager (giving all permissions to this webapp), but this caused some weird 'null KeyStore name' exception when reading my catalina.policy file (I just copied the default one from here.) In any case, I know it worked (and should work) without security, so don't want to go on a wild goose chase in this direction 🙂

If anyone wants any more detail, let me know.

P.S. Wanted to add an RMI tag (or rmiregistry to match StackOverflow), but don't have the rep for it 🙁 If anyone wants to add that, then great.

Best Answer

OK, solved it. The problem was the use of OpenJDK as opposed to Sun Java. The OpenJDK rmiregistry implementation doesn't like file URLs (access exceptions) and, when trying to access the codebase property for a Tomcat webapp, it somehow isn't seeing it properly (presume something to do with the per-webapp class loaders used in Tomcat messing it up).

Switching to the Sun rmiregistry implementation (even when retaining use of OpenJDK for Tomcat) meant it worked properly. If I can't find any OpenJDK bug on this, I'll raise one and link to it here for completeness.

I suspect that the file URLs issue with the OpenJDK one is due to different default (no explicit java policy) security setups, and that I could get that to work using an explicit policy file...

Hope this helps others out because it was a real head-scratcher.