Notice

The examples and use cases described here are intended to show the different ways SURF Research Access Management can be used and connected to application. These examples and use cases are not always validated by SURF.

SURF Research Access management is built on standards like SAML and OpenID Connect to authenticate and authorise users to applications. However, when applications can not be configured to support either of these protocols, a last resort solution is available in the form of a Reverse Proxy if the application can be configured to accept authentication and/or authorisation via HTTP request headers or the REMOTE_USER environment variable.

HTTP Request headers

HTTP Request headers are a part of the data that (web) clients send to a web-application when creating a request. Normally it would be unwise to use, let alone trust these headers as anyone who is a little technically inclined can inject these headers in every request and thus could impersonate every user on the platform. Thus, using HTTP Request headers should only be used when received from a trusted source.

REMOTE_USER environment

When a (web) application does not support accepting authentication and authorisation information from the request headers, it sometimes can be configured to acceptexternal authentication using the REMOTE_USER environment variable. The environment is a part of the context in which the web application runs and can be controlled by the server that serves that web application. It is, again, imperative that this environment is trusted and the variables used can only be set by a trusted party.

Reverse Proxy

Both solutions mentioned above require a trusted system, which is where the reverse proxy comes in. The reverse proxy is a web server that, on one hand, is connected to the external network which receives non-trusted user requests and which is capable of authenticating the user using SAML or OpenID Connect (OIDC) using plugins or modules. One example of such a webserver is Apache. Apache can be configured to require a successful OIDC-login before certain resources (endpoints) on the server are accessible to the end-user.

When the Apache webserver is running as a stand-alone server, it can manipulate the environment of the application and inject information originating from the OIDC or SAML authentication, for example by inserting the username of the authenticated user into the REMOTE_USER variable. The application, in turn, can make appropriate authorisation decisions based on the value(s) in the REMOTE_USER environments variable(s).

The (Apache) webserver can also forward external requests to a back-end application server and return the response to the client as if it were server from the server itself. This is called a reverse proxy. In reverse proxy mode, the webserver can inject extra information in the back-end request in the form of HTTP request headers. If we make sure the backend server can only be reached by the reverse proxy, we can safely trust the information in the HTTP request headers to authenticate and authorise the user that is requesting the application.

Security

I should be clear from the above that it is important that the secured resource is only accessible from the reverse proxy and that the reverse proxy correctly takes care of protecting (all) endpoints that fall under the reverse proxy configuration. Also, accepting headers that can be manipulated by the client is dangerous so the configuration should explicitly unset any incoming header before assigning the required values.

Apache OIDC module mod_auth_openidc 

This section gives an example setup for the Apache webserver using the mod_auth_openidc module.  This module can be downloaded from https://github.com/zmartzone/mod_auth_openidc/ but is also available by default on all major Linux distributions.

A generic VirtualHost configuration using this module might look something like this:

Apache mod_auth_openidc reverse proxy configuration example
LoadModule auth_openidc_module /usr/lib/apache2/modules/mod_auth_openidc.so
<VirtualHost *:80>
        ServerName mysite.example.edu
        DocumentRoot /var/www/html

        OIDCProviderMetadataURL https://proxy.sram.eduteams.org/.well-known/openid-configuration
        OIDCClientID oidc_client_id
        OIDCClientSecret oidc_client_secret
        OIDCResponseType "code"
        OIDCResponseMode "query"
        OIDCScope "openid profile"

        OIDCRedirectURI http://mysite.example.edu/redirect_uri
        OIDCCryptoPassphrase random_passphrase

        # Enable Reverse Proxy
        ProxyRequests On
        ProxyPreserveHost on

        # Authentication Header
        RequestHeader unset X-Authenticated-User
        RequestHeader unset X-Authenticated-Name
        RequestHeader set X-Authenticated-User expr=%{ENV:OIDC_CLAIM_sub}
        RequestHeader set X-Authenticated-Name expr=%{ENV:OIDC_CLAIM_sub}

        <Location />
            AuthType openid-connect
            Require valid-user
            ProxyPassMatch http://172.22.11.1:8000/
            ProxyPassReverse http://172.22.11.1:8000/
        </Location>
</VirtualHost>

An line by line explanation follows:

  • Line 1: Loads the moduel for OIDC authentication
  • Lines 2-4: Sets up a virtual host for the site mysite.example.edu 
  • Lines 6-14: Set up OIDC authentication.  The different settings may differ for different OIDC OPs, and should be provided by your OP
  • Lines 16-18: Enable the reverse proxy; further configuration is done below
  • Lines 20-24: First explicitly unset the authentication headers the web server receives from the user's browser, and then fill them with values provided by the OIDC authentication module.  Note that the can use any header names here, depending on what you application accepts.  These headers will be sent to the backend application configrues in lines 29-30
  • Lines 27-28: Force OIDC authentication for all URLs (everything under /).
  • Lines 29-30: Configure the proxy mapping: pass all URLs to the application running on http://172.22.11.1:8000/

Note that this is merely an example.  To use this in production, you should make sure that the OIDC connection (to SRAM or another OP) uis set up correctly, and you should make sure that HTTPS is setup correctly for your web server (this is not shown in the example above)

Apache SAML module mod_auth_mellon

This section contain a similar example using the mod_auth_mellon  module, which provides SAML2-based authentication.  Note that the mod_auth_mellon module requires a bit more configuration, but that the structure of the configuration is similar to the OIDC case: set up the cirtual host, set up the authentication, fill the varaibles from the authenticaiotn date, set up the reverse proxy.

https://github.com/latchset/mod_auth_mellon

Apache mod_auth_mellon reverse proxy example configuration
LoadModule auth_mellon_module /usr/lib64/httpd/modules/mod_auth_mellon.so

<VirtualHost *:80>
        ServerName mysite.example.edu
        DocumentRoot /var/www/html

        MellonCacheSize 100
        MellonLockFile "/var/run/mod_auth_mellon.lock"
        MellonPostTTL 900
        MellonPostSize 1048576
        MellonPostCount 100
        MellonDiagnosticsFile logs/mellon_diagnostics
        MellonDiagnosticsEnable Off

        # Enable Reverse Proxy
        ProxyRequests On
        ProxyPreserveHost on

        # Authentication Header
        RequestHeader unset X-Authenticated-User
        RequestHeader unset X-Authenticated-Name
        RequestHeader set X-Authenticated-User %{MELLON_user}e env=MELLON_user
        RequestHeader set X-Authenticated-Name %{MELLON_username}e env=MELLON_username

        <Location />
            AuthType Mellon
            Require valid-user

            MellonEnable "auth"
            MellonVariable "cookie"
            MellonCookiePath /
            MellonUser "urn:oid:1.3.6.1.4.1.5923.1.1.1.6"
            MellonSessionDump Off
            MellonSamlResponseDump Off
            MellonEndpointPath "/mellon"
            MellonDefaultLoginPath "/"
            MellonSessionLength 86400

            MellonIdPMetadataFile /etc/httpd/mellon/idp-metadata.xml

            ProxyPassMatch http://172.22.11.1:8000/
            ProxyPassReverse http://172.22.11.1:8000/
        </Location>
</VirtualHost>