How to organize RMI Client-Server architecture

Solution 1:

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.

Solution 2:

You are misunderstanding how Remote interfaces work. the client does not have the Bank, it only has a reference to a remote instance of a Bank. all the method calls made by the client on the Bank interface are actually turned into remote calls against the remote instance of the Bank (running in the server).

presumably, the security checking is done inside the Bank methods on every method call.