Documentation

Server 3.x

SAML (mod_auth_mellon)#

Below we assume you use vpn.example, but modify this domain to your own domain name!

This document describes how to use/configure mod_auth_mellon.

Installation#

Fedora / Enterprise Linux#

First install mod_auth_mellon:

$ sudo dnf -y install mod_auth_mellon

Debian / Ubuntu#

$ sudo apt -y install libapache2-mod-auth-mellon

In the examples below you will need to replace /etc/httpd with /etc/apache2. To restart Apache, you need to use apache2 as the service, and not httpd.

Configuration#

Generate an SP signing key:

$ openssl req \
    -nodes \
    -subj "/CN=SAML SP" \
    -x509 \
    -sha256 \
    -newkey rsa:3072 \
    -keyout "sp.key" \
    -out "sp.crt" \
    -days 3650

Copy the files:

$ sudo mkdir /etc/httpd/saml
$ sudo cp sp.crt sp.key /etc/httpd/saml

Obtain the IdP metadata from the IdP, for example if your IdPs metadata URL is https://idp.example.org/saml/metadata, use this:

$ curl -o idp.example.org.xml https://idp.example.org/saml/metadata

Now copy the metadata to `/etc/httpd/saml` as well:

```bash
$ sudo cp idp.example.org.xml /etc/httpd/saml

Modify the /etc/httpd/conf.d/vpn.example.conf file, and add the contents as shown here inside the Apache configuration file in the right section.

Restart the web server:

$ sudo systemctl restart httpd

Now when you visit https://vpn.example/vpn-user-portal/ you should be redirected to the IdP. If this works, you probably need to register your SP at your IdP. You can use the following URL as the metadata URL: https://vpn.example/saml/metadata.


You also need to modify the `vpn-user-portal` configuration to specify the 
attribute that should be used to identify the users.

Edit `/etc/vpn-user-portal/config.php` and set:

```php
'authModule' => 'MellonAuthModule',

You MUST set the userIdAttribute value under the MellonAuthModule section.

If you also want to use authorization based on an attribute, e.g. eduPersonEntitlement or eduPersonAffiliation you can set the permissionAttributeList as well.

Examples#

Using uid:

'MellonAuthModule' => [
    // uid
    'userIdAttribute' => 'MELLON_urn:oid:0_9_2342_19200300_100_1_1',
    // eduPersonAffiliation
    'permissionAttributeList' => ['MELLON_urn:oid:1_3_6_1_4_1_5923_1_1_1_1']
],

Using Pairwise Subject Identifier:

'MellonAuthModule' => [
    'userIdAttribute' => 'MELLON_urn:oasis:names:tc:SAML:attribute:pairwise-id',
    // eduPersonEntitlement
    'permissionAttributeList' => ['MELLON_urn:oid:1_3_6_1_4_1_5923_1_1_1_7'],
],

If you want to use eduPersonTargetedId, which is not really recommended, use pairwise-id instead, you can configure it like this:

'MellonAuthModule' => [
    // eduPersonTargetedId
    'userIdAttribute' => 'MELLON_urn:oid:1_3_6_1_4_1_5923_1_1_1_10',
    'nameIdSerialization' => true,
    'spEntityId' => 'https://vpn.example/saml/metadata',
],

This will serialize the XML node to a string using the IdP and SP entity ID together with the eduPersonTargetedId value. If you are using the “Name ID”, very much not recommended, you can set userIdAttribute to MELLON_NAME_ID.

Apache#

Fedora / Enterprise Linux#

<VirtualHost *:443>

    ...

    <Location />
        MellonEnable "info"
        MellonSecureCookie On
        MellonIdP "IDP"
        MellonMergeEnvVars On
        # Override the SP's entityID if needed, by default it is 
        # https://vpn.example/saml/metadata
        #MellonSPentityId https://vpn.example/saml
        MellonSPPrivateKeyFile /etc/httpd/saml/sp.key
        MellonSPCertFile /etc/httpd/saml/sp.crt
        MellonSignatureMethod rsa-sha256
        MellonEndpointPath /saml
        MellonIdPMetadataFile /etc/httpd/saml/idp.example.org.xml
        # When using a discovery service, use these two lines below 
        #MellonIdPMetadataFile /path/to/metadata.xml
        #MellonDiscoveryUrl "https://disco.example.org/"
    </Location>

    <Location /vpn-user-portal>
        MellonEnable "auth"
    </Location>

    # do not restrict API Endpoint as used by VPN clients
    <Location /vpn-user-portal/api>
        MellonEnable "off"
    </Location>

    # do not secure OAuth Token Endpoint as used by VPN clients
    <Location /vpn-user-portal/oauth/token>
        MellonEnable "off"
    </Location>

    # If you run separete node(s) you MUST allow access to "node-api.php" 
    # without protecting it with Mellon
    #<Location /vpn-user-portal/node-api.php>
    #    MellonEnable "off"
    #</Location>

    ...

</VirtualHost>

Debian / Ubuntu#

<VirtualHost *:443>

    ...

    <Location />
        MellonEnable "info"
        MellonSecureCookie On
        MellonIdP "IDP"
        MellonMergeEnvVars On
        # Override the SP's entityID if needed, by default it is 
        # https://vpn.example/saml/metadata
        #MellonSPentityId https://vpn.example/saml
        MellonSPPrivateKeyFile /etc/apache2/saml/sp.key
        MellonSPCertFile /etc/apache2/saml/sp.crt
        MellonSignatureMethod rsa-sha256
        MellonEndpointPath /saml
        MellonIdPMetadataFile /etc/apache2/saml/idp.example.org.xml
        # When using a discovery service, use these two lines below 
        #MellonIdPMetadataFile /path/to/metadata.xml
        #MellonDiscoveryUrl "https://disco.example.org/"
    </Location>

    <Location /vpn-user-portal>
        MellonEnable "auth"
    </Location>

    # do not restrict API Endpoint as used by VPN clients
    <Location /vpn-user-portal/api>
        MellonEnable "off"
    </Location>

    # do not secure OAuth Token Endpoint as used by VPN clients
    <Location /vpn-user-portal/oauth/token>
        MellonEnable "off"
    </Location>

    # If you run separete node(s) you MUST allow access to "node-api.php" 
    # without protecting it with Mellon
    #<Location /vpn-user-portal/node-api.php>
    #    MellonEnable "off"
    #</Location>

    ...

</VirtualHost>