Shibboleth is one of many SSO providers that are available in the open source identity ecosystem. Shibboleth implements SAML (also OIDC) providing IDP (Shibboleth Identity Provider 5) and SP (Shibboleth Service Provider 3) products while also providing a Discovery Service and Metadata Aggregator tools to supplement the SAML ecosystem.

In SAML the term IDP refers to the Identity Provider, which aims to protect applications or services with authentication to verify the users identity before giving them access. Meanwhile the SP refers to the Service Provider naturally referring to the service or application a user is attempting to access.

shibboleth logo

Shibboleth has an interesting history of development from the days when SAML was first being developed to now being managed by the Shibboleth Consortium. The name also has equally interesting origins in Biblical Hebrew, the start of the word sh was incorrectly pronounced sibboleth, people misprouncing the word led them to be declared as outsiders to the group. In this context Shibboleth seems an apt name for an SSO protecting an applications and services.

This article will focus on configuring Shibboleth IDP and Nextcloud to enable SAML SSO functionality. Over the course of this article we will use other tools such as Apache2 as a reverse proxy and use Docker to host Nextcloud.

Shibboleth IDP

The Shibboleth IDP is provided as a tar or zip containing scripts to install Shibboleth. The installation script provides a step by step CLI process to installation the application but we will use a properties file to conduct an unattended installation. The file contains the hostname, the installation directory shibboleth will install its components, an entityID is an identitifier which is also found in the metadata XML usually pointing to a URL where the metadata is located.

idp.target.dir=/opt/shibboleth-idp
idp.host.name=example.com
idp.entityID=http://auth.example.com/idp/shibboleth

The install script should ingest the properties.txt file with all the defined variables. The installation will copy the example and base configurations, the generated certficates for signing and encrypting SAML requests and a WAR file.

/path/to/shibboleth/bin/./install.sh --propertyFile /opt/properties.txt

The script automatically builds a idp.war file in the war folder in /opt/shibboleth-idp/. Shibboleth allows you to customise the login page with a logo, background, organisation name etc. The file messages/messages.properties can be configured with the location of a custom css, where a background splash image can be declared and the location of the logo. The css and images are located in /opt/shibboleth-idp/edit-webapp and the webpages can be modified in /opt/shibboleth-idp/views.

idp.css = /css/custom.css
idp.logo = /images/logo.png

Executing the script /opt/shibboleth-idp/bin/./build.sh will rebuild the war file. This can be copied from /opt/shibboleth-idp/war directory to /path/to/tomcat/webapps directory in tomcat and execute the following script to start Tomcat.

/path/to/tomcat/bin/./startup.sh

As this is a new installation we will need to generate the SAML IDP metadata. This metadata can contain a variety of different components from Entity IDs to SSO and SLO endpoints to certificates for signing and encrypting SAML requests and responses between IDP and SP.

Shibboleth provides a plugin called Metadatagen. This plugin once installed provides a script to generate the XML file containing the metadata for the SAML IDP. The plugin can be installed with the following command:

/opt/shibboleth-idp/bin/./plugin.sh -i https://shibboleth.net/downloads/identity-provider/plugins/metadatagen/2.0.0/idp-plugin-metadatagen-dist-2.0.0.tar.gz

The following command is an example to generate the SAML IDP metadata for our example. The command includes flags to add certs to sign and encrypt as well as NameID format for user attributes. In addition you can add the following flags --logout <insert_url> and --sso <insert_url> for Single Sign-On (SSO) and Single Log-out (SLO) URL endpoints. For system administrators you can also add the flag --contact-admin, --contact-support and --contact-tech to provide contact details for anyone having issues configuring their SP to work with your deployment of Shibboleth IDP.

/opt/shibboleth-idp/bin/./metadatagen.sh
   --entityID https://auth.example.com/idp/shibboleth
   --signing /opt/shibboleth-idp/credentials/idp-signing.crt
   --encryption /opt/shibboleth-idp/credentials/idp-encryption.crt
   --nameid-format urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
   --nameid-format urn:oasis:names:tc:SAML:1.1:nameid-format:givenName
   --nameid-format urn:oasis:names:tc:SAML:1.1:nameid-format:sn
   --file /opt/shibboleth-idp/metadata/idp-metadata-test.xml

After generating the metadata make sure to uncomment the following line in /opt/shibboleth-idp/conf/idp.properties . Once Shibboleth has restarted the metadata can be found at the following URL for all SPs to access: https://auth.example.com/idp/shibboleth.

idp.entityID.metadataFile=%{idp.home}/metadata/idp-metadata.xml

Shibboleth provides a modular framework for enabling features such as Terms and Conditions, MFA etc. These can be enable with the /opt/shibboleth-idp/bin/./module.sh script. When enabling these modules new configuration files are also created to configure the modules which are not activated by default.

/opt/shibboleth-idp/bin/./module.sh --enable idp.authn.MFA
#  ------------ OUTPUT ------------ #
INFO  - Including auto-located properties in ./../conf/admin/admin.properties
INFO  - Including auto-located properties in ./../conf/authn/authn.properties
INFO  - Including auto-located properties in ./../conf/c14n/subject-c14n.properties
INFO  - Including auto-located properties in ./../conf/saml-nameid.properties
INFO  - Including auto-located properties in ./../conf/services.properties
INFO  - Including auto-located properties in ./../conf/ldap.properties
WARN  - Ignoring duplicate property 'idp.authn.LDAP.bindDNCredential'
WARN  - Ignoring duplicate property 'idp.attribute.resolver.LDAP.bindDNCredential'
Enabling idp.authn.MFA...
        conf/authn/mfa-authn-config.xml created
[OK]

Shutdown and restart tomcat with the following scripts /path/to/tomcat/bin/./shutdown.sh and /path/to/tomcat/bin/./start.sh.

Shibboleth IDP metadata

Once running the IDP we can configure reverse proxy such as Apache2 to make the IDP securely exposed and accessible with HTTPS. Apache2 can be configured with the CA signed certificates to ensure HTTPS protocol is using the private key and CA certificate. The AJP connector functionality allows Apache2 to connect transparently to Tomcat without needing to directly expose Tomcat.

vim /etc/apache2/sites-enabled/shibboleth.conf
# ------------------------------------------ #
<VirtualHost *:80>
    ServerName auth.example.com

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

    Redirect permanent / https://auth.example.com:443/
</VirtualHost>
<VirtualHost *:443>
    ServerName auth.example.com

    SSLCertificateFile      /path/to/certs/example.com.pem
    SSLCertificateKeyFile   /path/to/certs/example.com.key
    SSLCertificateChainFile /path/to/certs/chain-example.com.crt

    ProxyPass /idp ajp://127.0.0.1:8009/idp/ retry=0

</VirtualHost>

All Shibboleth configuration is done via XML files stored in /opt/shibboleth-idp/conf/. SAML uses XML metadata presented by the IDP and SP to share the required configurations for the respective components to send and receive attributes, keys/certs, SAML endpoints etc. The Shibboleth IDP requires the metadata for each SP to be configured in the metadataProvider.xml. There are a series of different mechanisms to configure the SP metadata. Although we are using FilesystemMetadataProvider in our example we can use FileBackedHTTPMetadataProvider to provide a metadata URL that is queried first which is stored as local XML file, incase the URL is inaccessible the previously stored metadata XML file is used.

vim metadataProvider.xml
# -------------------- #
<MetadataProvider
    id="cloud.example.com"
    xsi:type="FilesystemMetadataProvider"
    xmlns="urn:mace:shibboleth:2.0:metadata"
    metadataFile="%{idp.home}/metadata/cloud.example.com.xml">
</MetadataProvider>

Configuring any SSO will require a user directory or backend of some type from LDAP to SQL DB. Shibboleth IDP provides a series of method to connect to a user backend of choice with LDAPConnector, RelationalDatabaseConnector etc. The XML configuration file attribute-resolver.xml can be used to configure the LDAP connection. The XML component DataConnector accepts the configuration items ldapURL, baseDN, principleDN(bindDN), principleCredential(bindDNCredential) and more that are relevant to make a connection with the LDAP server.

vim attribute-resolver.xml
# ---------------------- #

<!-- LDAP Connector -->
<DataConnector id="myLDAP" xsi:type="LDAPDirectory"
                ldapURL="%{idp.authn.LDAP.ldapURL}"
                baseDN="%{idp.authn.LDAP.baseDN}"
                principal="%{idp.authn.LDAP.bindDN}"
                principalCredential="%{idp.authn.LDAP.bindDNCredential}"
<FilterTemplate>
        <![CDATA[
                %{idp.authn.LDAP.searchFilter}
        ]]>
</FilterTemplate>
</DataConnector>

A file named ldap.properties can be defined with certain configurable variables that are referenced in the XML configuration. This file is a simple key=value pair for each of the properties.

vim ldap.properties
# --------------- #

idp.authn.LDAP.baseDN = ou=people,dc=my-domain,dc=com
idp.authn.LDAP.searchFilter = (uid=$resolutionContext.principal)
idp.authn.LDAP.bindDNCredential = secret
idp.authn.LDAP.bindDN = cn=Manager,dc=my-domain,dc=com
idp.authn.LDAP.ldapURL = ldap://localhost

With regards to LDAP, Worteks provides a simple to use tool called LDAP ToolBox with a CLI tool called slapd-cli which can be used to backup, modify and restore openldap data and configurations.

Once shibboleth is able to connect to the LDAP server the users and their attributes need to be resolved to their appropriate variable name or user-specific customisations such as setting certain static values or modifications. Shibboleth IDP providers the administrator full ability to customise the attributes. The following is an example of the variables we can use in our test environment.

vim attribute-resolver.xml
# ---------------------- #

<AttributeDefinition xsi:type="Simple" id="uid">
        <InputDataConnector ref="myLDAP" attributeNames="uid" />
        <AttributeEncoder xsi:type="SAML1String"
                name="urn:mace:dir:attribute-def:uid" />
        <AttributeEncoder xsi:type="SAML2String"
                name="urn:oid:0.9.2342.19200300.100.1.1" friendlyName="uid" />
</AttributeDefinition>

<AttributeDefinition xsi:type="Simple" id="mail">
        <InputDataConnector ref="myLDAP" attributeNames="mail" />
        <AttributeEncoder xsi:type="SAML1String"
                name="urn:mace:dir:attribute-def:mail" />
        <AttributeEncoder xsi:type="SAML2String"
                name="urn:oid:0.9.2342.19200300.100.1.3" friendlyName="mail" />
</AttributeDefinition>

<AttributeDefinition xsi:type="Simple" id="sn">
        <InputDataConnector ref="myLDAP" attributeNames="sn" />
        <AttributeEncoder xsi:type="SAML1String"
                name="urn:mace:dir:attribute-def:sn" />
        <AttributeEncoder xsi:type="SAML2String"
                name="urn:oid:2.5.4.4" friendlyName="sn" />
</AttributeDefinition>

<AttributeDefinition xsi:type="Simple" id="givenName">
        <InputDataConnector ref="myLDAP" attributeNames="givenName" />
        <AttributeEncoder xsi:type="SAML1String"
                name="urn:mace:dir:attribute-def:givenName" />
        <AttributeEncoder xsi:type="SAML2String"
                name="urn:oid:2.5.4.42" friendlyName="givenName" />
</AttributeDefinition>

Shibboleth IDP also provides customisation to filter attributes to meet the requirements of the SP. These attributes are the usual basics such as givenName, sn, mail etc. Shibboleth IDP provides this configurability in attribute-filter.xml. This is a simple way to limit the information that is shared between an IDP and SP while also allowing for some privileged or demanding SPs to receive more information than other SPs. The value defined in this configuration refers to the entityID of the service provider protecting with Shibboleth.

vim attribute-filter.xml
# -------------------- #
<AttributeFilterPolicy id="nextcloud">
    <PolicyRequirementRule xsi:type="Requester" value="https://cloud.example.com" />
    <AttributeRule attributeID="uid">
        <PermitValueRule xsi:type="ANY" />
    </AttributeRule>
    <AttributeRule attributeID="mail">
        <PermitValueRule xsi:type="ANY" />
    </AttributeRule>
    <AttributeRule attributeID="sn">
        <PermitValueRule xsi:type="ANY" />
    </AttributeRule>
    <AttributeRule attributeID="givenName">
        <PermitValueRule xsi:type="ANY" />
    </AttributeRule>
</AttributeFilterPolicy>

NextCloud

Now that the IDP is configured we will deploy Nextcloud as our SP to protect the authentication with SAML SSO. I have chosen to use Docker compose to deploy Nextcloud with the following configuration.

services:
  nextcloud:
    container_name: nextcloud
    image: linuxserver/nextcloud:30.0.5
    ports:
      - 80:80
    volumes:
      - /path/to/nextcloud/config/:/config

Nextcloud will ask to create an admin account when setting it up for the first time. You will need to install the App SSO & SAML authentication which will enable the SAML SSO feature. An important aspect of the configuration is to enable the following option Allow the use of multiple user back-ends (e.g. LDAP) to ensure both direct login and SAML Login are available as options to users and admins.

NextCloud SAML Configuration

Once the SAML configuration has been validated the metadata for Nextcloud can be downloaded at the following URL: Nextcloud SAML Metadata URL

NextCloud SSO Login Page

The login page for Nextcloud should look as following enabling the option to log into both the Nextcloud default backend which can be configured with an LDAP server or the Shibboleth IDP that we have configured.