/ system-administration

Transparent, Application-Agnostic SSO using Apache mod_auth_form

Context

I use several internal-only domains intended for system monitoring, Node process management, and log visualization, among others. The domains themselves are publicly accessible, with handy domains like *.kevinlin.info or *.internal.kevinlin.info, but are secured using HTTP basic authentication.

Basic authentication is convenient and relatively painless to configure (can be declared explicitly in an .htaccess file in the DocumentRoot or as a configuration directive in httpd.conf), but:

  1. It's primitive.
  2. It's insecure (credentials are sent over as a mere base64-encoded hash as an HTTP request header). I hesitate to type credentials into any site that isn't SSL-secured.
  3. It's generally unappealing from a user experience standpoint; it's a simple popup dialog box with minimal opportunity for customization or branding.

SSO

Single sign-on is an authentication scheme whereby a user authenticates against a central authentication server, which then requests for the user to store a short-lived session cookie on the client (browser). Subsequent requests by the client to domains within the cookie's scope supply the value of this cookie in their HTTP headers, which the server validates on every request to ensure that the user is authorized.

Why is this convenient?

  1. Authorization can be shared across domains. Supply credentials at a single point, and authenticate against any service within the scope of the cookie's domain (in my case, any domain matching the pattern *.kevinlin.info).
  2. There is no longer a need to re-enter passwords. Browsers will generally cache the basic authentication credentials locally, which are automatically sent in the Authorization header of every outgoing request to that domain in that session (i.e. while the browser is open). However, if you close the browser and visit the domain again, you'll be prompted to re-enter your password. SSO eliminates this process by setting a constant expiry time on every distributed session cookie, so you only need to authenticate once every SessionMaxAge seconds.
  3. Flexibility to extend authentication. Validate against a custom datastore rather than /etc/apache2/.htpasswd? Sure; just implement application logic to do that. 2FA? Sure; just add additional steps between the initial authentication request and Apache's mod_auth_form handler.
  4. Nicer UI. The authentication layer is just another web application; it can be extended and branded freely.

Fortunately, Apache's mod_auth_form supplies all of the server-side logic for distributing and validating session cookies. The only task at hand is to implement a frontend that calls into Apache's APIs to request session cookies appropriately.

mod_auth_form

mod_auth_form is an Apache module that supplies handler endpoints for validating a user against those in an AuthUserFile, e.g. /etc/apache2/.htpasswd. In this sense, the authorization mechanism itself is not much different than that of HTTP basic authentication, but successful authorizations return a response with a Set-Cookie header whose cookie value is recognized by Apache on subsequent incoming requests as authorization tokens.

The greatest aspect of mod_auth_form is that it sits completely transparently between the client and underlying application. There is thus zero integration overhead associated with auth-walling applications, and it is entirely application and stack agnostic. All logic related to authentication resides in the virtual host configuration for the application, and authentication requests are directed to a dedicated service.

Let's consider the following architecture diagram:

Authentication architecture diagram

Cookie-based session authentication.

My Kibana dashboard lives at logs.internal.kevinlin.info and my authentication frontend lives at auth.kevinlin.info. A typical SSO flow would look something like this:

  1. Client issues a GET to logs.internal.kevinlin.info, with no session cookies.
  2. Apache tries to validate the session cookie, but there is none. The user is not authenticated; issue a 302 redirect to auth.kevinlin.info.
  3. Client supplies authentication credentials to the frontend at auth.kevinlin.info, which submits an AJAX request to mod_auth_form's auth handler form-login-handler.
  4. Apache validates the credentials using a mechanism of choice (e.g. an AuthUserFile), creates a session cookie, encrypts it, and sends it to the client using a Set-Cookie header.
  5. The client (browser) respects the incoming cookie and will include it as a header in all subsequent requests to the cookie's domain scope.
  6. Another attempt to access logs.internal.kevinlin.info is made, with a valid session cookie. Apache validates the session cookie and continues to service the request as normal.

Details on what the Apache configuration looks like can be found in the repository's README.

apache-auth

apache-auth is an Express/React frontend application for interfacing with the handlers provided by mod_auth_form. In practice, it is the visible authentication service that exists on the authentication domain (in my case, auth.kevinlin.info). Its only functionality is to dispatch requests for accepting and destroying session cookies created by Apache.

apache-auth demo

It looks suspiciously like OneLogin

Together, apache-auth and mod_auth_form provide a dead-simple implementation of SSO with zero impact to application logic under a secured domain. Please visit the repository for more information.