Undertow - IdentityManager

Version 2

    Undertow - Identity Manager

     

    This article describes the IdentityManager interface as used by Undertow.  The first point to remember is that this IdentityManager interface is an SPI to identify the methods required by the standard authentication mechanisms included with Undertow.  Where new authentication mechanisms are added especially with the integration with WildFly there is no requirement for them to make use of this IdentityManager at all.

     

    The IdentityManager interface includes three methods that are used for verification of incomming requests.

     

    public interface IdentityManager {
        Account verify(final Account account);
        Account verify(final String id, final Credential credential);
        Account verify(final Credential credential);
    }
    

     

    One key difference with the verification methods compared to previous approaches using JAAS is that the purpose of the verification methods is to verify the account and/or credential supplied, the outcome of this verification is not nescesarily an indication of an authentication acceptance or failure - the authentication mechanisms have the opportunity to further decide if the request will be accepted after using the IdentityManager.  As will be documented elsewhere the authentication framework within Undertow also includes a notification API/SPI that is used by authentication mechanisms to indicate the outcome of authentication attempts.

     

    The three verification methods are used as follows: -

     

    Account verify(final Account account);

    This method is used by authentication mechanisms that cache a previously successfull authentication, as an example where FORM authentication is used the result of the successful authentication is cached in the HttpSession also established - for subsequent invocations this cached value is used without prompting the user to fill in their username and password for each request.

     

    The verify method shown here is called each time the cached value is used, this method gives the underlying IdentityManager implementation an opportunity to check that the account is still valid e.g. has not subsequently been disabled.  This also gives an oportunity to reload the group membership information for the Account.  If verification is successful this method can return the Account instance it was passed, possibly after updating it's contents or it can return a completely new instance.

     

    Account verify(final String id, final Credential credential);

    This verification method is used by authentication mechanisms where we are supplied with an identifier for the calling user as well as a response to a challenge represented as a Credential, the mechanisms currently using this are: -

    • FORM Authentication
    • BASIC Authentication
    • DIGEST Authentication
    • Programatic Authentication (Servlet APIs)

     

    The 'Credential' interface is just a marker interface, in reality we have the following two representations of a Credential used with this method: -

     

    public final class PasswordCredential implements Credential {
    
        private final char[] password;
    
        public PasswordCredential(final char[] password) {
            this.password = password;
        }
    
        public char[] getPassword() {
            return password;
        }
    
    }
    

     

    This first representation of Credential is used by the authentication mechanisms that we receive a plain text password from the calling client, i.e. every mechanism listed except Digest.

     

    The IdentityManager implementation can take this and call getPassword to obtain the password supplied and verify it against it's internal store.  This approach means that the underlying IdentityManager implementation could store the password in a non-reversible form allowing it to take care of the verification.

     

    public interface DigestCredential extends Credential {
       DigestAlgorithm getAlgorithm();
       String getRealm();
       byte[] getSessionData();
    
    
    
       boolean verifyHA1(final byte[] ha1);
    }
    

     

    The DigestCredential is used where authentication is using HTTP Digest, due to the nature of the mechanism some additional information is needed and a slightly more complex verification process is required.

     

    Firstly the getAlgorithm method can be called by the IdentityManager to identify the algorithm used for hashing in the current exchange and also to identify if this is session based digest authentication i.e. is this the first request generating a session key?

     

    The IdentityManager can also call getRealm to obtain the name of the realm being authenticated against and if this is session based Digest it can call getSessionData to obtain the additional bytes needed to generate a H(A1) value.

     

    At the time for verification the IdentityManager should then call the verifyHA1 method and pass in the hex encoded hashed A1 value according to the DigestAlgorithm selected.  The Credential instance will have access to the underlying message received and will take this provided H(A1) to verify the challenge response.  If this method returns true the IdentityManager can assume it was a valid challenge response and reutrn the Account instance, if this method returns false the IdentityManager should return null.

     

    The reason for taking this approach is to minimise how much of the HTTP Digest mechanism leaks into the IdentityManager without placing a requirement on the IdentityManager to supply plain text passwords for account.  This approach also means that where the mechanism requires a cache of the H(A1) value it can obtain it from the Credential instance used.

     

    Account verify(final Credential credential);

    This final version of verify is used by authentication mechanisms where we only have a Credential and no identifier to match it to - the IdentityManager is then responsible for mapping it to the desired account as well.

     

    Currently this is only used with an X509CertificateCredential: -

     

    public final class X509CertificateCredential implements Credential {
      
        private final X509Certificate certificate;
      
        public X509CertificateCredential(final X509Certificate certificate) {
            this.certificate = certificate;
        }
      
        public X509Certificate getCertificate() {
            return certificate;
        }
      
    }
    

     

    However this will be updated for use with SPNEGO / Kerberos based authentication at a future point.

     

    Account

     

    The final interface that is of interest from the IdentityManager is the Account interface, an instance of which is returned from each of the verify methods if verification of the supplied parameters is successful.

     

    public interface Account {
        Principal getPrincipal();
        boolean isUserInRole(final String role);
    }
    

     

    Integrated within an application server environment the Account implementation is free to contain additional information, however the methods illustrated here show the bare minimum required to work with Undertow.