Apache user authentication multiplexing

From RavenWiki
Jump to navigationJump to search

There are occasions when it would be useful to be able to use two different authentcation mechanisms for the same Web site, for instance to allow a site with some non-Cambridge users still to use Raven for its Cambridge users. The following snippet of apache.conf suggests a (fairly hairy) way to accomplish this using Apache 2.0.40 or later. Unauthenticated visitors to a URL in the protected space get an error page (the "401" ErrorDocument) offering them a choice of authentication mechanisms. When one of them succeeds, a cookie is set recording which one it was, and all further authentication happens transparently.

In this example, the DocumentRoot is /var/www, and the protected area is /var/www/protected. The example authentication methods are Raven and HTTP Basic authentication. It should be possible to transplant the whole thing into .htaccess if you really want to.

<Directory "/var/www/protected">
        AACookieKey "Some random string"
        # Make a 'cancel' from ucam_webauth go to the right error document
        AACancelMsg "<a href='/protected/_ucam_webauth/_bounce'>Raven</a><a href='/protected/_basic/_bounce'>Basic</a>"

        RewriteEngine on
        RewriteBase /protected

        RewriteCond %{HTTP:Cookie} (^|;\s*)bounceurl=/([^;]*)($|;)
        RewriteRule ^_(ucam_webauth|basic)/_bounce      _$1/%2

        # For magic URIs, if we know who the user is, then redirect either
        # internally or externally to the real version.  In the former case,
        # remember who the user was.
        RewriteCond %{REMOTE_USER} !=""
        RewriteCond %{ENV:REDIRECT_STATUS} !=""
        RewriteRule ^_(ucam_webauth|basic)/(.*)$ $2 [L,E=IU:%{REMOTE_USER}]
        RewriteCond %{REMOTE_USER}      !=""
        RewriteRule ^_(ucam_webauth|basic)/(.*)$ $2 [L,R,CO=authtype:$1:%{SERVER_NAME}]
        RewriteRule ^_(ucam_webauth|basic)/(.*)$ -      [L]

        # For non-magic URIs, if we already know who the user is, let them
        # through.
        RewriteCond %{ENV:REDIRECT_IU}  !=""
        RewriteRule ^(.*)$ -    [L,E=REMOTE_USER:%{ENV:REDIRECT_IU}]

        # If we don't yet know who the user is, but it looks as if they've
        # logged in, pass the request on to the correct authenticator.
        RewriteCond %{HTTP:Cookie} (^|;\s*)authtype=(ucam_webauth|basic)($|;)
        RewriteRule ^(.*)$ _%2/$1       [L]

        # Otherwise, generate a "401" response, recording the URL they first
        # thought of in a cookie, and let them choose how to authenticate.
        RewriteRule ^(.*)$ _authfail    [L,CO=bounceurl:/$1:%{SERVER_NAME}]
        Redirect 401 /protected/_authfail

        # If this ErrorDocument were dynamic, it could arrange to refer to
        # protected/_ucam_webauth/$1, and we wouldn't need the bounceurl
        # cookie.
        ErrorDocument 401 "<a href='/protected/_ucam_webauth/_bounce'>Raven</a><a href='/protected/_basic/_bounce'>Basic</a>"

</Directory>

# The _ucam_webauth and _basic directories must exist, but they can be
# empty.  "Require" lines can obviously be changed to be more useful.
<Directory "/var/www/protected/_ucam_webauth">
        AuthType Ucam-WebAuth
        Require valid-user
</Directory>
<Directory "/var/www/protected/_basic">
        AuthType basic
        AuthName "Test thingy"
        AuthUserFile "htpasswd"
        Require valid-user
</Directory>