Configuring the Apache web server for Raven OAuth2

This page follows on from the first steps page and peeks behind the scenes a bit about how our example web server is configured. By doing so you will learn how to configure the Apache web server to require Raven authentication when visiting a site.

Prerequisites

This guide is written assuming you have completed the first steps guide, that you have had some experience with the Linux command line and have configured an Apache web server before.

In order to add Raven authentication to a website you will need to make sure that the mod_auth_openidc is Apache module is installed on your server. If you are running a Debian or Ubuntu server this is provided by the libapache2-mod-auth-openidc package which can be installed via apt-get. Other Linux distributions will require an alternative install command, such as yum install mod_auth_openidc.

In this guide we will make use of a pre-built Docker container based on Ubuntu.

Fetching and building the container image

We will be making use of Play with Docker as we did on the first steps page. If you haven't done so already make sure now that:

  1. You have created a Play with Docker instance.
  2. You have set the CLIENT_ID and CLIENT_SECRET environment variables to out OAuth2 client credentials.

Previously we made use of a pre-built container to demonstrate Raven integration. Now we will build our own.

Use the git command line tool to fetch the Raven documentation samples and move into the apache-oauth2 directory:

git clone https://gitlab.developers.cam.ac.uk/uis/devops/raven/doc-samples.git

cd doc-samples/apache-oauth2

Build a new container image called my-server:

docker build -t my-server .

Run the web-server just as you did on the first steps page except using your new image name:

docker run --rm -it -e CLIENT_ID -e CLIENT_SECRET -p 8000:80 my-server

Important

Make sure you have set the CLIENT_ID and CLIENT_SECRET environment variables.

Experiment with the container

Since you are now building the container yourself, you can experiment with changing how it is configured.

  1. Press Ctrl-C in the Play with Docker window to stop the web server.
  2. Click the editor button and navigate to /root/doc-samples/apache-oauth2/htdocs.
  3. Click on index.shtml to edit the code of the example web page.
  4. Change the word "Congratulations" to "Well done".
  5. The Play with Docker editor changes the permissions on files it edits so, back in the Play with Docker terminal window, use the following command to restore them:
    chmod -R oug+r htdocs/
    

Try re-building and re-running the web server:

docker build -t my-server .

docker run --rm -it -e CLIENT_ID -e CLIENT_SECRET -p 8000:80 my-server

If you visit the link next to the open port button, you should see that the message is different from the one you got when following the steps on the first steps page.

A tour of the container

Now you are familiar with how to modify the container configuration, you can experiment with the container setup to gain some familiarity with it. Don't worry if you've never used docker before. We'll now go on a tour of how the container works its magic.

Installing mod_auth_openidc

The Dockerfile describes the steps to set up the container. We start from a base Ubuntu install. We run a number of basic system configuration commands but the main commands which install and configure mod_auth_openidc are as follows:

apt-get install apache2 libapache2-mod-auth-openidc

a2enmod auth_openidc

Configuring mod_auth_openidc

The Apache web server supports serving multiple websites from the same server. Each website is usually configured with a <VirtualHost> section in the Apache configuration file.

The configuration for our protected site can be found within the sites/protected.conf file. The mod_auth_openidc module is configured using directives which start OIDC....

OpenID connect metadata URL

The OpenID Connect specification describes a way to auto-configure a number of the OAuth2 parameters for a particular authentication server. We can use the OIDCProviderMetadataURL directive to specify the appropriate metadata configuration URL for Raven:

# Raven OAuth2 is provided by Google. This URL provides metadata which
# auto-configures some OAuth2 parameters.
OIDCProviderMetadataURL \
    https://accounts.google.com/.well-known/openid-configuration

OAuth2 client credentials

The OIDCClientID and OIDCClientSecret directives let you specify the OAuth2 client credentials for your site. In our container we load them from the CLIENT_ID and CLIENT_SECRET environment variables but you can specify them directly in your configuration if you wish:

# OAuth2 client application.
OIDCClientID "some-client-id"
OIDCClientSecret "some-client-secret"

Redirect URI

When a website wants to cause a user to sign in, it redirects them to Raven. Raven, in turn, needs to know where to redirect the user back to after they have authenticated. This is a special URL on your site known as the "redirect URI".

It doesn't matter what you choose as a redirect URI as long as it doesn't conflict with any other URL on your website. A good choice is /.oidc/redirect.

Our example container allows the redirect URI to be customised with an environment variable but you can specify it directly in the configuration if you wish:

# Redirect URI claimed by mod_auth_openidc. This should not be any URL used by
# the site you're protecting. A good choice is usually something like
# "/.oidc/redirect".
OIDCRedirectURI "/.oidc/redirect"

It would be tiresome in the extreme if each time a visitor to your site navigated around it they were prompted for their Raven credentials. To prevent this mod_auth_openidc keeps a special value in a "session cookie" which a user's web browser presents to the web server on each visit to identify them. To make sure that this cookie can't be faked, it is encrypted with a secret value you configure in the web server.

This value should ideally be a long random string. The container generates a different passphrase each time it is run but in production you should use a fixed value and add it to the Apache configuration using the OIDCCryptoPassphrase directive:

# Crypto passphrase for session cookie. This is used to encrypt a session
# cookie which allows users to re-visit your site once signed in without
# having to present their Raven credentials again.
OIDCCryptoPassphrase "e3b0c44298fc1c149996fb92427ae41e4649b934ca495991b7852b855"

Info

The container uses a little bit of Unix command line trickery to generate the passphrase. Try it yourself in the Play with Docker terminal:

dd if=/dev/urandom of=/dev/stdout count=100 2>/dev/null | sha256sum - | cut -f1 -d ' '

In production, you should make use of whatever secure token generation system you currently use.

Token request parameters

The OAuth2 standard allows for websites to make special requests about sign ins. For example they could request that a user always be asked for their password even if they have signed in before. Raven OAuth2 uses the hd parameter to signal that a website only wants users with @cam.ac.uk email addresses. The parameters are set via the OIDCAuthRequestParams directive:

# OAuth2 token request parameters. Use "hd=cam.ac.uk" to request the Raven
# login box.
OIDCAuthRequestParams "hd=cam.ac.uk"

If you don't set the hd parameter you will get a generic Google login box. This may be what you want if you want offer sign in to both the public and Raven account holders.

OAuth2 scopes

In the OAuth2 protocol, "scope" refers to the set of things a server wants to be able to do on behalf of a user. To get the @cam.ac.uk email address for the user in you only need the "email" scope. To get other basic information on a user such as name and profile picture you need the "openid" and "profile" scopes. Generally it is best to specify all three. Do this via the OIDCScope directive:

# Scopes indicating the information we want back from Raven.
OIDCScope "openid email profile"

Remote user

Apache supports the concept of a "remote user" which some applications use to automatically create user accounts when a user signs in. If your application makes use of this feature, you can configure mod_auth_openidc to use the user's email address as their username via the OIDCRemoteUserClaim directive:

# Some sites look at the "remote user" setting in Apache to determine the
# username which should be used. Set this to the user's "@cam.ac.uk" email
# address.
OIDCRemoteUserClaim email

Tip

It is possible to perform some regular expression trickery with OIDCRemoteUserClaim to strip the domain-name part of the email address off. This is not recommended since, as described in the Raven "golden rules", it reduces your ability to allows users without CRSids to use your site.

Requiring sign in

Configuring mod_auth_openidc does not actually cause the website to be Raven enabled. You must explicitly specify locations within a site which require sign in. To protect the entire site you can use the following <Location> section which should be within the appropriate <VirtualHost> section:

# Protect entire site with Raven authentication.
<Location />
    # Use OIDC authentication - ESSENTIAL FOR RAVEN WORKFLOW
    AuthType openid-connect

    <RequireAll>
        # Require that authentication succeeded.
        Require valid-user

        # Require that the user be a Raven user.
        #
        # THIS CHECK IS REQUIRED TO STOP ANYONE WITH A PUBLIC GOOGLE ACCOUNT
        # FROM SIGNING IN TO YOUR SITE.
        Require claim "hd:cam.ac.uk"
    </RequireAll>
</Location>

Always check the hd claim

Great sites follow the Raven "golden rules". Although you can set the hd request parameter via OIDCAuthRequestParams, a clever user could modify the request in their browser and request sign in for any public Google account. Unless you check the hd claim in the response from Raven you are essentially letting anyone on the Web access your site.

Next steps

On this page you learned how to build and customise the example Apache container. You saw all the mod_auth_openidc configuration directives required to configure Raven sign in and you saw how to require sign in for an entire web site.

Remember to read the Raven golden rules when configuring your website.

The complete list of configuration directives for mod_auth_openidc is available if you want to find out more.


Last update: March 8, 2024