You need two remote object classes.
The first one is obtained via Naming.lookup()
; it is a singleton; and it contains a login()
method.
This method returns the second remote object, which is not a singleton, not registered in the Registry, and is created anew for every return value. This object contains all the banking methods and also a logout()
method, which unexports it; it probably also implements the Unreferenced
interface so it can detect a dead client, and unexport itself. Because it exists once per client, it can hold client state, and because it can only be obtained by a successful login step it solves your security problem.
public interface Login extends Remote
{
Session login(String username, char[] password /* or whatever */)
throws LoginException, RemoteException;
}
public interface Session extends Remote
{
void logout() throws RemoteException;
void deposit(...) throws RemoteException;
void withdraw(...) throws RemoteException;
}
public class LoginImpl extends UnicastRemoteObject implements Login
{
public Session login(String username, char[] password)
throws LoginException, RemoteException
{
// username/password check; if it fails throw a LoginException
return new SessionImpl(username); // or whatever
}
}
public class SessionImpl extends UnicastRemoteObject implements Session, Unreferenced
{
public void logout() throws RemoteException
{
unexportObject(this, true);
}
public void unreferenced()
{
unexportObject(this, true); // needs to be in a try/catch block of course
}
// etc
}
I described this as the Remote Session pattern in my book in 2001.
Of course you also need transport layer security: see javax.rmi.ssl.