HttpServletRequest to authenticated Principal

Thoughts about going from HttpServletRequest objects to something we can feed to an AuthenticationHandler:

A poor man's diagram

HttpServletRequest

An HttpServletRequest addressed to the Logon Controller representing a request for authentication.

enters the

Logon Controller

Controller which examines the request and applies some logic.

Logon controller applies an

AuthenticationRequestBinder

Translates from an HttpServletRequest to an AuthenticationRequest.

/**
 * Interface for components that know how to extract from HttpServletRequest
 * whatever it is that constitutes actual arguments of the request for authentication.
 */
public interface AuthenticationRequestBinder {

    /**
     * Parse an HttpServletRequest and extract from it whatever it is that is necessary as input to the AuthenticationHandler
     * which will examine the request for authentication represented by the HttpServletRequest. Return an Object
     * encapsulating that extracted information.  Specific implementations will return specific objects which in turn specific
     * AuthenticationHandler implementations will expect and consume.
     * @returns an object representing the relevant information for the authentication request
     * @throws RuntimeException - indicates failure
     */
   Object authenticationRequestFromHttpServletRequest(HttpServletRequest httpServletRequest);

   /**
    * Returns true if authenticationRequestFromHttpServletRequest() will return an Object for the given
    * argument.  Returns false if this other method will throw a RuntimeException for the given argument.
    *
    * This method exists to allow a client of this class to efficiently determine whether it should use this
    * AuthenticationRequestBinder or whether doing so will only throw a costly exception.
    */
   boolean supports(HttpServletRequest httpServletRequest);

}

Once the Logon Controller has applied its AuthenticationRequestBinder, it has an AuthenticationRequest in hand (or the supports() method returned false and it knows that it has no way of getting an AuthenticationRequest or the other method threw an exception and getting an authentication request failed. These are failure instances in which Logon Controller which will have to "recover in a way that makes sense", which might mean re-painting the login screen.)

It then passes that AuthenticationRequest to an AuthenticationHandler (or it passes it more generally into the CAS engine, which will return a TicketGrantingTicket, a Cookie representation of which the Logon Controller will then store back into the user's browser. Down inside the CAS service implementation is where the AuthenticationHandler lives. The purpose of this page is to explore the path of the AuthenticationRequest more than to nail down exactly the Logon Controller implementation).

So the AuthenticationRequest is an argument to the AuthenticationHandler:

AuthenticationHandler

An AuthenticationHandler examines an AuthenticationRequest and returns either an AuthenticationResult which indicates the authenticated Principal (and additional information about the successful authentication) or an AuthenticationResult which indicates an authentication failure (and additional information about the nature of the failure).

Our AuthenticationRequest has been transformed into an AuthenticationResult which CAS stores in the data associated with a GrantingTicket that it issues on the basis of this authentication. Out comes the GrantingTicket back to the LogonController, which attempts to store a String representation of it (really key to find it again server-side) into the end user's web browser. Also uses the GrantingTicket to get a ST for the desired Service, and then sends user along her way.

Implementation notes

AuthenticationRequest, marker interfaces, and POJOs

I use the term AuthenticationRequest here in the interest of ubiquitous language and calling things what they are. I continue to prefer at an implementation level that we let these be just plain old Objects and not require that they implement a marker interface because doing so will allow a particular AuthenticationRequestBinder and AuthenticationHandler pair to agree to use any arbitrary Object one has lying around that meets the need and not have to wrap it with a CAS-specific AuthenticationHandler interface that adds no methods. My own preference. -Andrew Petro

Multiple AuthenticationRequestBinders

In fact one might have several different kinds of AuthenticationRequest for which there are mapped AuthenticationHandlers. I would want to implement this as a special AuthenticationRequestBinder implementation which knows how to delegate to other AuthenticationRequestBinders, rather than introduce an AuthenticationRequestBinderManager. Again, my own preference. -Andrew Petro