|
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
|
|
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
|