A basic implementation of basic access authentication using JASPIC

Basic access authentication is a crude mechanism to authenticate that's part of the HTTP standard. It allows both an agent to send username/password credentials and a server to request the agent to authenticate itself. This happens in a simple but standardized way.

The mechanism can be easily implemented using Java EE's JASPIC and a sprinkle of utility code from the experimental OmniSecurity project (which is currently being discussed as one of the possible options to simplify security in Java EE 8).

A basic implementation looks as follows:

public class BasicAuthModule extends HttpServerAuthModule {
    
    @Override
    public AuthStatus validateHttpRequest(HttpServletRequest request, HttpServletResponse response, HttpMsgContext httpMsgContext) throws AuthException {
        
        String[] credentials = getCredentials(request);
        if (!isEmpty(credentials)) {
            
            UsernamePasswordIdentityStore identityStore = getReferenceOrNull(UsernamePasswordIdentityStore.class);
            if (identityStore != null) {
                if (identityStore.authenticate(credentials[0], credentials[1])) {
                    return httpMsgContext.notifyContainerAboutLogin(
                        identityStore.getUserName(), 
                        identityStore.getApplicationRoles()
                    );
                }                
            }            
        }
        
        if (httpMsgContext.isProtected()) {
            response.setHeader("WWW-Authenticate", "Basic realm=\"test realm:\"");
            return httpMsgContext.responseUnAuthorized();
        }
        
        return httpMsgContext.doNothing();
    }
    
    private String[] getCredentials(HttpServletRequest request) {
        
        String authorizationHeader = request.getHeader("Authorization");
        if (!isEmpty(authorizationHeader) && authorizationHeader.startsWith("Basic ") ) {
            return new String(parseBase64Binary(authorizationHeader.substring(6))).split(":");
        }
        
        return null;
    }
}
Full code in the OmniSecurity repo

Using injection, the example can be simplified a little and will then look as follows:

public class BasicAuthModule extends HttpServerAuthModule {

    @Inject
    private UsernamePasswordIdentityStore identityStore;
    
    @Override
    public AuthStatus validateHttpRequest(HttpServletRequest request, HttpServletResponse response, HttpMsgContext httpMsgContext) throws AuthException {
        
        String[] credentials = getCredentials(request);
        if (!isEmpty(credentials) && identityStore.authenticate(credentials[0], credentials[1])) {
            return httpMsgContext.notifyContainerAboutLogin(
                identityStore.getUserName(),
                identityStore.getApplicationRoles()
            );
        }
        
        if (httpMsgContext.isProtected()) {
            response.setHeader("WWW-Authenticate", "Basic realm=\"test realm:\"");
            return httpMsgContext.responseUnAuthorized();
        }
        
        return httpMsgContext.doNothing();
    }
    
    private String[] getCredentials(HttpServletRequest request) {
        
        String authorizationHeader = request.getHeader("Authorization");
        if (!isEmpty(authorizationHeader) && authorizationHeader.startsWith("Basic ") ) {
            return new String(parseBase64Binary(authorizationHeader.substring(6))).split(":");
        }
        
        return null;
    }
}

Note that the JASPIC auth module as shown here is responsible for implementing the client/server interaction details. Validating the credentials (username/password here) and obtaining the username and roles is delegated to an identity store (which can e.g. be database or LDAP based).

Arjan Tijms

Comments

Popular posts from this blog

Implementing container authentication in Java EE with JASPIC

Jakarta EE Survey 2022

Counting the rows returned from a JPA query