Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 5029435
Votes 0
Synopsis RMI needs to a protected internal rmiregistry
Category java:rmi
Reported Against 1.4.2
Release Fixed
State 6-Fix Understood, request for enhancement
Priority: 4-Low
Related Bugs
Submit Date 09-APR-2004
Description


A DESCRIPTION OF THE REQUEST :
An internal RMI Registry can be created using LocateRegistry.createRegistry(int).  The result is a registry that is writable by all client instances on the localhost.  It is possible for an application running locally to illegally modify the registry.


JUSTIFICATION :
In many cases, when a local registry is used, it should be protected from other applications tampering with its local registrations.

Consider:

Registry reg = LocateRegistry.createProtectedRegistry(2004)
reg.bind("serviceAye", new MyServiceA(2004);
reg.bind("serviceBee", new MyServiceB(2004);
reg.bind("serviceCee", new MyServiceC2004);

The above result exposes one  customer  port (2004) on which the registry and three services are additionally exposed on port 2004. (They extend UnicastRemoteObject which takes an integer port number in a constructor)

Clients may use (MyServiceB)Naming.lookup("//machine:2004/serviceBee") to retrieve the RMI  customer .

A developer will observe that, there is no remotely managed registry
there is no additional deployment installation only one port needs to be opened on a firewall.

Without a protected registry, it may be tampered with by local applications.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Refering to java.rmi.Registry, the functions bind, unbind and rebind must only allow explicit registration of objects by applications local to the VM that hosts its reference.  Remote clients that execute bind, unbind or rebind must receive a thrown AccessException.

A protected registry must be retrieved through a call to,

java.rmi.registry.LocateRegistry.createProtectedRegistry(int port)
java.rmi.registry.LocateRegistry.createProtectedRegistry(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf)

or possibly even better,

java.rmi.registry.LocateRegistry.createRegistry(int port, boolean protect)
java.rmi.registry.LocateRegistry.createRegistry(int port,RMIClientSocketFactory csf, RMIServerSocketFactory ssf, boolean protect)

---

Regarding the name parameter in the following methods,

Registry.unbind(String name)
Registry.rebind(String name, Remote)
Registry.bind(String name, Remote)

It may further be preferrable to have the name parameter accept unqualified references such as "MyService" instead of "//localhost:1234/MyService" as the localhost address is superfluous and the port number may be specified incorrectly if it differs from the port number provided to createRegistry(int).
ACTUAL -
Naming.unbind("//localhost/myservice") will unbind a service from the registry if its on the local machine.  The an internal registry created by LocateRegistry.createRegistry is not protected from local applications.

---------- BEGIN SOURCE ----------
the following two methods must be added to LocateRegistry:

public static Registry createProtectedRegistry(int port) throws RemoteException
{
return new ProtectedRegistry(port).getSuperRegistry();
}

public static Registry createProtectedRegistry(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException
{
return new ProtectedRegistry(port,csf,ssf).getSuperRegistry();
}

the following class must be created:

class ProtectedRegistry extends sun.rmi.registry.RegistryImpl
{
	public ProtectedRegistry(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException
	{
		super(port,csf,ssf);
	}

	public void bind(String name, Remote obj)
			throws RemoteException, AlreadyBoundException, AccessException
	{
		throw new AccessException("readonly");
	}
	public void unbind(String name)
			throws RemoteException, NotBoundException, AccessException
	{
		throw new AccessException("readonly");
	}
	public void rebind(String name, Remote obj)
			throws RemoteException, AccessException
	{
		throw new AccessException("readonly");
	}

	public Registry getSuperRegistry()
	{
		return new Registry(){
			public Remote lookup(String name)
					throws RemoteException, NotBoundException, AccessException
			{
				return pvtLookup(name);
			}
			public void bind(String name, Remote obj)
					throws RemoteException, AlreadyBoundException, AccessException
			{
				pvtBind(name,obj);
			}
			public void unbind(String name)
					throws RemoteException, NotBoundException, AccessException
			{
				pvtUnbind(name);
			}
			public void rebind(String name, Remote obj)
					throws RemoteException, AccessException
			{
				pvtRebind(name,obj);
			}
			public String[] list() throws RemoteException, AccessException
			{
				return pvtList();
			}
		};
	}

	private Remote pvtLookup(String name)
			throws RemoteException, NotBoundException, AccessException
	{
		return super.lookup(name);
	}

	private void pvtBind(String name, Remote obj)
			throws RemoteException, AlreadyBoundException, AccessException
	{
		super.bind(name, obj);
	}

	private void pvtUnbind(String name)
			throws RemoteException, NotBoundException, AccessException
	{
		super.unbind(name);
	}

	private void pvtRebind(String name, Remote obj)
			throws RemoteException, AccessException
	{
		super.rebind(name, obj);
	}

	private String[] pvtList() throws RemoteException, AccessException
	{
		return super.list();
	}
}

the test case would be the construction of a Client that tries to unbind, bind and rebind objects against the protected registry.

NOTES:
Both local and remote  customer  references can be bound to the registry by the application itself.  Remote clients may not register their objects directly to the registry, they have to pass them to an local application  customer  that registers it to the registry.
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
This is a feature request.  The source code listed above may be used.
The need for the source code above is to protect the local registry.
(Incident Review ID: 237524) 
======================================================================
Posted Date : 2007-01-10 19:48:19.0
Work Around
It would seem that this behavior could be accomplished with the current J2SE RMI API and implementation by passing an instance of a custom RMIServerSocketFactory implementation to LocateRegistry.createRegistry.

The registry implementation returned by LocateRegistry.createRegistry enforces remote access control on "mutating" registry operations (bind, unbind, and rebind) by determining if the "client host" (as indicated by an invocation of RemoteServer.getClientHost) resolves to an IP address of the local machine (specifically, one to which a socket can be bound on the local machine).  The RemoteServer.getClientHost method operates by invoking Socket.getInetAddress on the socket that is being used to communicate the remote call executing in the current thread.

An RMIServerSocketFactory implementation can control the value returned by RemoteServer.getClientHost-- for remote calls to remote objects exported with an instance of that factory class-- by creating server sockets that wrap the Socket objects returned from ServerSocket.accept() in an instance of a Socket class that forwards all invocations to the underlying socket *except* for getInetAddress.  getInetAddress could be implemented in various ways to ensure that it never returns an InetAddress that resolves to an IP address of the local machine (one approach would be for it to return null, at least when it would otherwise return a local address).

  xxxxx@xxxxx   2004-04-09
Evaluation
This RFE will be considered for a future release.  See "Workaround" section for a suggestion to accomplish the desired behavior with the current J2SE RMI API and implementation.

A comment about the "Description" of this RFE:

None of the methods on the java.rmi.Registry interface expect names with slashes, host names, addresses, or port numbers in them; they just expect the "pure" name of the binding (which can be an arbitrary string).  It is only the methods of the java.rmi.Naming class that expect URL-formatted strings representing binding names.  Note that use of the Naming class is entirely optional-- anything that can be done with Naming can also be done with an invocation of LocateRegistry.getRegistry and invocations on the returned Registry stub (and the latter approach is more powerful, because with it you can communicate with the registry using a custom RMIClientSocketFactory, you can use names that are not permitted in Naming's URL-formatted syntax, etc.).

  xxxxx@xxxxx   2004-04-09
A more general solution than the one proposed in the Description would be to allow users to supply their own implementation of the Registry interface.  In other words, we could add to LocateRegistry the following method:

    public static Registry createRegistry(
        int port,
        RMIClientSocketFactory csf,
        RMIServerSocketFactory ssf,
        Registry impl)
    throws RemoteException

We would probably also want to provide a default implementation, similar to sun.rmi.registry.RegistryImpl except that it would not extend RemoteServer.

The requested functionality could then be achieved trivially by subclassing RegistryImpl and overriding the mutator methods to throw UnsupportedOperationException.  Various solutions for creating the initial registry contents locally are obviously possible.
Posted Date : 2007-01-10 19:48:19.0

I agree with the above Evaluation note, that a more general solution like it proposed would be preferable to enhancing the existing API only to add one very specific additional registry access control policy.

[Along similar lines, the ability to export an arbitrary remote object with a fixed ObjID, and without participation in the distributed garbage collection protocols, would also seem very desirable (a tidbit from JSR-78)-- with that capability, any remote object could have the same "magic" that only the RMI registry can have through the current public APIs.]
Posted Date : 2007-01-12 19:20:18.0
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang