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:
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
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>