1. Introduction

This is a tutorial about setting up a basic SAML Service Provider (SP) for the CLARIN Service Provider Federation, using the Shibboleth SP software package.

1.1. Requirements and target audience

Familiarity with DNS and HTTP, SSH and shell interaction, XML and Unix/Linux is a prerequisite for understanding most material. I use a CentOS 7 image on Google Compute Engine (GCE). I will not cover the details of GCE, as you can use any hosting provider that gives you root access to a Linux server and an external static IP.

2. Preparation: creating an SP host

2.1. Creating a host and making it reachable from outside

Visit https://console.developers.google.com/ and create a project, then an instance under that project. In the following, you are free to use an arbitrary project name (e.g. test-sp) with an instance name (e.g. test-sp.clarin.eu-1). Mandatory is to register a fully-qualified domain name (FQDN) pointing to one of the SP host’s static external IP addresses via your DNS hosting provider or perhaps GCE itself. In this tutorial I assume an FQDN of test-sp.clarin.eu. The following, please substitute test-sp.clarin.eu with the fully-qualified domain name (FQDN) of your SP host, and likewise for the hostname test-sp. I will refer to your computer, running a modern Unix-like OS with common utilities such as curl, OpenSSH and rsync as well an XML editor, as your workstation and to the remote computer on which the SP will be set up as the SP host. Please also tick the 'Allow HTTPS traffic' under 'Network' in the instance settings.

2.2. Establish SSH login

On your workstation, issue for example:

ssh-keygen -t 'ed25519' -C 'Your_Google_Name@gmail.com' -n 'Your_Google_Name@gmail.com' -f ~/'.ssh/Your_Google_Name@test-sp.clarin.eu' &&
cat ~/'.ssh/Your_Google_Name@test-sp.clarin.eu.pub'

Substituting Your_Google_Name with your own Google login name.

Now copy and paste your SSH public key, which is now displayed as a result of the last cat command, key into your GCE configuration.

In order to work with the VM from your own command line instead of the web terminal, prepend the following snippet:

~/.ssh/config
Match originalhost test-sp
    Hostname test-sp.clarin.eu
    User Your_Google_Name
    IdentityFile "%d/.ssh/Your_Google_Name@test-sp.clarin.eu"

Substituting Your_Google_Name with your own Google login name.

You should now SSH into your SP host from a shell on your workstation:

ssh 'test-sp'

In case you cannot connect, please note that once you register the DNS record for your SP host, it may still take up to a day before this propagates to your workstation and other computers. You can decide to put the external static IP address as Hostname in your OpenSSH configuration instead of the FQDN, but you will still run into issues later on. So it’s best to be patient.

From now on, work on the SP host except I when state otherwise.

2.3. Installation and updating of software

Begin by updating your OS packages:

sudo yum makecache fast &&
sudo yum update

Then install the Shibboleth package repository so that your OS' package utilities such as yum will manage your Shibboleth installation:

(cd '/etc/yum.repos.d/' &&
sudo curl -v --location --remote-name 'http://download.opensuse.org/repositories/security://shibboleth/CentOS_7/security:shibboleth.repo')

Now install Shibboleth SP (shibd) and Apache HTTP server (httpd)

sudo yum install 'shibboleth' 'httpd'

Shibboleth service provider version 3 or later is required!

Disable the Apache HTTP server and Shibboleth SP after bootup for now:

sudo systemctl disable 'shibd' 'httpd'

Optionally, make sure your OS can find current versions of other software packages, which is critical if you e.g. wish to host a Python web application. Visit the IUS download page to determine the current release version and URL. In the following I assume CentOS 7 on the x86_64 platform:

sudo mkdir '/srv/installers/' ;
(cd '/srv/installers/' &&
current-ius_release_file_name='ius-release-1.0-14.ius.centos7.noarch.rpm' &&
current_ius_release_url='https://dl.iuscommunity.org/pub/ius/stable/CentOS/7/x86_64/'"${current-ius_release_file_name}" &&
sudo curl -v --fail --header 'Accept: application/x-rpm' --location --remote-name  &&
sudo yum install 'epel-release' &&
sudo rpm --hash --upgrade -v 'ius-release-1.0-14.ius.centos7.noarch.rpm' &&
sudo rm 'ius-release-1.0-14.ius.centos7.noarch.rpm')

Optionally, you may find it very helpful later into this tutorial to have set up a more usable text editor than the default vi:

sudo yum install 'nano' &&
printf '%s\n' 'EDITOR=nano export EDITOR ; ' >> ~/'.bashrc' &&
. ~/'.bashrc'

If the GNU/Linux kernel was updated, do remember to reboot now:

sudo reboot

3. Configuring Apache HTTP server

3.1. Changing its mode from prefork to worker

Shibboleth SP demands that deployers run the coupled Apache HTTP server in the 'worker' mode for performance reasons. Therefore, change httpd’s mode to 'worker' in `/etc/httpd/conf.modules.d/00-mpm.conf.

sudo -e '/etc/httpd/conf.modules.d/00-mpm.conf'
I will not repeat the command suggested above to edit a text file as superuser, but only mention the file’s path or name. Also, you are advised to configure your text editor to make backups, otherwise, please do not expect those to be around somewhere.

3.2. Enabling TLS (with OpenSSL)

Following the Red Hat 7 System Administrator’s Guide is a starting point to enable TLS using OpenSSL.

sudo yum install mod_ssl openssl

If SELinux is enabled, and it is by default on Red Hat 7, please stop it from enforcing policies. Shibboleth urges us to do this, as SELinux has a hard-to-grasp impact and is even claimed to break Shibboleth SP.

/etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#       enforcing - SELinux security policy is enforced.
#       permissive - SELinux prints warnings instead of enforcing.
#       disabled - No SELinux policy is loaded.
SELINUX=permissive  (1)
# SELINUXTYPE= can take one of these two values:
#       targeted - Targeted processes are protected,
#       mls - Multi Level Security protection.
SELINUXTYPE=targeted
1 This should work.

In my experience you will have to reboot before for this change to become effective.

3.3. Setting up a Virtual Host and creating a mock resource to protect

The Apache HTTP server configuration provided by many Linux distributions is rather convoluted and monolithic. An alternative configuration that relies on Virtual Host sections is more modular than such default configurations, and is practically required for this tutorial.

Create a Virtual Host for your resource or application, following the Red Hat 7 System Administrator’s Guide. To start out with, you can copy a template Virtual Host configuration file into a directory from which Apache HTTP server detects and reads configuration files. To remind you, in this tutorial I assume a fully-qualified domain name of the SP host equal to test-sp.clarin.eu, and so I give the file this corresponding name:

sudo cp --archive -v '/usr/share/doc/httpd-2.4.6/httpd-vhosts.conf' '/etc/httpd/conf.d/test-sp.clarin.eu.conf'

First, make Apache HTTP server load the mod_macro module:

printf '%s\n' 'LoadModule macro_module modules/mod_macro.so' | sudo tee '/etc/httpd/conf.modules.d/00-macro.conf'

This module will help modularize the configuration.

Comment out the Listen directive in '/etc/httpd/conf/httpd.conf', because you will want to keep this directive more clearly coupled to the Virtual Host by putting it in the same file as the Virtual Host configuration.

Comment out the Location directive for '/secure'

/etc/httpd/conf.d/shib.conf
#<Location /secure>
#  AuthType shibboleth
#  ShibRequestSetting requireSession 1
#  require shib-session
#</Location>

You will have to put a similar snippet back into the Virtual Host configuration later.

To create a Virtual Host configuration file that uses TLS (i.e. can be reached with an https:// URL) straightforwardly, disable the monolithic default ssl.conf file:

sudo mv -v '/etc/httpd/conf.d/ssl.conf' '/etc/httpd/conf.d/ssl.conf.disabled'

And create

/etc/httpd/conf.d/0_TLS_generic.conf
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog

SSLSessionCache shmcb:/run/httpd/sslcache(512000)
SSLSessionCacheTimeout 300

SSLRandomSeed startup file:/dev/urandom 256
SSLRandomSeed connect builtin
#SSLRandomSeed startup file:/dev/random  512
#SSLRandomSeed connect file:/dev/random  512
#SSLRandomSeed connect file:/dev/urandom 512

SSLCryptoDevice builtin
#SSLCryptoDevice ubsec

<Macro TLSVHost $fqdn>
ServerName $fqdn

SSLEngine on

SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5
#SSLCipherSuite RC4-SHA:AES128-SHA:HIGH:MEDIUM:!aNULL:!MD5
#SSLHonorCipherOrder on

SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
#SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt
#SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt

#SSLVerifyClient require
#SSLVerifyDepth  10

#<Location />
#SSLRequire (    %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \
#            and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
#            and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \
#            and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \
#            and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20   ) \
#           or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
#</Location>

#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire

BrowserMatch "MSIE [2-5]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
</Macro>
The contents of this helper configuration file are simply based on Red Hat 7’s default ssl.conf, and should not be assumed to be ideal. For instance, a default self-signed X.509 certificate is used instead of a trusted certificate that you should provide for production use. Before opening your SP for production, please review all of your configuration with respect to security separately using the most current and reliable sources.

An example Virtual Host configuration for your SP:

/etc/httpd/conf.d/test-sp.clarin.eu.conf
Listen 443 https

<VirtualHost *:443>
    UseCanonicalName On (1)
    UseCanonicalPhysicalPort On (1)
    ServerAdmin tech_contact@test-sp.clarin.eu
    DocumentRoot "/srv/www/test-sp.clarin.eu"
    ServerName test-sp.clarin.eu
    ErrorLog "/var/log/httpd/test-sp.clarin.eu-error_log"
    CustomLog "/var/log/httpd/test-sp.clarin.eu-access_log" common
    Use TLSVHost test-sp.clarin.eu

    <Directory "/srv/www/test-sp.clarin.eu">
        AllowOverride None
        Require all granted
    </Directory>

    <Directory "/srv/www/test-sp.clarin.eu/protected">
        AuthType shibboleth
        ShibRequestSetting requireSession 1
        require shib-session
    </Directory>
</VirtualHost>

The actual DocumentRoot directory tree that is declared in '/etc/httpd/conf.d/test-sp.clarin.eu.conf' must be created still:

(sudo mkdir --mode=a+rx --parents -v '/srv/www/{sp-fqdn}/' ;
cd '/srv/www/{sp-fqdn}/' &&
sudo chown --recursive v --reference='/var/www/' '/srv/www/' &&
sudo chmod --recursive v --reference='/var/www/' '/srv/www/' &&
sudo chcon --recursive --type httpd_used_content_t '/srv/www/')

To create a minimal example of optionally protected static content (e.g., resources as files), make some mock content like so:

(cd '/srv/www/test-sp.clarin.eu/' &&
sudo mkdir -v 'protected/' &&
printf '%s\n' 'This is a protected resource.' | sudo tee 'protected/my_resource.txt' &&
printf '%s\n' 'This is an unprotected resource.' | sudo tee 'my_resource.txt')

4. Configuring the Shibboleth Service Provider

First, please visit the Shibboleth Wiki on https://wiki.shibboleth.net/confluence/display/SHIB2/. Start out by reading up on the main the concepts. Next, read through Installation. After reading that you can move on to NativeSPLinuxInstall. Moving on, please go to NativeSPConfiguration and after reading that, visit NativeSPGettingStarted. Based on the perhaps overwhelming information you now read, it is clear that the main Shibboleth SP configuration file /etc/shibboleth/shibboleth2.xml needs some changes to get your SP working.

An important source of service-disrupting errors in XML configuration files is ill-formed or invalid XML. So, mind to use the right tool for the job, an XML editor, to edit such critical XML files. A suggestion: Oxygen XML editor.

4.1. The main configuration file

Now on your workstation, issue:

mkdir ~/'test-sp/' ;
(cd ~/'test-sp/' &&
rsync --archive --backup --itemize-changes --no-owner --no-group --relative --update -v 'test-sp:/etc/shibboleth/' .)

Open up your XML editor and open the file ~/'test-sp/etc/shibboleth/shibboleth2.xml'. A few positions in this XML document (pointed to by XPath expressions) should be changed to get a basic working configuration.

4.1.1. Setting your SP’s unique name

You have to give your SP a unique and standard name, its entityID.

  • Set /conf:SPConfig/conf:ApplicationDefaults[1]/@entityID to e.g. https://test-sp.clarin.eu/shibboleth.

This looks like a URL, but it is a URI and basically fictional.

4.1.2. Securing connections

You are also advised to configure your SP as secure-only by default, in terms of using TLS.

  • Set /conf:SPConfig/conf:ApplicationDefaults[1]/conf:Sessions[1]/@handlerSSL | /conf:SPConfig/conf:ApplicationDefaults[1]/conf:Sessions[1]/@checkAddress to true.

  • Set /conf:SPConfig/conf:ApplicationDefaults[1]/conf:Sessions[1]/@cookieProps to https.

4.1.3. Specifying SPF IdPs

Your SP needs to know which Identity Providers (IdPs) its users may come from.

  • This setting — which is SPF-specific — is at /conf:SPConfig/conf:ApplicationDefaults[1]/conf:MetadataProvider[1]. What to put here is briefly described at http://www.clarin.eu/content/creating-and-testing-shibboleth-sp. Which IdPs the two SAML metadata batches referred to in the snippet are about is described at http://www.clarin.eu/content/where-do-i-find-saml-metadata-identity-federations. All in all, you will end up with the following snippet:

    ~/test-sp/etc/shibboleth/shibboleth2.xml
    <MetadataProvider
        xmlns:xi="http://www.w3.org/2001/XInclude"
        type="Chaining">
        <!-- SAML metadata about all contracted identity federations' production IdPs. -->
        <MetadataProvider
            type="XML"
            uri="https://infra.clarin.eu/aai/prod_md_about_spf_idps.xml"
            backingFilePath="prod_md_about_spf_idps.xml"
            reloadInterval="7200">
            <MetadataFilter
                xmlns="urn:mace:shibboleth:2.0:native:sp:config"
                type="Blacklist">
                <Exclude>https://openidp.aco.net/saml</Exclude>
            </MetadataFilter>
        </MetadataProvider>
        <!-- SAML metadata about the CLARIN IdP. -->
        <MetadataProvider
            type="XML"
            uri="https://infra.clarin.eu/aai/prod_md_about_clarin_erics_idp.xml"
            backingFilePath="prod_md_about_clarin_erics_idp.xml"
            reloadInterval="7200"/>
    </MetadataProvider>

4.1.4. Letting users choose an IdP

The CLARIN central Discovery Service (DS) gives an accurate and usable listing of all IdPs that are connected to the SPF. you are advised to use it if your SP is only used for the SPF.

  • Replace the /conf:SPConfig/conf:ApplicationDefaults[1]/conf:Sessions[1]/conf:SSO[1] element with the snippet at CLARIN central Discovery Service:

    ~/test-sp/etc/shibboleth/shibboleth2.xml
    <!-- CLARIN central discovery service (DiscoJuice) -->
    <SSO
        discoveryProtocol="SAMLDS"
        discoveryURL="https://discovery.clarin.eu/discojuice">
        SAML2
    </SSO>

4.1.5. Contact info and error pages

Make sure that your SP gives the clearest required information to users in case of errors.

  • Change /conf:SPConfig/conf:ApplicationDefaults[1]/conf:Errors[1]/@supportContact to an appropriate e-mail-address.

As suggested by Shibboleth, you are advised to customize your error pages as well.

4.1.6. SAML metadata template

You must create SAML metadata that describes your SP. This will be discussed in Creating SAML metadata about your SP for external distribution. For now, configure an initial quasi SAML metadata file as template for the Metadata Generator handler at /conf:SPConfig/conf:ApplicationDefaults[1]/conf:Sessions[1]/conf:Handler[@type='MetadataGenerator'], substituting the element with:

~/test-sp/etc/shibboleth/shibboleth2.xml
<Handler
    type="MetadataGenerator"
    Location="/Metadata"
    signing="false"
    template="test-sp.clarin.eu.template.metadata.xml"/>

4.1.7. Finishing up the main configuration

You can remove the examples and comments explaining Shibboleth 2 defaults and functionality.

Configuration is not documentation and any documentation you leave in now may become outdated and misleading as the software changes.

If you have completed the previous sections successfully, you now have about this main configuration:

~/test-sp/etc/shibboleth/shibboleth2.xml
<SPConfig
    xmlns="urn:mace:shibboleth:2.0:native:sp:config"
    xmlns:conf="urn:mace:shibboleth:2.0:native:sp:config"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
    clockSkew="180">
    <!-- # tag::TCPListener[] -->
    <!-- ... -->
    <!-- # end::TCPListener[] -->
    <ApplicationDefaults
        entityID="https://test-sp.clarin.eu/shibboleth"
        REMOTE_USER="eppn persistent-id targeted-id">
        <Sessions
            lifetime="28800"
            timeout="3600"
            relayState="ss:mem"
            checkAddress="true"
            handlerSSL="true"
            cookieProps="https"
            redirectLimit="exact">
            <!-- # tag::SSO[] -->
            <!-- CLARIN central discovery service (DiscoJuice) -->
            <SSO
                discoveryProtocol="SAMLDS"
                discoveryURL="https://discovery.clarin.eu/discojuice">
                SAML2
            </SSO>
            <!-- # end::SSO[] -->
            <Logout>SAML2 Local</Logout>
            <NameIDMgmt>SAML2</NameIDMgmt>
            <!-- # tag::MetadataGenerator[] -->
            <Handler
                type="MetadataGenerator"
                Location="/Metadata"
                signing="false"
                template="test-sp.clarin.eu.template.metadata.xml"/>
            <!-- # end::MetadataGenerator[] -->
            <Handler
                type="Status"
                Location="/Status"
                acl="127.0.0.1 ::1"/>
            <Handler
                type="Session"
                Location="/Session"
                showAttributeValues="false"/>
            <Handler
                type="DiscoveryFeed"
                Location="/DiscoFeed"/>
        </Sessions>
        <Errors
            supportContact="spf@clarin.eu"
            helpLocation="/about.html"
            styleSheet="/shibboleth-sp/main.css"/>
        <!-- # tag::MetadataProvider[] -->
        <MetadataProvider
            xmlns:xi="http://www.w3.org/2001/XInclude"
            type="Chaining">
            <!-- SAML metadata about all contracted identity federations' production IdPs. -->
            <MetadataProvider
                type="XML"
                uri="https://infra.clarin.eu/aai/prod_md_about_spf_idps.xml"
                backingFilePath="prod_md_about_spf_idps.xml"
                reloadInterval="7200">
                <!-- # tag::MetadataFilter[] -->
                <MetadataFilter
                    xmlns="urn:mace:shibboleth:2.0:native:sp:config"
                    type="Blacklist">
                    <Exclude>https://openidp.aco.net/saml</Exclude>
                </MetadataFilter>
                <!-- # tag::MetadataFilter[] -->
            </MetadataProvider>
            <!-- SAML metadata about the CLARIN IdP. -->
            <MetadataProvider
                type="XML"
                uri="https://infra.clarin.eu/aai/prod_md_about_clarin_erics_idp.xml"
                backingFilePath="prod_md_about_clarin_erics_idp.xml"
                reloadInterval="7200"/>
        </MetadataProvider>
        <!-- # end::MetadataProvider[] -->
        <AttributeExtractor
            type="XML"
            validate="true"
            reloadChanges="false"
            path="attribute-map.xml"/>
        <AttributeResolver
            type="Query"
            subjectMatch="true"/>
        <AttributeFilter
            type="XML"
            validate="true"
            path="attribute-policy.xml"/>
        <CredentialResolver
            type="File"
            key="sp-key.pem"
            certificate="sp-cert.pem"/>
    </ApplicationDefaults>
    <SecurityPolicyProvider
        type="XML"
        validate="true"
        path="security-policy.xml"/>
    <ProtocolProvider
        type="XML"
        validate="true"
        reloadChanges="false"
        path="protocols.xml"/>
</SPConfig>

4.2. Generating a key pair for your SP’s cryptographic functions

The md:EntityDescriptor elements contain public keys. Public keys in SAML metadata about SPs are used for three purposes. The most relevant two are:

  • Verification of the authenticity of SAML metadata that IdPs consume about SPs.

  • Encryption of network traffic between the SP and the IdP, on top of any transport layer encryption (https/TLS).

You must configure Shibboleth SP with the right key separately from whatever you state in SAML metadata about your SP. In principle, metadata is for external distribution. However, once the key is configured the SAML Metadata Generator handler will include the public automatically in the SAML metadata about our SP.

Become superuser, and set the umask such that no other user will be able to read files you create:

sudo su
    umask 066

Now create a directory to store the key pair in securely, and generate the key pair:

mkdir --mode=u=rwx,go= '/root/keys/' ;
cd '/root/keys/' &&
command -p openssl req -new -x509 -nodes -newkey rsa:2048 -keyout 'test-sp.clarin.eu.private-key.pem' -days 3650 -subj '/CN=test-sp.clarin.eu' -out 'test-sp.clarin.eu.crt' &&
chown shibd:shibd 'test-sp.clarin.eu.private-key.pem' 'test-sp.clarin.eu.crt' &&
ln --force -v '/root/keys/test-sp.clarin.eu.private-key.pem' '/etc/shibboleth/sp-key.pem' &&
ln --force -v '/root/keys/test-sp.clarin.eu.crt' '/etc/shibboleth/sp-cert.pem' &&
exit

4.3. Creating SAML metadata about your SP for external distribution

SAML metadata that describes your SP is required for your SP to be registered with identity federations. While you create and update this SAML metadata, it is managed centrally by the SPF administration.

As described on the CLARIN SPF SPs metadata repository on GitHub, the contents of the preproduction SAML metadata batch about SPF SPs at https://infra.clarin.eu/aai/md_about_spf_sps.xml are directly sourced from the SAML metadata batch kept in the "production" branch of the CLARIN GitHub repository at https://raw.githubusercontent.com/clarin-eric/SPF-SPs-metadata/production/clarin-sp-metadata.xml.

You may have to temporarily configure your XML editor to accept invalid X.509 certificates when reading XML data from URLs, as you will do in the following steps. This is a consequence of the circumstance that TLS is not yet configured to a production level on the Apache HTTP server, as noted previously.

Now create the SAML metadata template file 'test-sp.clarin.eu.template.metadata.xml' in ~/'test-sp/etc/shibboleth' in the following way.

  1. Create your own fork of the CLARIN SPs metadata repository on github.

  2. Checkout your forked repository:

    mkdir --parents ~/'CLARIN/git/parts/' ;
    (cd ~/'CLARIN/git/parts/' &&
    git clone 'https://github.com/<your_fork_location>/SPF-SPs-metadata.git' --recursive)
  3. Open ~/'CLARIN/git/parts/SPF-SPs-metadata/clarin-sp-metadata.xml' with your XML editor. Find an example of good SAML metadata about an SP, an md:EntityDescriptor element. The best starting point to determine what is ‘good’ are CLARIN’s own guidelines for SAML metadata about SPF SPs.

  4. Copy this md:EntityDescriptor element into a new XML file in your XML editor.

  5. Optionally, fetch the original SAML metadata about your SP that is being generated automatically by the Metadata Generator handler by opening its default URL in XML editor.

    <md:EntityDescriptor
        xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
        ID="_138cfa3369070d4d44bda0e9346e9358ffe96dcf"
        entityID="https://test-sp.clarin.eu/shibboleth">
        <md:Extensions>
            <mdattr:EntityAttributes
                xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute">
                <saml:Attribute
                    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                    Name="http://macedir.org/entity-category"
                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
                    <saml:AttributeValue>http://www.geant.net/uri/dataprotection-code-of-conduct/v1</saml:AttributeValue>
                </saml:Attribute>
                <saml:Attribute
                    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                    Name="http://macedir.org/entity-category"
                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
                    <saml:AttributeValue>http://refeds.org/category/research-and-scholarship</saml:AttributeValue>
                </saml:Attribute>
            </mdattr:EntityAttributes>
            <alg:DigestMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmlenc#sha512"/>
            <alg:DigestMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#sha384"/>
            <alg:DigestMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
            <alg:DigestMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#sha224"/>
            <alg:DigestMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2009/xmldsig11#dsa-sha256"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <alg:SigningMethod
                xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport"
                Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
        </md:Extensions>
        <md:SPSSODescriptor
            protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
            <md:Extensions>
                <mdui:UIInfo
                    xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui">
                    <mdui:DisplayName
                        xml:lang="en">CLARIN - test-sp</mdui:DisplayName>
                    <mdui:Description
                        xml:lang="en">For resource A and web application B.</mdui:Description>
                    <mdui:DisplayName
                        xml:lang="de">CLARIN - test-sp</mdui:DisplayName>
                    <mdui:Description
                        xml:lang="de">Für Ressource A und Webanwendung B.</mdui:Description>
                    <mdui:DisplayName
                        xml:lang="fi">CLARIN - test-sp</mdui:DisplayName>
                    <mdui:Description
                        xml:lang="fi">Resurssien A ja web-sovelluksen B.</mdui:Description>
                    <mdui:DisplayName
                        xml:lang="nl">CLARIN - test-sp</mdui:DisplayName>
                    <mdui:Description
                        xml:lang="nl">Voor materiaal A en webapplicatie B.</mdui:Description>
                    <mdui:InformationURL
                        xml:lang="en">https://www.clarin.eu/applications</mdui:InformationURL>
                    <mdui:Logo
                        height="220"
                        width="195">https://www.clarin.eu/sites/default/files/clarin-logo.png</mdui:Logo>
                    <mdui:Keywords
                        xml:lang="en">CLARIN test-sp resource+A A B</mdui:Keywords>
                    <mdui:Keywords
                        xml:lang="nl">CLARIN test-sp materiaal+A A B</mdui:Keywords>
                    <mdui:PrivacyStatementURL
                        xml:lang="en">https://catalog.clarin.eu/privacy_statement.xhtml</mdui:PrivacyStatementURL>
                </mdui:UIInfo>
                <init:RequestInitiator
                    xmlns:init="urn:oasis:names:tc:SAML:profiles:SSO:request-init"
                    Binding="urn:oasis:names:tc:SAML:profiles:SSO:request-init"
                    Location="https://test-sp.clarin.eu/Shibboleth.sso/Login"/>
                <idpdisc:DiscoveryResponse
                    xmlns:idpdisc="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol"
                    Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol"
                    Location="https://test-sp.clarin.eu/Shibboleth.sso/Login"
                    index="1"/>
            </md:Extensions>
            <md:KeyDescriptor>
                <ds:KeyInfo
                    xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <ds:KeyName>https://test-sp.clarin.eu/shibboleth</ds:KeyName>
                    <ds:KeyName>resource_a.clarin.eu</ds:KeyName>
                    <ds:KeyName>test-sp.clarin.eu</ds:KeyName>
                    <ds:KeyName>web_app_b.clarin.eu</ds:KeyName>
                    <ds:X509Data>
                        <ds:X509SubjectName>CN=test-sp.clarin.eu</ds:X509SubjectName>
                        <ds:X509Certificate>MIIDTTCCAjWgAwIBAgIJAMWnf258cLcJMA0GCSqGSIb3DQEBBQUAMBwxGjAYBgNV
                            BAMTEXRlc3Qtc3AuY2xhcmluLmV1MB4XDTE2MDUxMDA5MTIwNloXDTI2MDUwODA5
                            MTIwNlowHDEaMBgGA1UEAxMRdGVzdC1zcC5jbGFyaW4uZXUwggEiMA0GCSqGSIb3
                            DQEBAQUAA4IBDwAwggEKAoIBAQDNNKQia0NthFeW2ZuBT0kq9ZswVLHwF4Y74SSm
                            B4lw7p/jFQLSiAcy584UvYFHiVZlAeXLvYB5AuOzJLc3rcFYyfuXgJPaYnKhWR6o
                            QGG/fEqRFM4U35DAnf9ZBW+C2XvdI4PYhVON4nfccY5/ojhfxYvnfnLBfaHdjiWR
                            kAJATxbVsNnvnQiGhdxBk5wRTM5yflWH5vkuaQw/mw0C8t7XPRaGtVg0d1iwGMt/
                            CIMEHiSDBB7yZS4bjVd6GCOuMxqolfVzZjsVjJmZmi0XbedtSi2Gm4beRhED+vtZ
                            hzni8qySX+1cDcoA6Dt2pN+jAUcsNi6fgdCqCI0BjX5/ZYC5AgMBAAGjgZEwgY4w
                            bQYDVR0RBGYwZIYkaHR0cHM6Ly90ZXN0LXNwLmNsYXJpbi5ldS9zaGliYm9sZXRo
                            ghF0ZXN0LXNwLmNsYXJpbi5ldYIUcmVzb3VyY2VfYS5jbGFyaW4uZXWCE3dlYl9h
                            cHBfYi5jbGFyaW4uZXUwHQYDVR0OBBYEFFiYqttJ5ZCl4NxH4AH5iMI0gaQgMA0G
                            CSqGSIb3DQEBBQUAA4IBAQAZck7UIKIHi8CvCcKhQwVQZ/QRSTWwNeNkdm1e9rOY
                            3VabmTTQuaq+IE0s2OlAjRnh/Hh39RfXxUABdBbKpwRvc0Ad9zc+t5YT7Fo684CU
                            QCnDsHraskPdQc7vRIYTIHlMiGa6hzW4P3tcQrJbq/5JKVdZy3Jm06waL26EJGdH
                            W61miKDHOkOH8YinJGEhVSzFc+UbuRGozd+KTqBhSCTtsROjhmh1NFrFWqCs+0SU
                            aIdBPrYzQglowdEF5PLit6VRITAA65CESq9ra+Q76+dqJ8B4XXbe+xHh1iWk8kob
                            B1m0lxloat5tLwJoNBn2aM3Je4aZN4pjPLB+IB0lsa/H
                        </ds:X509Certificate>
                    </ds:X509Data>
                </ds:KeyInfo>
                <md:EncryptionMethod
                    Algorithm="http://www.w3.org/2009/xmlenc11#aes128-gcm"/>
                <md:EncryptionMethod
                    Algorithm="http://www.w3.org/2009/xmlenc11#aes192-gcm"/>
                <md:EncryptionMethod
                    Algorithm="http://www.w3.org/2009/xmlenc11#aes256-gcm"/>
                <md:EncryptionMethod
                    Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
                <md:EncryptionMethod
                    Algorithm="http://www.w3.org/2001/04/xmlenc#aes192-cbc"/>
                <md:EncryptionMethod
                    Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
                <md:EncryptionMethod
                    Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
                <md:EncryptionMethod
                    Algorithm="http://www.w3.org/2009/xmlenc11#rsa-oaep"/>
                <md:EncryptionMethod
                    Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
            </md:KeyDescriptor>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                Location="https://resource_a.clarin.eu/Shibboleth.sso/SAML2/POST"
                index="1"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
                Location="https://resource_a.clarin.eu/Shibboleth.sso/SAML2/POST-SimpleSign"
                index="2"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
                Location="https://resource_a.clarin.eu/Shibboleth.sso/SAML2/Artifact"
                index="3"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
                Location="https://resource_a.clarin.eu/Shibboleth.sso/SAML2/ECP"
                index="4"/>
    
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                Location="https://web_app_b.clarin.eu/Shibboleth.sso/SAML2/POST"
                index="5"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
                Location="https://web_app_b.clarin.eu/Shibboleth.sso/SAML2/POST-SimpleSign"
                index="6"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
                Location="https://web_app_b.clarin.eu/Shibboleth.sso/SAML2/Artifact"
                index="7"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
                Location="https://web_app_b.clarin.eu/Shibboleth.sso/SAML2/ECP"
                index="8"/>
    
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                Location="https://test-sp.clarin.eu/Shibboleth.sso/SAML2/POST"
                index="9"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
                Location="https://test-sp.clarin.eu/Shibboleth.sso/SAML2/POST-SimpleSign"
                index="10"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
                Location="https://test-sp.clarin.eu/Shibboleth.sso/SAML2/Artifact"
                index="11"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
                Location="https://test-sp.clarin.eu/Shibboleth.sso/SAML2/ECP"
                index="12"/>
            <md:AttributeConsumingService
                index="1">
                <md:ServiceName
                    xml:lang="en">CLARIN - test-sp</md:ServiceName>
                <md:ServiceDescription
                    xml:lang="en">For resource A and web application B.</md:ServiceDescription>
                <md:RequestedAttribute
                    FriendlyName="eduPersonTargetedID"
                    Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10"
                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
                    isRequired="true"/>
                <md:RequestedAttribute
                    FriendlyName="eduPersonPrincipalName"
                    Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6"
                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
                    isRequired="true"/>
                <md:RequestedAttribute
                    FriendlyName="mail"
                    Name="urn:oid:0.9.2342.19200300.100.1.3"
                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
                    isRequired="false"/>
            </md:AttributeConsumingService>
        </md:SPSSODescriptor>
        <md:Organization>
            <md:OrganizationName
                xml:lang="en">CLARIN ERIC</md:OrganizationName>
            <md:OrganizationDisplayName
                xml:lang="en">CLARIN</md:OrganizationDisplayName>
            <md:OrganizationURL
                xml:lang="en">https://www.clarin.eu/</md:OrganizationURL>
        </md:Organization>
        <md:ContactPerson
            contactType="administrative">
            <md:GivenName>Dieter</md:GivenName>
            <md:SurName>Van Uytvanck</md:SurName>
            <md:EmailAddress>mailto:clarin@clarin.eu</md:EmailAddress>
        </md:ContactPerson>
        <md:ContactPerson
            contactType="support">
            <md:GivenName>Dieter</md:GivenName>
            <md:SurName>Van Uytvanck</md:SurName>
            <md:EmailAddress>mailto:spf@clarin.eu</md:EmailAddress>
        </md:ContactPerson>
        <md:ContactPerson
            contactType="technical">
            <md:GivenName>Dieter</md:GivenName>
            <md:SurName>Van Uytvanck</md:SurName>
            <md:EmailAddress>mailto:sysops@clarin.eu</md:EmailAddress>
        </md:ContactPerson>
    
    </md:EntityDescriptor>

    This gives a picture of what bare example SAML metadata about your SP looks like.

  6. Now create a template file like the following:

    ~/test-sp/etc/shibboleth/test-sp.clarin.eu.template.metadata.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <md:EntityDescriptor
        entityID="https://test-sp.clarin.eu/shibboleth"
        xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
        <md:Extensions>
            <mdattr:EntityAttributes
                xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute">
                <saml:Attribute
                    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
                    Name="http://macedir.org/entity-category">
                    <saml:AttributeValue>http://www.geant.net/uri/dataprotection-code-of-conduct/v1</saml:AttributeValue>
                </saml:Attribute>
                <saml:Attribute
                    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                    Name="http://macedir.org/entity-category"
                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
                    <saml:AttributeValue>http://refeds.org/category/research-and-scholarship</saml:AttributeValue>
                </saml:Attribute>
            </mdattr:EntityAttributes>
        </md:Extensions>
        <md:SPSSODescriptor
            protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
            <md:Extensions>
                <mdui:UIInfo
                    xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui">
                    <mdui:DisplayName
                        xml:lang="en">CLARIN - test-sp</mdui:DisplayName>
                    <mdui:Description
                        xml:lang="en">For resource A and web application B.</mdui:Description>
                    <mdui:DisplayName
                        xml:lang="de">CLARIN - test-sp</mdui:DisplayName>
                    <mdui:Description
                        xml:lang="de">Für Ressource A und Webanwendung B.</mdui:Description>
                    <mdui:DisplayName
                        xml:lang="fi">CLARIN - test-sp</mdui:DisplayName>
                    <mdui:Description
                        xml:lang="fi">Resurssien A ja web-sovelluksen B.</mdui:Description>
                    <mdui:DisplayName
                        xml:lang="nl">CLARIN - test-sp</mdui:DisplayName>
                    <mdui:Description
                        xml:lang="nl">Voor materiaal A en webapplicatie B.</mdui:Description>
                    <mdui:InformationURL
                        xml:lang="en">https://www.clarin.eu/applications</mdui:InformationURL>
                    <mdui:Logo
                        height="220"
                        width="195">https://www.clarin.eu/sites/default/files/clarin-logo.png</mdui:Logo>
                    <mdui:Keywords
                        xml:lang="en">CLARIN test-sp resource+A A B</mdui:Keywords>
                    <mdui:Keywords
                        xml:lang="nl">CLARIN test-sp materiaal+A A B</mdui:Keywords>
                    <mdui:PrivacyStatementURL
                        xml:lang="en">https://catalog.clarin.eu/privacy_statement.xhtml</mdui:PrivacyStatementURL>
                </mdui:UIInfo>
            </md:Extensions>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                Location="https://resource_a.clarin.eu/Shibboleth.sso/SAML2/POST"
                index="1"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
                Location="https://resource_a.clarin.eu/Shibboleth.sso/SAML2/POST-SimpleSign"
                index="2"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
                Location="https://resource_a.clarin.eu/Shibboleth.sso/SAML2/Artifact"
                index="3"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
                Location="https://resource_a.clarin.eu/Shibboleth.sso/SAML2/ECP"
                index="4"/>
            
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                Location="https://web_app_b.clarin.eu/Shibboleth.sso/SAML2/POST"
                index="5"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
                Location="https://web_app_b.clarin.eu/Shibboleth.sso/SAML2/POST-SimpleSign"
                index="6"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
                Location="https://web_app_b.clarin.eu/Shibboleth.sso/SAML2/Artifact"
                index="7"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
                Location="https://web_app_b.clarin.eu/Shibboleth.sso/SAML2/ECP"
                index="8"/>
            
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                Location="https://test-sp.clarin.eu/Shibboleth.sso/SAML2/POST"
                index="9"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
                Location="https://test-sp.clarin.eu/Shibboleth.sso/SAML2/POST-SimpleSign"
                index="10"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
                Location="https://test-sp.clarin.eu/Shibboleth.sso/SAML2/Artifact"
                index="11"/>
            <md:AssertionConsumerService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
                Location="https://test-sp.clarin.eu/Shibboleth.sso/SAML2/ECP"
                index="12"/>
            <md:AttributeConsumingService
                index="1">
                <md:ServiceName
                    xml:lang="en">CLARIN - test-sp</md:ServiceName>
                <md:ServiceDescription
                    xml:lang="en">For resource A and web application B.</md:ServiceDescription>
                <md:RequestedAttribute
                    FriendlyName="eduPersonTargetedID"
                    Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10"
                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
                    isRequired="true"/>
                <md:RequestedAttribute
                    FriendlyName="eduPersonPrincipalName"
                    Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6"
                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
                    isRequired="true"/>
                <md:RequestedAttribute
                    FriendlyName="mail"
                    Name="urn:oid:0.9.2342.19200300.100.1.3"
                    NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
                    isRequired="false"/>
            </md:AttributeConsumingService>
        </md:SPSSODescriptor>
        <md:Organization>
            <md:OrganizationName
                xml:lang="en">CLARIN ERIC</md:OrganizationName>
            <md:OrganizationDisplayName
                xml:lang="en">CLARIN</md:OrganizationDisplayName>
            <md:OrganizationURL
                xml:lang="en">https://www.clarin.eu/</md:OrganizationURL>
        </md:Organization>
        <md:ContactPerson
            contactType="administrative">
            <md:GivenName>Dieter</md:GivenName>
            <md:SurName>Van Uytvanck</md:SurName>
            <md:EmailAddress>mailto:clarin@clarin.eu</md:EmailAddress>
        </md:ContactPerson>
        <md:ContactPerson
            contactType="support">
            <md:GivenName>Dieter</md:GivenName>
            <md:SurName>Van Uytvanck</md:SurName>
            <md:EmailAddress>mailto:spf@clarin.eu</md:EmailAddress>
        </md:ContactPerson>
        <md:ContactPerson
            contactType="technical">
            <md:GivenName>Dieter</md:GivenName>
            <md:SurName>Van Uytvanck</md:SurName>
            <md:EmailAddress>mailto:sysops@clarin.eu</md:EmailAddress>
        </md:ContactPerson>
    </md:EntityDescriptor>

    The previous listing is basically a stripped-down version with regards to all dynamic/automatically generated elements in https://test-sp.clarin.eu/Shibboleth.sso/Metadata.

  7. Save the file.

  8. Add the contents of the previously saved ~/test-sp/etc/shibboleth/test-sp.clarin.eu.template.metadata.xml as an element under /md:EntitiesDescriptor in ~/'CLARIN/git/parts/SPF-SPs-metadata/clarin-sp-metadata.xml'. Save the latter file.

  9. Validate the file with your XML editor and the appropriate XML catalog of XSD schemas, or alternatively using the accompanying command line utility ~/'CLARIN/git/parts/SPF-SPs-metadata/check-saml-metadata/check_saml_metadata.sh' .

    (cd ~/'CLARIN/git/parts/SPF-SPs-metadata/' &&
    ./check-saml-metadata/check_saml_metadata.sh 'clarin-sp-metadata.xml')
  10. Once validation has succeeded and you have double-checked the final contents yourself, commit and push your revision of the SAML metadata batch into your git fork.

    (cd ~/'CLARIN/git/parts/SPF-SPs-metadata/' &&
    git commit -m 'Added test-sp.clarin.eu Service Provider' 'clarin-sp-metadata.xml' &&
    git push)
  11. Go back to your repository fork on the GitHub website and create a pull request to the master branch of the original CLARIN ERIC repository (SPF-SPs-metadata).

    After your pull request is created the check_saml_metadata.sh script will automactically run on the pull request code via Travis CI. The result of this check will be visible on the pull request page. Check the existing pull resquests on the original repository for examples.

    If your pull request successfully passes XSD validation, a CLARIN SPF operator will merge it into the master branch of original repository for QA assessment.

    The SPF operators will only consider for merging pull requests which are XSD valid. If you cannot make you file successfully pass the XSD validation or you believe you are hitting a false positive. Please create an issue explaining the problem.

    Every hour a cron job automatically analyzes the latest master version and generates a QA report visible in this spreadsheet. Mind to check and resolve issues in the SAML metadata quality for your SP after your pull request has been merged into the master branch.

    Finally your metadata will be merged into the 'production' branch and picked up by an hourly cron job which automatically checks out the latest version and publishes it at ​http://infra.clarin.eu/aai/prod_clarin_sp_metadata.xml

4.4. Pushing your revisions to your Shibboleth Service Provider configuration

Push your changes Shibboleth SP configuration directory to your SP-host:

(cd ~/{sp-hostname}/etc/shibboleth/ &&
rsync --archive --backup --itemize-changes --no-owner --no-group --relative --update -v '.' 'test-sp:shibboleth')

Then on your SP host, push the new-config to /etc/shibboleth:

(cd ~/shibboleth/ &&
sudo rsync --archive --backup --itemize-changes --no-owner --no-group --relative --update -v '.' '/etc/shibboleth')

5. Starting and enabling Shibboleth SP and Apache HTTP Server

(Re)start shibd:

sudo systemctl restart 'shibd'

If that succeeds, you are now ready to (re)start the Apache HTTP server:

sudo systemctl restart 'httpd'

If these steps succeeded, enable automatic starting of the Apache HTTP server and Shibboleth SP after bootup:

sudo systemctl enable 'shibd' 'httpd'

6. Checking SAML metadata about your SP

Do a check whether the SAML metadata about your SP being generated by the Metadata Generator handler is of the desired quality, by opening the URL https://test-sp.clarin.eu/Shibboleth.sso/Metadata in your XML editor. In case anything is wrong, follow the previous steps in Creating SAML metadata about your SP for external distribution again (without necessarily starting over completely).

7. Final results

To check whether your unprotected resource is being served out over HTTP:

curl --insecure 'https://test-sp.clarin.eu/my_resource.txt'

You should see the contents of your unprotected resource now.

By visiting https://test-sp.clarin.eu/my_resource.txt and https://test-sp.clarin.eu/protected/my_resource.txt, you will see that the one resource is freely accessible, whereas the other only after going through the CLARIN central DS and selecting the CLARIN IdP.