Shibboleth IdP 2.x is becoming End-Of-Life on July 31st, 2016.  This page now exists only as a historical archive - any new IdP deployments should follow the IdP 3.x documentation.

For upgrading, please see the instructions on Upgrading a 2.x IdP to 3.x.

Please note that if your 2.x IdP was configured with ComputeId connector for eduPersonTargetedID (not storing the values in a database), you will need to follow these instructions on configuring the StoredId connector on the 2.x IdP before upgrading to the 3.x IdP.

 

This page is a guide to installing a Shibboleth 2.x IdP. This page assumes the IdP would be installed on a blank Linux system (typically a virtual machine) and follows from that point on. The same process can be used to bootstrap a generic VM. The IdP will be installed both with the Shibboleth IdP software and the uApprove attribute release approval web application.

This guide is periodically updated as new versions of the software installed become available. This guide is current for IdP 2.3.6 and uApprove 2.4.1, the latest versions available as of May 2012. The guide was initially written with the assumption that CentOS/RHEL 5 would be the OS and Tomcat5 would be the web application server, but has been updated for RHEL6 (no change really needed) and Tomcat6 (minor variations, documented inline).

If you are interested in upgrading an existing IdP to the latest 2.x release, please see Upgrading a Shibboleth 2.x IdP.

But, more importantly, see the instructions on Upgrading a 2.x IdP to 3.x.

If you are interested in linking an existing IdP into Tuakiri, please see Configuring a Shibboleth Identity Provider to join the Tuakiri Federation.

Prerequisites

  • A Linux system (VM) preinstalled with base OS distribution, with current updates installed.
    • Minimum hardware recommendation: 1GB RAM, 16GB diskspace minimum
    • Linux distribution: recommended RHEL 6 or CentOS 6
  • Network requirements:
    • Allocating a hostname (typically idp.institution.domain.ac.nz) and a static IP address.
    • Setup firewall rules:
      • Enable incoming and outgoing TCP connections to ports 80, 443, 8443. Note that these connections MUST be direct connections and cannot go through a proxy. In particular, the port 8443 connections use client SSL authentication and will not work with proxies that try to step in the middle of an SSL connection, even if the server certificate is pre-loaded onto the proxy.
      • Enable connections to an external NTP server or provide an internal NTP server.
  • Provide an X509 certificate for the allocated hostname issued by a CA trusted by major browsers.
    • (There are no further requirements on the certificate, it would be only accessed from inside a browser)
  • Access to an institutional LDAP server (with a system account allowed to read all attributes needed for the federation). This typically includes the following information:
    • LDAP server hostname and port number
    • Search base (subtree DN)
    • Bind DN for a generic reader account
    • Bind password for this account
    • Search filter - i.e. what attribute contains the user's login name?

Modifications to Identity Management system

Your Identity Management System (IdMS) will very likely have most of the attributes asked for by the federation - or will have enough information to synthesize the specific attribute values on the fly inside the IdP. But for some attributes, the IdMS might not have enough information. The following information should be considered for adding into your IdMS:

  • eduPersonEntitlement: The eduPersonEntitlement attribute is a storage container for values representing privileges to access resources within the federation. It is a multi-valued string attribute. The values will have the form of a URI - with specific values that are yet to be defined. The attribute definition details are (source: Attribute Recommendation 2.1 (PDF), page 14):

    Origin/ObjectClass:   eduPerson [eduPerson]
    OID:                  1.3.6.1.4.1.5923.1.1.1.7
    SAML attribute name:  urn:mace:dir:attribute-def:eduPersonEntitlement
    LDAP syntax:          directoryString [1.3.6.1.4.1.1466.115.121.1.15]
    Number of values:     Multiple
    Example values:       eduPersonEntitlement: urn:mace:washington.edu:confocalMicroscope
                          eduPersonEntitlement: http://publisher.example.com/contract/GL123
    

    This attribute can also be defined as a static attribute. If you would prefer not to modify your IdMS schema and do not have any eduPersonEntitlement values to release, it is OK to initially only define the attribute as static inside the IdP. For more information on this option, please see the notes on configuring eduPersonEntitlement as a static attribute further below in this document.

  • auEduPersonSharedToken: The auEduPersonSharedToken uniquely identifies users when accessing certain resources - particularly within the computational grid and data grid. The values should be opaque, non-reassignable and persistent - and transferrable when a user moves between institutions. Even though the values are typically created as hash-values on first use, they MUST be stored and each institution must be ready to accept values users already have when coming from another institution. The attribute can be stored in either the IdMS directly (preferred) or in a database. The attribute definition details are (source: Attribute Recommendation 2.1 (PDF), pages 9-10, with OID updated to correct value):

    Origin/ObjectClass:   auEduPerson
    OID:                  1.3.6.1.4.1.27856.1.2.5
    SAML attribute name   urn:mace:federation.org.au:attribute:auEduPersonSharedToken
    LDAP syntax:          directoryString [1.3.6.1.4.1.27856.1.2.5]
    Number of values:     Single
    Example values:       ZsiAvfxa0BXULgcz7QXknbGtfxk
    
    • See also the auEduPerson LDAP Schema Definition(pages 45-52) for exact LDAP definition snippets.

      This auEduPersonSharedToken values can also be stored locally in a MySQL database. If you would prefer not to modify your IdMS schema, you can also choose the local database option - at the cost of not having all of your primary identity information in your IdMS. Please see the instructions on defining the sharedToken attribute further below for more detail.

  • eduPersonAssurance: This attribute represents the Levels of Assurance. Either add the attribute into the IdMS directly, or start collecting enough information to synthesize the values later in a scripted attribute definition (like done for Affiliation below).  The attribute definition details are (source: Attribute Recommendation 2.1 (PDF), page 13):

    Origin/ObjectClass:   eduPerson
    OID:                  1.3.6.1.4.1.5923.1.1.1.11
    SAML attribute name:  urn:oid:1.3.6.1.4.1.5923.1.1.1.11
    LDAP syntax:          directoryString [1.3.6.1.4.1.1466.115.121.1.15]
    Number of values:     multiple
    Example values:       See AAF IdentityLoA Vocabulary
    

Preliminaries

System firewall configuration

  • Edit /etc/sysconfig/iptables and add rules to permit incoming traffic to ports 80, 443, and 8443; add the following just below the rule for port 22:

    -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
    -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT
    -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 8443 -j ACCEPT
    
  • Restart iptables:

    service iptables restart
    

Bootstrapping the VM

We assume a standard install of either CentOS or RHEL, version 5 or 6. The IdP web application can run inside Tomcat either 5 or 6. CentOS/RHEL 5 comes with Tomcat5 (but Tomcat6 can be installed from JPackage), RHEL6 comes with Tomcat6. Further on, we'll be referring to the Tomcat of choice as $TOMCAT_NAME (either tomcat5 or tomcat6).

Install packages

  • Apache with mod_ssl, Java (with javac) and Tomcat:

    yum install httpd mod_ssl java-1.6.0-openjdk java-1.6.0-openjdk-devel ant $TOMCAT_NAME
    
  • MySQL (needed for storing sharedToken values and uApprove attribute release approvals)
    • MySQL is not strictly required and an alternative database system may be used if already available on site - just use the corresponding JDBC drivers for the alternative database.

      yum install mysql mysql-server
      
  • Install NTP (if time synchronization is to be done inside the VM)

    yum install ntp
    
  • Useful debugging / sysadmin tools

    yum install openldap-clients wireshark-gnome mc strace subversion
    

Local configuration

  • Configure NTP: time synchronization is crucial for the Shibboleth IdP to correctly interact with Service Providers in the federation. Please gather beforehand the hostname or IP address of the time server provided within your organisation. Further on, we'll assume it's ntp.institution.domain.ac.nz. If your organisation is not providing one, you may use an external source (including the default servers listed in /etc/ntp.conf) - but make sure your firewall allows the NTP traffic through (outgoing UDP port 123 traffic + reply packets).
    • Do a one-off synchronization:

      ntpdate -s ntp.institution.domain.ac.nz
      
    • Edit /etc/ntp.conf and:

      • Comment out local server (server 127.127.1.0 and fudge 127.127.1.0)
      • Comment out CentOS servers (all lines starting with server)
      • The local time server:

        server ntp.institution.domain.ac.nz
        
    • Make ntpd start on system startup:

      chkconfig ntpd on
      
    • Start ntpd now:

      service ntpd start
      
    • Check ntpd is running and synchronizing: run

      ntpdc -p
      
  • Disable SELinux: the Apache LDAP module does not work with SELinux - SELinux would not allow the module to open outgoing TCP connections.
    • Disable SELinux now:

      echo 0 > /selinux/enforce
      
    • And for future restarts, edit /etc/sysconfig/selinux and change:

      SELINUX=permissive
      

Basic Shibboleth IdP and uApprove installation

Rationale and planning

From the very beginning, we will install the Shibboleth IdP:

  • as a web application WAR file managed by Tomcat
  • with uApprove integrated into the web application
  • with a Tomcat login screen used for authentication

Having done these steps early in the installation prevents them from slipping later on.

The installation paths will be (as close to defaults as possible, putting all IdP files under /opt:

  • IDP_HOME - /opt/shibboleth-idp (default)
  • Tomcat home: /var/lib/$TOMCAT_NAME (where Tomcat web applications and common files live)

Your IdP hostname will be idp.institution.domain.ac.nz
Your scope, home organization name and security domain will be institution.domain.ac.nz
Your IdP entityId will be https://idp.institution.domain.ac.nz/idp/shibboleth

  • The Shibboleth IdP installation directory (from where Shibboleth IdP software is installed) will be /root/inst/shibboleth-identityprovider-<version> - and the name of the directory will be stored in SHIB_INST_HOME (here, we assume version is 2.3.6)
  • The uApprove installation directory will be /root/inst/uApprove-<version> and the name of the directory will be stored in UAPPROVE_INST_HOME (here, we assume version is 2.4.1)
  • Configure the corresponding environment variable: create /etc/profile.d/shib.sh with the following content (and make the file executable):

    IDP_VERSION="2.3.6"
    UAPPROVE_VERSION="2.4.1"
    SHIB_HOME=/opt/shibboleth-idp
    SHIB_INST_HOME=/root/inst/shibboleth-identityprovider-$IDP_VERSION
    UAPPROVE_INST_HOME=/root/inst/uApprove-$UAPPROVE_VERSION
    IDP_HOME=/opt/shibboleth-idp
    JAVA_HOME=/usr/lib/jvm/java
    TOMCAT_NAME=tomcat5 # can be tomcat5 or tomcat6
    TOMCAT_HOME=/var/lib/$TOMCAT_NAME
    
    export SHIB_HOME IDP_HOME JAVA_HOME TOMCAT_HOME SHIB_INST_HOME UAPPROVE_INST_HOME
    

Basic Shibboleth Installation

  • Create an installation directory and download Shibboleth

    mkdir /root/inst
    cd /root/inst
    wget http://www.shibboleth.net/downloads/identity-provider/${IDP_VERSION}/shibboleth-identityprovider-${IDP_VERSION}-bin.zip
    unzip shibboleth-identityprovider-${IDP_VERSION}-bin.zip
    cd $SHIB_INST_HOME
    
  • Invoke installer

    sh ./install.sh
    
    • When prompted, give the following non-default answers:
      • FQDN is the hostname assigned to your IdP, typically idp.institution.domain.ac.nz
      • Keystore password would be used to create the java keystore containing the back-channel certificates. As the private key will be also stored on disk in an unencrypted X509 key file, there is no need to choose a secure keystore password...

        FQDN: idp.institution.domain.ac.nz
        Keystore: changeit
        

Important

When re-running the installer in the future (you'll be asked to do so further on in this guide), you'll be asked whether to overwrite the configuration files.
It is important you answer no to that question - otherwise, all modifications made to the configuration files will be lost.

  • This installs the Shibboleth IdP web application into /opt/shibboleth-idp/war/idp.war

Configure Tomcat and deploy the IdP WAR

  • Create /etc/$TOMCAT_NAME/Catalina/localhost/idp.xml with the following content:

          <Context docBase="/opt/shibboleth-idp/war/idp.war"
                   privileged="true"
                   antiResourceLocking="false"
                   antiJARLocking="false"
                   unpackWAR="false"
                   swallowOutput="true" />
    

Endorse XML libraries used by the IdP. This procedure is different for Tomcat6 (where the endorsed directory needs to be created and defined first) and for Tomcat5 (where the directory exists but contains other versions of the XML libraries that need to be deleted first).

  • If installing with Tomcat6:
    • Create /var/lib/tomcat6/common/endorsed:

      mkdir -p /var/lib/tomcat6/common/endorsed
    • Add the following to /etc/sysconfig/tomcat6 to make endorsed directories really work:

      JAVA_ENDORSED_DIRS="/var/lib/tomcat6/common/endorsed"
    • And copy all jars from $SHIB_INST_HOME/endorsed/ into this endorsed directory:

      cp $SHIB_INST_HOME/endorsed/* /var/lib/tomcat6/common/endorsed
  • If installing with Tomcat5, remove /var/lib/tomcat5/common/endorsed/* (@[xml-commons-apis].jar and @[jaxp_parser_impl].jar, symbolic links to /usr/share/java/) and install all jars from $SHIB_INST_HOME/endorsed/ into /var/lib/tomcat5/common/endorsed

    ls -l /var/lib/tomcat5/common/endorsed/*
    rm /var/lib/tomcat5/common/endorsed/*
    cp $SHIB_INST_HOME/endorsed/* /var/lib/tomcat5/common/endorsed
    
  • Connectors: in /etc/$TOMCAT_NAME/server.xml, define a new AJP connector at port 8009.

    Note

    Tomcat6 already has this connector defined, but in an insecure way that would be opening the connector to outside connections as well. Comment the original definition out and instead put this definition in.

       <Connector port="8009" address="127.0.0.1"
                  enableLookups="false" redirectPort="443" protocol="AJP/1.3"
                  tomcatAuthentication="false" />
    
  • And comment out the existing http connector defined for port 8080:

        <!--
        <Connector port="8080" maxHttpHeaderSize="8192"
                   maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
                   enableLookups="false" redirectPort="8443" acceptCount="100"
                   connectionTimeout="20000" disableUploadTimeout="true" />
        -->
    
  • Tweak Tomcat memory settings: increase the default Java minimal and maximal heap size settings to at least 512MB (or more, depending the total RAM in your VM)
    • Edit /etc/$TOMCAT_NAME/$TOMCAT_NAME.conf and add:

      JAVA_OPTS="-Xms256m -Xmx768m"
      

Configure Apache

Apache needs to be configured to:

  • Listen on ports 443 and 8443 - this is done via separate configuration files idp.conf and idp8443.conf (bypassing parts of the default configuration in ssl.conf)
  • Disable SSL session cache to work around a bug
  • To make Apache listen at ports 443 and 8443, create /etc/httpd/conf.d/ports.conf with

    Listen 443
    Listen 8443
    
  • To configure the two virtual hosts for the two ports, download the files attached to this page idp.conf and idp8443.conf into /etc/httpd/conf.d
    • In both files, replace all occurrences of idp.example.org with the hostname of your IdP
    • In idp.conf, configure the SSL VirtualHost to use the commercial certificate issued for your IdP
    • Note that idp.conf is configured to disable all access to <Location /idp/Authn/RemoteUser> - all users will be authenticating via the Tomcat login screen.
    • Note that idp8443.conf is using the back-channel certificate generated when deploying Shibboleth IdP, stored in /opt/shibboleth-idp/credentials
  • Make a backup of your ssl.conf

    cd /etc/httpd/conf.d/
    cp ssl.conf ssl.conf.dist
    
  • Edit your ssl.conf and:
    • Disable SSL session cache by commenting out the default SSLSessionCache directive and instead setting the cache to none:

      #SSLSessionCache         shmcb:/var/cache/mod_ssl/scache(512000)
      SSLSessionCache         none
      
    • Delete the whole default <VirtualHost> section from ssl.conf (the definitions in idp.conf and idp8443.conf will be used instead).
    • Delete the entry for Listen 443 (because we now have the directive in ports.conf).

Basic Shibboleth Configuration

  • Set symbolic links for your convenience. Link /etc/shibboleth to the Shibboleth IdP configuration directory and /var/log/shibboleth to the Shibboleth IdP log directory:

    ln -s /opt/shibboleth-idp/conf /etc/shibboleth
    ln -s /opt/shibboleth-idp/logs /var/log/shibboleth
    
  • Backup Shibboleth IdP original configuration: to make it easier to track changes done to the Shibboleth configuration files, create a backup copy of each of the files with the ".dist" suffix:

     for FILE in \
    /opt/shibboleth-idp/conf/{attribute-filter.xml,attribute-resolver.xml,handler.xml,internal.xml,logging.xml,relying-party.xml,service.xml,login.config} \
         /root/inst/shibboleth*/src/main/webapp/login.jsp /opt/shibboleth-idp/metadata/idp-metadata.xml ; do cp -i $FILE $FILE.dist ; done
    
  • Configure proper Scope in IdP metadata: edit /opt/shibboleth-idp/metadata/idp-metadata.xml and make sure the Scope is set to your institution.domain.ac.nz - both for IDPSSODescriptor and AttributeAuthorityDescriptor (two modifications)

            <Extensions>
                <shibmd:Scope regexp="false">institution.domain.ac.nz</shibmd:Scope>
            </Extensions>
    
  • Configure the IdP to load the Federation Metadata in /opt/shibboleth-idp/conf/relying-party.xml by adding the following snippet into the Chaining MetadataProvider.

            <!-- Tuakiri -->
            <metadata:MetadataProvider id="Tuakiri" xsi:type="metadata:ResourceBackedMetadataProvider">
              <metadata:MetadataFilter xsi:type="metadata:ChainingFilter" xmlns="urn:mace:shibboleth:2.0:metadata">
                <metadata:MetadataFilter xsi:type="metadata:SignatureValidation" xmlns="urn:mace:shibboleth:2.0:metadata"
                                trustEngineRef="shibboleth.MetadataTrustEngine"
                                requireSignedMetadata="true" />
              </metadata:MetadataFilter>
              <metadata:MetadataResource xsi:type="resource:FileBackedHttpResource"
                              url="https://directory.tuakiri.ac.nz/metadata/tuakiri-metadata-signed.xml"
                              file="/opt/shibboleth-idp/metadata/tuakiri-metadata.xml" />
            </metadata:MetadataProvider>
    
  • The Tuakiri metadata should have their signature verified: add the trust engine definition as well (or uncomment and configure it further down in the file):

        <!-- Trust engine used to evaluate the signature on loaded metadata. -->
        <security:TrustEngine id="shibboleth.MetadataTrustEngine" xsi:type="security:StaticExplicitKeySignature">
            <security:Credential id="Tuakiri-FederationCredentials" xsi:type="security:X509Filesystem">
                <security:Certificate>/opt/shibboleth-idp/credentials/tuakiri-metadata-cert.pem</security:Certificate>
            </security:Credential>
        </security:TrustEngine>
    
  • This definition is referring to a certificate used to verify the signature - store the certificate in /opt/shibboleth-idp/credentials

    wget https://directory.tuakiri.ac.nz/metadata/tuakiri-metadata-cert.pem -O $IDP_HOME/credentials/tuakiri-metadata-cert.pem
    
  • Note that the relying-party.xml file also refers to:
    • Our own metadata generated for the IdP in /opt/shibboleth-idp/metadata/idp-metadata.xml
    • Our own credentials stored in /opt/shibboleth-idp/credentials/idp.crt and /opt/shibboleth-idp/credentials/idp.key
    • Our own entityId (also stored in the self-metadata in /opt/shibboleth-idp/metadata/idp-metadata.xml

Configure IdP with a login screen

It is desirable to have a site-branded login screen - which makes it easier for users to recognize the proper login screen - and may be necessary for deploying site-wide login and password-handling policies. The credentials are then cached only for a given period of time - instead of the whole browser session.

For deploying a login screen for a Shibboleth 2.0 IdP:

  • Edit $IDP_HOME/conf/handler.xml and
    • Uncomment UsernamePassword LoginHandler
    • Comment out RemoteUser LoginHandler
    • Optionally, customize session duration (default 30 minutes): add the following attribute (with the duration either in minutes or using the PT notation) to the UsernamePassword login handler:

      authenticationDuration="PT1H0M0.000S"
  • Edit $IDP_HOME/conf/login.config and provide details for the LDAP server (uncomment and configure LdapLoginModule section). You may have to provide more attributes than what's in the default commented-out section: namely subtreeSearch="true" and serviceUser and serviceCredential with login details for a privileged account (to look up users). The following section has worked at Canterbury:

       edu.vt.middleware.ldap.jaas.LdapLoginModule required
          host="ldap.canterbury.ac.nz"
          base="ou=useraccounts,dc=canterbury,dc=ac,dc=nz"
          serviceUser="<ldap user DN here>"
          serviceCredential="<ldap password here>"
          subtreeSearch="true"
          ssl="false"
          tls="false"
          userField="uid";
    
  • Customize login screen with site branding: edit src/main/webapp/login.jsp in your Shibboleth IdP source distribution
    • Rebuild and redeploy the WAR file afterwards by re-running the installer:

      cd $SHIB_INST_HOME
      sh ./install.sh
      

LDAP connections with TLS/SSL with an untrusted certificate

The connection to the LDAP server can be established either over plain LDAP (no cryptographic protection), or over LDAP with either TLS/SSL. Some LDAP servers may be configured to only accept a bind operation over an cryptographically protected channel (TLS or SSL). Some LDAP servers might however be using a self-signed certificate - or a certificate issued by a CA not trusted by the default Java trust store. In that case, it is necessary to add the CA certificate issuing the LDAP server certificate (or alternatively the LDAP server cerificate itself) to the Java keystore.

  • Get the CA certificate and save it into /opt/shibboleth-idp/credentials/local-ca.crt (picking an appropriate file name)
  • Make a copy of the default Java keystore:

    cp $JAVA_HOME/jre/lib/security/cacerts $JAVA_HOME/jre/lib/security/cacerts.orig
  • Import the CA certificate into the Java keystore:

    keytool -import -trustcacerts -alias "Local-CA" -file /opt/shibboleth-idp/credentials/_local-ca_.crt -keystore $JAVA_HOME/jre/lib/security/cacerts
    • Change the alias to something descriptive for the local CA
    • You will get prompted for the passphrase protecting the Java keystore. The default password is "changeit" (literally).

Install uApprove

Privacy laws require the IdP to get an explicit consent from the user before releasing personal information about the user to other parties. Thus, before proceeding with a Shibboleth login and sending the user's attributes to the Service Provider, the IdP must first obtain the user's consent. The uApprove application takes care of this - it steps in the first time the user is logging in to a service, and asks the user for permission to release the required (and desired) attributes to the service. The user would be asked again if the set of attributes released to the service changes. The user also has the option of giving a Global consent - permission to release any attributes to any service the user accesses in the future. The Global consent can be later revoked (via the Reset-approvals feature) and can also be completely disabled in the system-wide configuration (if the institution decided their users shouldn't be allowed to give global consent).

More information about uApprove, as well as download links, can be found at http://www.switch.ch/aai/support/tools/uApprove.html.

As uApprove plugs into the IdP, the version of uApprove must be matched to be compatible with the version of IdP. At the time of writing (May 2012), the most recent version of uApprove (2.4.1) is compatible with IdP 2.3.6 (the most recent stable version).

As of version 2.4.1, uApprove installs directly into the IdP web applications (previous versions, up to 2.2.1, were a separate web application with install base in /opt/uApprove). The uApprove configuration files are now located in /opt/shibboleth-idp/conf. After installing uApprove into the IdP web application, it is necessary to re-run the IdP installer to rebuild the IdP WAR file.

The following instructions are closely based on the uApprove 2.4.1 installation manual, http://www.switch.ch/aai/downloads/uApprove-manual/

Please check at the uApprove website that 2.4.1 is still the most recent version - and otherwise refer to the new version's installation manual for updated instructions.

uApprove can store the approval information in either a SQL database, or in a flat file. Storing the information in a SQL database is more scalable, and it also allows to revoke consent already given. This guide documents installing uApprove configured to use a local MySQL database. Please refer to the uApprove installation manual for other alternatives.

To install uApprove:

  • Download the uApprove binary distribution, unpack it in /root/inst

    cd /root/inst
    wget http://www.switch.ch/aai/downloads/uApprove-${UAPPROVE_VERSION}.zip
    unzip uApprove-${UAPPROVE_VERSION}.zip
    
  • Copy uApprove libraries into the IdP lib directory:

    # match the variable names used in uApprove manual
    export UAPPROVE_INSTALL=$UAPPROVE_INST_HOME
    export IDP_INSTALL=$SHIB_INST_HOME
    cp $UAPPROVE_INSTALL/lib/*.jar $IDP_INSTALL/lib
    cp $UAPPROVE_INSTALL/lib/jdbc/*.jar $IDP_INSTALL/lib
    
  • If using a SQL database (e.g., MySQL), install the JDBC driver into $IDP_INSTALL/lib. Either download the version from the database vendor's site (for MySQL: http://dev.mysql.com/downloads/connector/j/), or use one packaged with uApprove in $UAPPROVE_INSTALL/lib/jdbc/optional (has version 5.1.18 of the MySQL JDBC driver).
  • Copy configuration files into IdP configuration directory:

    cp $UAPPROVE_INSTALL/manual/configuration/uApprove.properties $IDP_HOME/conf
    cp $UAPPROVE_INSTALL/manual/configuration/uApprove.xml $IDP_HOME/conf
    
  • Copy the uApprove web application files (JSPs, CSS, images) to the IdPs webapp directory:

    mkdir $IDP_INSTALL/src/main/webapp/uApprove
    cp $UAPPROVE_INSTALL/webapp/* $IDP_INSTALL/src/main/webapp/uApprove
    
  • If running with MySQL:

    Note on MySQL timeouts

    By default, MySQL closes connections after 8 hours of inactivity. This breaks connections overnight - and the database clients running on the IdP (uApprove and also SharedToken) report errors when reconnecting to the database (even when using autoReconnect=true).

    As of September 2011 when this manual has been updated to use JDBC URLs that set the wait_timeout session variable to a very high value (one year), so changing the setting on the server side is no longer necessary.

    The original instructions were to edit /etc/my.cnf and add the following into the [mysqld] section:

    wait_timeout=31536000 # 3600*24*365 - one year
    • Start MySQL server and make it start automatically:

      service mysqld start
      chkconfig mysqld on
      
    • Set the MySQL root password (in a default installation, MySQL root user has no password):

      /usr/bin/mysqladmin -u root password MYSQL-ROOT-PASSWORD
    • For convenience, create a /root/.my.cnf file that allows Unix root to login as MySQL root without entering a password:

      [client]
      password=MYSQL-ROOT-PASSWORD
      
  • Create a MySQL database (uApprove), a user (also uApprove), and grant the user full access over the database (replace DB-PASSWORD with a suitable password):

    mysql -u root
    mysql>
    CREATE DATABASE uApprove;
    CREATE USER 'uApprove'@'localhost' IDENTIFIED BY 'DB-PASSWORD';
    GRANT ALL PRIVILEGES ON uApprove.* TO 'uApprove'@'localhost';
    ALTER DATABASE uApprove DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
    
  • Create the database tables, logging in as uApprove: run mysql -u uApprove -p, and feeding the two table definition SQL files to mysql:

    mysql -u uApprove -p uApprove < $UAPPROVE_INSTALL/manual/storage/attribute-release-schema.sql
    mysql -u uApprove -p uApprove < $UAPPROVE_INSTALL/manual/storage/terms-of-use-schema.sql
    
  • Make a backup of original uApprove configuration files before modifying them:

    for FILE in $IDP_HOME/conf/uApprove.properties $IDP_HOME/conf/uApprove.xml $SHIB_INST_HOME/src/main/webapp/WEB-INF/web.xml ; do cp $FILE ${FILE}.dist ; done
    
  • Edit the IdP web application deployment descriptor ($IDP_INSTALL/src/main/webapp/WEB-INF/web.xml) and paste in the relevant snippet as per section 2.1 of the uApprove manual.
    • Add the uApprove.xml file to the list of contextConfigLocation URLs
    • Add the uApprove filter, filter-mapping, servlet, and servlet-mapping elements just before the end of the top-level web-app element.

      <web-app ...>
      
          <context-param>
              <param-name>contextConfigLocation</param-name>
              <param-value>$IDP_HOME$/conf/internal.xml; $IDP_HOME$/conf/service.xml; $IDP_HOME$/conf/uApprove.xml; </param-value>
          </context-param>
      
          <!-- IdP Listeners, Filters and Servlets -->
          <!-- ...                                 -->
      
      
          <!-- uApprove Filter and Servlets -->
      
          <filter>
              <filter-name>uApprove</filter-name>
              <filter-class>ch.SWITCH.aai.uApprove.Intercepter</filter-class>
          </filter>
      
          <filter-mapping>
              <filter-name>uApprove</filter-name>
              <url-pattern>/profile/Shibboleth/SSO</url-pattern>
              <url-pattern>/profile/SAML1/SOAP/AttributeQuery</url-pattern>
              <url-pattern>/profile/SAML1/SOAP/ArtifactResolution</url-pattern>
              <url-pattern>/profile/SAML2/POST/SSO</url-pattern>
              <url-pattern>/profile/SAML2/POST-SimpleSign/SSO</url-pattern>
              <url-pattern>/profile/SAML2/Redirect/SSO</url-pattern>
              <url-pattern>/profile/SAML2/Unsolicited/SSO</url-pattern>
              <url-pattern>/Authn/UserPassword</url-pattern>
          </filter-mapping>
      
          <servlet>
              <servlet-name>uApprove - Terms Of Use</servlet-name>
              <servlet-class>ch.SWITCH.aai.uApprove.tou.ToUServlet</servlet-class>
          </servlet>
      
          <servlet-mapping>
              <servlet-name>uApprove - Terms Of Use</servlet-name>
              <url-pattern>/uApprove/TermsOfUse</url-pattern>
          </servlet-mapping>
      
          <servlet>
              <servlet-name>uApprove - Attribute Release</servlet-name>
              <servlet-class>ch.SWITCH.aai.uApprove.ar.AttributeReleaseServlet</servlet-class>
          </servlet>
      
          <servlet-mapping>
              <servlet-name>uApprove - Attribute Release</servlet-name>
              <url-pattern>/uApprove/AttributeRelease</url-pattern>
          </servlet-mapping>
      
      </web-app>
      
  • Edit $IDP_HOME/conf/uApprove.xml and change property location from a classpath URL to: file:/opt/shibboleth-idp/conf/uApprove.properties
  • Edit $IDP_HOME/conf/uApprove.properties and customize the following:
    • Set services (services excluded from uApprove) to the SLCS servers (AU and NZ) - note that as of uApprove 2.4.1, this is now a set of regular expressions:

      services                    = ^https://slcs1\.arcs\.org\.au/shibboleth$ \
                                    ^https://slcs\.nesi\.org\.nz/shibboleth$ \
                                    ^https://slcs1\.nesi\.org\.nz/shibboleth$
      
    • Make the database URL automatically reconnect and use very long session timeouts: database.url = jdbc:mysql://localhost:3306/uApprove?autoReconnect=true&sessionVariables=wait_timeout=31536000
    • Set the database password for the uApprove user: database.password = DB-PASSWORD
    • Disable Terms-Of-Use: tou.enabled = false
    • List the order in which attributes should appear (instead of letting them display in a random order each time: change the ar.attributes.order property (which lists only a few attributes by default) to cover all relevant attributes:

      ar.attributes.order         = commonName \
                                    displayName \
                                    auEduPersonLegalName \
                                    givenName \
                                    surname \
                                    email \
                                    eduPersonPrincipalName \
                                    uid \
                                    auEduPersonSharedToken \
                                    eduPersonTargetedID \
                                    eduPersonEntitlement \
                                    eduPersonAssurance \
                                    eduPersonAffiliation \
                                    eduPersonScopedAffiliation \
                                    eduPersonPrimaryAffiliation \
                                    auEduPersonAffiliation \
                                    organizationName \
                                    homeOrganization \
                                    homeOrganizationType \
                                    organizationalUnit \
                                    postalAddress \
                                    telephoneNumber \
                                    mobileNumber
      
  • Add a checkbox into the login form that would give the user the option to reset all prior approvals: edit $SHIB_INST_HOME/src/main/webapp/login.jsp and add the following table row with a checkbox below the password prompt table row:

                 <tr><td colspan="2">
    
      <input id="uApprove.consent-revocation" type="checkbox" name="uApprove.consent-revocation" value="true"/>
      <label for="uApprove.consent-revocation">Clear my attribute release consent</label>
      <div class="infotext">Checking this option resets all of your previously given approvals for sending information about you to this site and any other services.</div>
                       </td></tr>
    
    
  • Rebuild the Shibboleth IdP WAR:

    cd $SHIB_INST_HOME
    sh ./install.sh
    
  • If you already have the IdP running, restart Tomcat and reload Apache (otherwise, if this is the first install, wait with starting Tomcat till instructed to do so in the next section):

    service $TOMCAT_NAME restart
    

For additional documentation, see the uApprove installation manual at http://www.switch.ch/aai/downloads/uApprove-manual/.

Start Tomcat

  • Make all files under /opt/shibboleth-idp owned by Tomcat:

    chown -R tomcat.tomcat /opt/shibboleth-idp
    
  • For extra security, you may consider making files where passwords to MySQL are stored readable only to the Tomcat users:

    chmod 600 /opt/shibboleth-idp/conf/uApprove.properties /opt/shibboleth-idp/conf/attribute-resolver.xml /opt/shibboleth-idp/conf/login.config
  • Start MySQL, Tomcat and Apache and make them auto start:

    service mysqld start
    service $TOMCAT_NAME start
    service httpd start
    chkconfig mysqld on
    chkconfig $TOMCAT_NAME on
    chkconfig httpd on
    

Configure Attribute Resolver

All attribute configuration is done in /opt/shibboleth-idp/conf/attribute-resolver.xml.

Edit the file and implement the following changes:

Link your Attribute Resolver to your LDAP server

In /opt/shibboleth-idp/conf/attribute-resolver.xml, uncomment the LDAP DataConnector element and configure it with local LDAP connection parameters to connect to your LDAP server (ldapURL, baseDN, principal, principalCredential) and also set the property java.naming.referral to "follow":

    <resolver:DataConnector id="myLDAP" xsi:type="LDAPDirectory" xmlns="urn:mace:shibboleth:2.0:resolver:dc"
        ldapURL="*ldap://ldap.institution.domain.ac.nz*" baseDN="dc=institution,dc=domain,dc=ac,dc=nz" principal="LDAP-BIND-DN-HERE"
        principalCredential="PASSWORD-HERE">
        <FilterTemplate>
            <![CDATA[
                (cn=$requestContext.principalName)
            ]]>
        </FilterTemplate>
        <dc:LDAPProperty name="java.naming.referral" value="follow"/>
    </resolver:DataConnector>

Link existing attributes

  • Define attributes available directly in LDAP: mail, sn, and givenName: just uncomment the relevant AttributeDefinition element for each of these attributes.
  • Define attributes available as an attribute in the LDAP with a slightly different name - typically, in ActiveDirectory, cn would be the user's login name, while displayName would be the user's actual preferred (common) name. In that case, uncomment the relevant AttributeDefinition element and change the sourceAttributeID XML attribute to the name of the original attribute. If connecting to ActiveDirectory,
    • Define cn based on displayName (sourceAttributeID="displayName")
    • Define uid based on cn
    • Define displayName based on displayName.
  • Define eduPersonPrincipalName define based on cn with your institution's scope (in the form institution.domain.ac.nz): set the scope attribute like:

    scope="institution.domain.ac.nz" sourceAttributeID="cn"
  • If either eduPersonAssurance or eduPersonEntitlement are available in your IdMS, expose them via the IdP by uncommenting their respective definition in attribute-resolver.xml

Define static attributes

We need to define several attributes that would have a static value for each user. We do so by first defining a StaticDataConnector (close to where the commented-out example is):

  • Provide actual meaningful values for your institution: full organization name, home organization name (same as scope), and home Organization Type.
    <!-- Static Connector -->
    <resolver:DataConnector id="staticAttributes" xsi:type="dc:Static">
        <dc:Attribute id="o">
            <dc:Value>The Institution</dc:Value>
        </dc:Attribute>
        <dc:Attribute id="homeOrganization">
            <dc:Value>institution.domain.ac.nz</dc:Value>
        </dc:Attribute>
        <dc:Attribute id="homeOrganizationType">
            <dc:Value>urn:mace:terena.org:schac:homeOrganizationType:int:university</dc:Value>
        </dc:Attribute>
    </resolver:DataConnector>

Now define the attributes:

  • Define organizationName by uncommenting the definition and changing the connector dependency from "myLDAP" to "staticAttributes"
    • Note: the attribute constructed by the IdP is called organizationName, while the attribute defined in the staticAttributes connector used as the source for this attribute is called just o. Don't get confused.
  • Pasting in the definitions for homeOrganization and homeOrganizationType, not provided in the default configuration:
    <resolver:AttributeDefinition id="homeOrganization" xsi:type="ad:Simple" sourceAttributeID="homeOrganization">
        <resolver:Dependency ref="staticAttributes" />
        <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:oid:1.3.6.1.4.1.25178.1.2.9" />
        <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:1.3.6.1.4.1.25178.1.2.9" friendlyName="homeOrganization" />
    </resolver:AttributeDefinition>

    <resolver:AttributeDefinition id="homeOrganizationType" xsi:type="ad:Simple" sourceAttributeID="homeOrganizationType">
        <resolver:Dependency ref="staticAttributes" />
        <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:oid:1.3.6.1.4.1.25178.1.2.10" />
        <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:1.3.6.1.4.1.25178.1.2.10" friendlyName="homeOrganizationType" />
    </resolver:AttributeDefinition>

Define scripted attributes

The eduPersonAffiliation and eduPersonPrimaryAffiliation describe the affiliation type of the user authenticating. The typical question is: "Is this person staff or student?" The full set of values (with definitions available in the AAF Attribute Recommendation: eduPersonAffiliation) is: faculty / student / staff / employee / member / affiliate / alum / library-walk-in. The eduPersonAffiliation attribute is multi-valued and should include all values that apply to the user, while eduPersonPrimaryAffiliation should contain only a single, the most relevant value.

Typically, the LDAP server will not be directly providing values for these attributes, but it would have some attributes that allow to determine at least some of the affiliation type values applying to the user - e.g. to tell whether the user is a staff member or a student.

In this case, we recommend defining the attributes using a scriptlet, synthesizing the value from the LDAP attributes available.

This would be very specific for each institution. We illustrate this in an example (based on an actual setup), where we assume the LDAP server has attributes:

  • isUnderGrad (boolean)
  • isPostGrad (boolean)
  • isStaff (boolean)

We decide to give anyone with isStaff=TRUE the "staff" affiliation, and to anyone with isUnderGrad=TRUE OR isPostGrad=TRUE the "student" affiliation. Also, anyone who is staff or student also gets the "member" affiliation.

  • We first define these attributes at the Shibboleth level, importing them from LDAP, using the following definitions. Note that as these attributes are not expected to be passed in Shibboleth assertions, the definitions don't have any AttributeEncoder elements. Otherwise, we would have to decide on attribute names / OIDs to use in the encoder definitions.
    <!-- prerequisite to scripted eduPersonAffiliation -->
    <resolver:AttributeDefinition id="isUnderGrad" xsi:type="ad:Simple" sourceAttributeID="isUnderGrad">
        <resolver:Dependency ref="myLDAP" />
        <!-- no encoder needed -->
    </resolver:AttributeDefinition>

    <resolver:AttributeDefinition id="isPostGrad" xsi:type="ad:Simple" sourceAttributeID="isPostGrad">
        <resolver:Dependency ref="myLDAP" />
        <!-- no encoder needed -->
    </resolver:AttributeDefinition>

    <resolver:AttributeDefinition id="isStaff" xsi:type="ad:Simple" sourceAttributeID="isStaff">
        <resolver:Dependency ref="myLDAP" />
        <!-- no encoder needed -->
    </resolver:AttributeDefinition>
  • We follow by defining eduPersonAffiliation using an AttributeDefinition of type Script:
    <resolver:AttributeDefinition id="eduPersonAffiliation" xsi:type="ad:Script">
        <resolver:Dependency ref="isUnderGrad" />
        <resolver:Dependency ref="isPostGrad" />
        <resolver:Dependency ref="isStaff" />
        <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:mace:dir:attribute-def:eduPersonAffiliation" />
        <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1" friendlyName="eduPersonAffiliation" />
        <ad:Script>
        <![CDATA[
                importPackage(Packages.edu.internet2.middleware.shibboleth.common.attribute.provider);
                if (eduPersonAffiliation == null) {
                        eduPersonAffiliation = new BasicAttribute("eduPersonAffiliation");
                }
                is_UnderGrad = isUnderGrad != null && isUnderGrad.getValues().size()>0 && isUnderGrad.getValues().get(0).equals("TRUE");
                is_PostGrad = isPostGrad != null && isPostGrad.getValues().size()>0 && isPostGrad.getValues().get(0).equals("TRUE");
                is_Staff = isStaff != null && isStaff.getValues().size()>0 && isStaff.getValues().get(0).equals("TRUE");

                if (is_Staff) { eduPersonAffiliation.getValues().add("staff"); };
                if (is_UnderGrad || is_PostGrad ) { eduPersonAffiliation.getValues().add("student"); };
                if (is_UnderGrad || is_PostGrad || is_Staff ) { eduPersonAffiliation.getValues().add("member"); };
        ]]>
        </ad:Script>
    </resolver:AttributeDefinition>
  • And a similar definition for eduPersonPrimaryAffiliation (which has to be a single valued attribute, hence the logic in the script is slightly different):
    <resolver:AttributeDefinition id="eduPersonPrimaryAffiliation" xsi:type="ad:Script">
        <resolver:Dependency ref="isUnderGrad" />
        <resolver:Dependency ref="isPostGrad" />
        <resolver:Dependency ref="isStaff" />
        <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:mace:dir:attribute-def:eduPersonPrimaryAffiliation" />
        <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:1.3.6.1.4.1.5923.1.1.1.5" friendlyName="eduPersonPrimaryAffiliation" />
        <ad:Script>
        <![CDATA[
                importPackage(Packages.edu.internet2.middleware.shibboleth.common.attribute.provider);
                if (eduPersonPrimaryAffiliation == null) {
                        eduPersonPrimaryAffiliation = new BasicAttribute("eduPersonPrimaryAffiliation");
                }
                is_UnderGrad = isUnderGrad != null && isUnderGrad.getValues().size()>0 && isUnderGrad.getValues().get(0).equals("TRUE");
                is_PostGrad = isPostGrad != null && isPostGrad.getValues().size()>0 && isPostGrad.getValues().get(0).equals("TRUE");
                is_Staff = isStaff != null && isStaff.getValues().size()>0 && isStaff.getValues().get(0).equals("TRUE");

                if (is_Staff) { eduPersonPrimaryAffiliation.getValues().add("staff"); }
                else if (is_UnderGrad || is_PostGrad ) { eduPersonPrimaryAffiliation.getValues().add("student"); };
        ]]>
        </ad:Script>
    </resolver:AttributeDefinition>
  • Finally, we define the eduPersonScopedAffiliation attribute by uncommenting the definition and:
    • setting your institution's scope, in the format scope="institution.domain.ac.nz"
    • changing the dependency from LDAP to the previously defined attribute eduPersonAffiliation:

              <resolver:Dependency ref="eduPersonAffiliation" />
      

Define sharedToken

The shared token value MUST be stored in either the LDAP server itself (preferred, keeps the values alongside primary identity information), or alternatively in a MySQL database (easier to get going by running a MySQL server directly on the IdP).

In this section, some instructions are specific to storing the shared token values in an LDAP server, some are specific to storing the values in a local MySQL server - please choose accordingly.

  • If storing the sharedToken value in your LDAP server, edit the conf/sharedtoken.properties inside the jar and change the following settings - the search filter should be the same as in your LDAP connector - configuring which LDAP attribute is the principal name:

    DEFAULT_IDP_HOME=/opt/shibboleth-idp
    SEARCH_FILTER_SPEC=cn={0}
    
  • Copy the JAR into $SHIB_INST_HOME/lib and (later) rerun the Shibboleth IdP installer to rebuild the webapp WAR archive. (When rerunning the installer, accept the default install location (or specify your install location, stored also in $IDP_HOME) and answer no to the question on overwriting configuration.)

    cp arcs-shibext-*.jar $SHIB_INST_HOME/lib
    cd $SHIB_INST_HOME
    sh ./install.sh
    

Configuring a MySQL database for storing sharedToken values

  • If configuring with a MySQL database and a MySQL driver is not yet present in the IdP (should be installed with uApprove), download the MySQL JDBC driver from http://dev.mysql.com/downloads/connector/j/5.0.html
    • Install the driver (mysql-connector-java-5.0.8-bin.jar) into $SHIB_INST_HOME/lib and also into /opt/shibboleth-idp/lib (and re-run the Shibboleth IdP installer - now)
  • Create a MySQL user: run "mysql" as root and enter the following commands:

     create user 'idp_admin'@'localhost' identified by 'IDP_ADMIN_PASSWORD';
     grant all privileges on idp_db.* to 'idp_admin'@'localhost';
    
  • Create a MySQL user: run "mysql" as idp_admin and enter the following commands:

     mysql -u idp_admin -p
    
     CREATE DATABASE idp_db;
     use idp_db;
    
     CREATE TABLE tb_st (
     uid VARCHAR(100) NOT NULL,
     sharedToken VARCHAR(50),
     PRIMARY KEY  (uid)
     );
    

Defining sharedToken attribute (both LDAP and MySQL)

  • Add schema definition to attribute-resolver.xml: add urn:mace:arcs.org.au:shibboleth:2.0:resolver:dc classpath:/schema/arcs-shibext-dc.xsd to the list of schema locations at the top of the file.
  • Add connector definition to attribute-resolver.xml(sharedToken) with the following customizations:
    • idPIdentifier - your IdP entityId
    • sourceAttributeID: combination of attributes that is unique, non-reassignable and if possible persistent - if usernames are not reused at your institution, username is perfectly fine - so the "cn" or "uid" attribute would do
    • If using a MySQL server, enter the database connection details, with the IDP_ADMIN_PASSWORD as defined just above
    • If storing sharedToken in an LDAP server:
      • Omit the DatabaseConnection element from the below snippet
      • Change the values to storeLdap="true" and storeDatabase="false"

            <!-- ==================== auEduPersonSharedToken data connector ================== -->
        
            <resolver:DataConnector xsi:type="SharedToken" xmlns="urn:mace:arcs.org.au:shibboleth:2.0:resolver:dc"
                                id="sharedToken"
                                idpIdentifier="https://idp.institution.domain.ac.nz/idp/shibboleth"
                                sourceAttributeID="cn"
                                storeLdap="false"
                                storeDatabase="true"
                                salt="SALT-GOES-HERE">
                <resolver:Dependency ref="myLDAP" />
        
                <DatabaseConnection jdbcDriver="com.mysql.jdbc.Driver"
                                    jdbcURL="jdbc:mysql://localhost/idp_db?autoReconnect=true&amp;sessionVariables=wait_timeout=31536000"
                                    jdbcUserName="idp_admin"
                                    jdbcPassword="IDP_ADMIN_PASSWORD"
                                    primaryKeyName="uid"/>
        
            </resolver:DataConnector>
        

        Please note that the sharedToken module would be accessing the LDAP server from the connector specified in the dependency - so the same LDAP server as used for retrieving all other attributes, with the same credentials. Therefore, in order for this module to succeed in storing the generated sharedToken values, the account specified in the LDAP connector needs to have the permissions to write into the auEduPersonSharedToken attribute.

  • Note: on the first install, generate a suitable salt value with:

     openssl rand -base64 36 
    • On subsequent installs, reuse the same value (stored somewhere carefully)
  • Note also that the SharedToken value depends on the IdP entityID - which could be picked up from the environment, but is better set in the configuration.
  • Note that the JdbcURL sets the "autoReconnect=true" option and sets the wait_timeout session variable to a very high value (one year) - which is an extension from the original shared-token installation instructions.
    • As we are putting a URL with an ampersand (&) into an XML document, we need to encode the character as &amp;
  • Add attribute definition to attribute-resolver.xml (auEduPersonSharedToken)

        <!-- ==================== auEduPersonSharedToken attribute definition ================== -->
        <resolver:AttributeDefinition id="auEduPersonSharedToken" xsi:type="ad:Simple" sourceAttributeID="auEduPersonSharedToken">
            <resolver:Dependency ref="sharedToken" />
            <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:mace:federation.org.au:attribute:auEduPersonSharedToken" />
            <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:1.3.6.1.4.1.27856.1.2.5" friendlyName="auEduPersonSharedToken" />
        </resolver:AttributeDefinition>
    
  • Release attribute in attribute-filter.xml (auEduPersonSharedToken)
    • See attribute release later.

eduPersonTargetedID

Based on https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPTargetedID, define (uncomment) eduPersonTargetedID (in the "new" format only, ignore the "old" format). The steps are:

  1. Uncommenting AttributeDefinition id="eduPersonTargetedID"
  2. Uncommenting DataConnector where id="computedID and changing it in the following ways:
    • Using just the username attribute (typically cn, uid or sAMAccountName) as the source attribute.
      • Note: the attribute chosen must be unique, persistent, and non-reassignable - if usernames are reused at your institution, you must choose a different attribute (e.g., objectGUID on AD servers works well for this purpose)
    • Using a value of salt generated (only at the first install, to be reused later) with:

      openssl rand -base64 36

This is the final configuration of the ComputeID DataConnector (without the proper salt):

    <resolver:DataConnector xsi:type="ComputedId" xmlns="urn:mace:shibboleth:2.0:resolver:dc"
                            id="computedID"
                            generatedAttributeID="computedID"
                            sourceAttributeID="cn"
                            salt="abcef123YOURVALUE">
        <resolver:Dependency ref="myLDAP" />
    </resolver:DataConnector>

eduPersonAssurance

The eduPersonAssurance expresses both levels of identity assurance and authentication assurance (i.e., both how sure an IdMS is about the identity of a user and how strong authentication mechanisms were used to establish the session). These attributes would ideally have per-user values, based on information captured about the users in the IdMS - e.g., an attribute tracking whether the business process for creating the user's credentials involved checking official photoID documents and e.g. what kind of password policy applies to the user.

In the absence of such information in the IdMS, we recommend to at least define this attribute as a static attribute (providing the same value for all users) at level 1 (floor of trust). The basic requirements for level 1 are that the institution has documented processes for issuing credentials and is following good practice in managing credentials.

To configure the level 1 values as static attributes:

  • Add the level1 identity and authentication assurance values to the staticAttributes connector (defined above) with id="eduPersonAssurance":

        <resolver:DataConnector id="staticAttributes" xsi:type="dc:Static">
            <dc:Attribute id="eduPersonAssurance">
                <dc:Value>urn:mace:aaf.edu.au:iap:id:1</dc:Value>
                <dc:Value>urn:mace:aaf.edu.au:iap:authn:1</dc:Value>
            </dc:Attribute>
        ...
        </resolver:DataConnector>
    
  • Uncomment the eduPersonAssurance attribute definition and change the connector dependency from "myLDAP" to "staticAttributes"

eduPersonEntitlement

The eduPersonEntitlement attribute is a multivalued container for arbitrary strings (URNs) that identify privileges. Most values are yet-to-be-defined, one commonly used value is urn:mace:dir:entitlement:common-lib-terms. If not adding the eduPersonEntitlement to your IdMS, we recommend defining eduPersonEntitlement as a static attribute with this value (representing "this user has library privileges") being the only value defined.

  • Uncomment the eduPersonEntitlement attribute definition and change the connector dependency from "myLDAP" to "staticAttributes"
  • Add single value to be released (can be multivalued if desired) to the staticAttributes connector (defined above) with id="eduPersonEntitlement":

        <resolver:DataConnector id="staticAttributes" xsi:type="dc:Static">
            <dc:Attribute id="eduPersonEntitlement">
                <dc:Value>urn:mace:dir:entitlement:common-lib-terms</dc:Value>
            </dc:Attribute>
        ...
        </resolver:DataConnector>
    

Configuring Attribute Release

  • Attribute release is configured in /opt/shibboleth-idp/conf/attribute-filter.xml
  • The file can contain multiple policies.
  • Each policy can apply to a number of hosts or hostgroups (federations) - linked with the basic:OR policy.
  • Attributes are referred to by the "friendly" ID they get assigned in attribute-resolver.xml.
  • Further documentation on policy rules is at https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAddAttributeFilter.
  • The following two policies release:
    • All the required attributes to the Tuakiri Federation Registry - necessary for logging in there.
    • All available attributes to the Tuakiri Attribute Reflector (running on the virtualhome server) - very useful for testing.

          <afp:AttributeFilterPolicy id="federationRegistryPolicy" >
              <afp:PolicyRequirementRule xsi:type="basic:AttributeRequesterString" value="https://registry.tuakiri.ac.nz/shibboleth" />
      
              <afp:AttributeRule attributeID="displayName">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="surname">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="givenName">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="email">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="homeOrganization">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="homeOrganizationType">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="eduPersonTargetedID">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="auEduPersonSharedToken">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
          </afp:AttributeFilterPolicy>
      
          <afp:AttributeFilterPolicy id="virtualHomePolicy" >
              <afp:PolicyRequirementRule xsi:type="basic:AttributeRequesterString" value="https://virtualhome.tuakiri.ac.nz/shibboleth" />
      
              <afp:AttributeRule attributeID="displayName">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="commonName">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="surname">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="givenName">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="email">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="eduPersonPrincipalName">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="eduPersonScopedAffiliation">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="eduPersonAffiliation">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="eduPersonAssurance">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="eduPersonPrimaryAffiliation">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="homeOrganization">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="homeOrganizationType">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="organizationName">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="eduPersonTargetedID">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="auEduPersonSharedToken">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="eduPersonEntitlement">
                  <afp:PermitValueRule xsi:type="basic:AttributeValueString" value="urn:mace:dir:entitlement:common-lib-terms" />
              </afp:AttributeRule>
      
              <afp:AttributeRule attributeID="auEduPersonAffiliation">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="auEduPersonLegalName">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
      
              <afp:AttributeRule attributeID="mobileNumber">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="postalAddress">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="organizationalUnit">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
              <afp:AttributeRule attributeID="telephoneNumber">
                  <afp:PermitValueRule xsi:type="basic:ANY" />
              </afp:AttributeRule>
      
          </afp:AttributeFilterPolicy>
      
  • As needed, add more refined policies for hosts that need additional attributes. Instead of manually defining policies for all hosts, configure the automatic download of the Tuakiri attribute release policy synthesized for your IdP - see further below for that.
  • You may also wish to configure additional attribute release policies - e.g., if establishing bilateral relations with some service providers outside Tuakiri or if registering your IdP into another federation that does not generate a per-SP attribute filter (in that case, releasing a set of attributes to all hosts in the federation via an RequesterInEntityGroup rule might be a good choice). For more information on such configuration, please see the Shibboleth 2 IdP attribute filter documentation.

Register the IdP into the federation

Please follow the instructions on registering an IdP into the Tuakiri federation (using Federation Registry URL https://registry.tuakiri.ac.nz/federationregistry/ for the Tuakiri federation or https://registry.test.tuakiri.ac.nz/federationregistry/ for Tuakiri-TEST)

Go to the respecting Federation Registry URL and:

  • Register an Organisation for your institution (if not already registered)
    • For Contact Details, do not use a shared mailbox, alias or mailing list when entering an email address because the confirmation email contains a single-use link and may cause some confusion should more than one person attempt to use it.
    • For Organization Name, enter your DNS domain name.
    • For Organization Display Name, enter your actual organization name.
  • Wait for the Organisation to be approved
  • Register your IdP under that Organisation
    • Provide the Contact Details for the IdP admin (again, do not use a shared mailbox).
    • Select the organisation and provide a name and description for your IdP.
    • Enter the base URL for your IdP (https://idp.example.org).
    • Enter the PEM encoded certificate used by your IdP for signing Shibboleth assertions (the default is $IDP_HOME/credentials/idp.pem).
    • Select the attributes the IdP will be able to release to the federation.
    • Select supported NameID formats. By default, urn:oasis:names:tc:SAML:2.0:nameid-format:transient is already selected.
    • Submit the details and wait for your IdP to be approved.
    • After having your IdP registration approved, click on the link sent to you to become an Administrator of the IdP's registration.

      Confirmation email

      • It is important to click on the link in the confirmation email, as this makes the recipient of the email an administrator of the Identity Provider being registered in the Tuakiri Federation Registry.
        • The link in the confirmation email can only be used once.
        • Same applies for the link sent for the Organization registration.

Advanced IdP Configuration

Enabling automatic reload

To automatically reload a service configuration (such as the attribute-filter.xml file), one has to add two attributes to the service definition: configurationResourcePollingFrequency (in milliseconds) and configurationResourcePollingRetryAttempts.

The change done to /opt/shibboleth-idp/conf/service.xml is thus:

     <srv:Service id="shibboleth.AttributeResolver"
 +             configurationResourcePollingFrequency="PT5.000S" configurationResourcePollingRetryAttempts="10"
              xsi:type="attribute-resolver:ShibbolethAttributeResolver">
         <srv:ConfigurationResource file="/opt/shibboleth-idp/conf/attribute-resolver.xml" xsi:type="resource:FilesystemResource" />
     </srv:Service>
      <srv:Service id="shibboleth.AttributeFilterEngine"
 +             configurationResourcePollingFrequency="PT5.000S" configurationResourcePollingRetryAttempts="10"
              xsi:type="attribute-afp:ShibbolethAttributeFilteringEngine">
         <srv:ConfigurationResource file="/opt/shibboleth-idp/conf/attribute-filter.xml" xsi:type="resource:FilesystemResource" />
     </srv:Service>

and

     <srv:Service id="shibboleth.RelyingPartyConfigurationManager"
 +             configurationResourcePollingFrequency="PT5.000S" configurationResourcePollingRetryAttempts="10"
              xsi:type="relyingParty:SAMLMDRelyingPartyConfigurationManager"
              depends-on="shibboleth.SAML1AttributeAuthority shibboleth.SAML2AttributeAuthority">
         <srv:ConfigurationResource file="/opt/shibboleth-idp/conf/relying-party.xml" xsi:type="resource:FilesystemResource" />
     </srv:Service>

     <srv:Service id="shibboleth.HandlerManager"
 +             configurationResourcePollingFrequency="PT5.000S" configurationResourcePollingRetryAttempts="10"
              depends-on="shibboleth.RelyingPartyConfigurationManager"
              xsi:type="profile:IdPProfileHandlerManager">
         <srv:ConfigurationResource file="/opt/shibboleth-idp/conf/handler.xml" xsi:type="resource:FilesystemResource" />
     </srv:Service>

Load Attribute Filter

This step should be done only after fully registering your IdP into the federation.

To automatically release attributes to new services registered in the federation, we will define inside the AttributeFilterEngine a second ConfigurationResource, loading the data from a remote HTTP URL (backed by a local file) (as documented in Shibboleth documentation on multiple policy group files).

If registering the IdP into multiple federations (such as into Tuakiri and AAF), load the attribute filter for each of the federations according to the respective instructions.

For Tuakiri: please follow the instructions at Configuring a Shibboleth Identity Provider to join the Tuakiri Federation#Configure attribute release/filtering through the federation (this process would provide you with a custom URL to download the metadata from).

  • Contact the federation administrators (by emailing tuakiri@reannz.co.nz) and request a URL for the Attribute Filter for your IdP.
    • In the request, please include:
      • The name (hostname or entityID) of your IdP
      • An email address that should receive notifications whenever the attribute filter changes (these are notifications only, no action will be required).
    • The attribute filter may have to be manually added to the list of attribute filters published. Once created, the URL will have the form of: https://directory.tuakiri.ac.nz/attribute-filter/<institution-domain>.xml

After requesting the attribute filter:


  • Add the following entry into <srv:Service id="shibboleth.AttributeFilterEngine" in $IDP_HOME/conf/service.xml(note that the URL varies for each IdP and has to be obtained from the federation administrators):

            <srv:ConfigurationResource xsi:type="resource:FileBackedHttpResource"
                                  url="https://directory.tuakiri.ac.nz/attribute-filter/<institution-domain>.xml"
                                  file="/opt/shibboleth-idp/conf/tuakiri-attribute-filter.xml" />
    

    Note: if your $IDP_HOME is different from /opt/shibboleth-idp, change the file path in the above snippet accordingly.

    If configuring this in Shibboleth IdP 2.1.x, do not use the srv: namespace prefix - i.e., use just:

            <ConfigurationResource xsi:type="resource:FileBackedHttpResource"
                          url="https://directory.tuakiri.ac.nz/attribute-filter/<institution-domain>.xml"
                          file="/opt/shibboleth-idp/conf/tuakiri-attribute-filter.xml" />
    
    
  • We also strongly recommend you configure your IdP to periodically reload this file - we recommend at 2 hour intervals. This is documented in detail in the IdP Install Manual: Reloading configuration section and Load Attribute Filter sections. The simple step is to add the configurationResourcePollingFrequency="PT2H0M0.000S" and configurationResourcePollingRetryAttempts="10" attributes to the <srv:Service id="shibboleth.AttributeFilterEngine"element. If you already have these attributes set for reloading the local configuration file - with a shorter interval, please adjust them accordingly to 2 hours for the remotely loaded attribute filter:

        <srv:Service id="shibboleth.AttributeFilterEngine"
    +             configurationResourcePollingFrequency="PT2H0M0.000S" configurationResourcePollingRetryAttempts="10"
                 xsi:type="attribute-afp:ShibbolethAttributeFilteringEngine">
    

For both federations, please note:

  • The attribute names used in the download policy file must match the local attribute names. Check that the attribute names in the downloaded attribute filter against their names in existing configuration files:
    • attribute-resolver.xml (attribute definitions, match against the ID in the AttributeDefinition element)
    • attribute-filter.xml (local attribute filter)
    • /opt/uApprove/conf/attribute-list (uApprove attribute list)
  • But please note that no attributes need to be renamed with the Federation Registry as of December 2010.

ECP support

To allow your IdP to be used with the ECP profile (access via non-browser clients) to let your users access ECP-enabled services in the federation:

  • Enable the ECP profile in your DefaultRelyingParty configuration (following https://wiki.shibboleth.net/confluence/display/SHIB2/IdPSAML2ECPProfileConfig): check that your /opt/shibboleth-idp/conf/relying-party.xml contains a definition of rp:ProfileConfiguration xsi:type="saml:SAML2ECPProfile"(and add if not present):

            <rp:ProfileConfiguration xsi:type="saml:SAML2ECPProfile"
                                  signAssertions="always"
                                  includeAttributeStatement="true"/>
    
  • Make sure the ECP handler is enabled: check that /opt/shibboleth-idp/conf/handler.xml contains the following (and add if not present):

        <ph:ProfileHandler xsi:type="ph:SAML2ECP"
            inboundBinding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
            outboundBindingEnumeration="urn:oasis:names:tc:SAML:2.0:bindings:SOAP">
          <ph:RequestPath>/SAML2/SOAP/ECP</ph:RequestPath>
        </ph:ProfileHandler>
    
  • Protect the /idp/profile/SAML2/SOAP/ECP location on your IdP with authentication against your LDAP - add the following (customized for your LDAP server) into /etc/httpd/conf.d/idp.conf:

            <Location /idp/profile/SAML2/SOAP/ECP>
                    AuthType Basic
                    AuthName "Example Institution Shibboleth Identity Provider - ECP profile"
                    AuthzLDAPAuthoritative Off
                    AuthBasicProvider ldap
                    AuthLDAPURL ldap://ldap.example.org/ou=People,dc=example,dc=org?uid
                    AuthLDAPBindDN "cn=read,dc=example,dc=org"
                    AuthLDAPBindPassword "password"
                    Require valid-user
                    # enable this only over SSL -  not needed when defined in the context of a https VirtualHost
                    SSLRequireSSL
            </Location>
    
    • Note: the Apache LDAP module cannot handle LDAP referrals. When connecting to an Active Directory server (which typically includes referrals to other domains in the AD forest in the results), you will need to connect to the Global Catalog at port 3268.

In order for the ECP handler (running as part of the IdP web application inside Tomcat) to receive the REMOTE_USER variable set by Apache, the AJP connector in Tomcat must have the tomcatAuthentication="false" as instructed above.

ECP will not work if the AJP connector is left with the default settings.

ECP is only included in the IdP in the 2.3.x branch and above

Configuring Single Logout

As of version 2.4.0+, the Shibboleth IdP supports at least a minimalist implementation of Single Log Out (SLO)

The Shibboleth IdP (versions 2.4.0+) supports at least a minimalist SLO implementation:

  • It is possible to terminate the session at the IdP, so that no further SP sessions can be established.
  • It is possible to initiate logout at an SP where the user has a current session.  The SP can send an SLO message to the IdP and terminate the session there as well.
  • However, the IdP will not be propagating the SLO to any additional SPs.
  • By default, the SLO message from the SP to the IdP is asynchronous and the flow ends at the IdP Logout page.
  • The IdP Logout page displays the list of SPs the user has accessed from within this IdP session - and informs the user that the only secure way to close all sessions is to close the browser window.
  • It is also possible to do a synchronous SP to IdP SLO flow that redirects back to the SP, where the SP can either display a message confirming the SP and IdP sessions have been terminated, or can redirect the user to an application-level page confirming the successful logout.

Nonetheless, except for the case where the user has established a session with only one SP where the session (including application-level if used) has been successfully terminated, the only reliable way to close all sessions is to close the browser window.  Details on this minimalist implementation are available at https://wiki.shibboleth.net/confluence/display/SHIB2/IdPEnableSLO.

The software side of the SLO implementation comes out of the box on 2.4.0+ installations, however, the following changes must be made.

Step 1: Customize the Logout page.  We have a suitable template (logout.jsp) that:

If you enable Single Logout without branding your Logout page, users utilizing the Logout functionality will see an unflattering page saying: "This logout page is an example and should be customized."

  • Uses wording we deem suitable for use in the Tuakiri environment.
  • Lists services the user has accessed by the ServiceName (from metadata) and the host name (derived from entityId) - instead of just plain displaying the entityId, which would look rather confusing to users.

You still need to further customize the page with:

  • Your institution name (replace all occurrences of "Example University")
  • Your institution logo (you can reuse the logo you are also using for the IdP login screen - just replace the image link "images/dummylogo.png").

Step 2: If you are reusing IdP configuration files created by a version prior to 2.4.0, you will need to update the configuration files to support the Logout handler in conf/handler.xml and in the IdP metadata in metadata/idp-metadata.xml.  Refer to the src/installer/resources/conf-tmpl and src/installer/resources/metadata-tmp directories in the new version installation tree for up to date configuration files - and copy the respective entries from the templates into your configuration files under /opt/shibboleth-idp.

Step 3: Register the following additional endpoints as Single Logout Service in your IdP metadata the Federation Registry, with the following bindings names and URL values (substituting your IdP hostname in the URLs):

BindingURL
urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirecthttps://idp.example.org/idp/profile/SAML2/Redirect/SLO
urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POSThttps://idp.example.org/idp/profile/SAML2/POST/SLO
urn:oasis:names:tc:SAML:2.0:bindings:SOAPhttps://idp.example.org:8443/idp/profile/SAML2/SOAP/SLO

Customization and Branding

Customizing and branding IdP login screen

In a default install, the IdP login screen is displaying the Shibboleth project logo, a default prompt for username and password, and text saying that this screen should be customized. To establish trust with users, this page should at the very least have the proper institution logo and name and the instructions to customize the page should be removed. Each institution may also wish to customize the graphics to match the style of their login pages. The instructions below show how to change the style of the login screen to match the style of the uApprove screen.

The instructions add a bit of functional logic into the login page - instead of displaying just the entityId of the login page, displaying the full name of the service as configured in the metadata (if available), followed by the hostname of the service.

All of the customization has to be done in the Shibboleth installation directory ($SHIB_INST_HOME, in particular to src/main/webapp/login.jsp) - and after any changes, it is necessary to re-deploy the IdP web application (re-run ./install.sh and restart Tomcat).

For reference, see the Shibboleth Login Page customization instructions at https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAuthUserPassLoginPage.

To customize the login screen with your institutional branding:

  • Copy your institution's logo into $SHIB_INST_HOME/src/main/webapp/images/inst_logo.gif (change the filename here and later on as suitable)
  • Edit $SHIB_INST_HOME/src/main/webapp/login.jsp and:
    • Set head->title to "Institution-name Login" (with your institution name)
    • Do the same for the <h1> element (and for formatting purposes, demote this to an <h2> element)
    • Delete the paragraph saying this is a sample login page
    • Change link to the logo image from /images/logo.jpg (Shibboleth logo) to /images/inst_logo.gif (your institution's logo)
    • Nice framing: wrap the whole HTML body in the following DIV element - applying the same style as what the uApprove screen is using:

      <div style="width: 650px; margin-left:auto; margin-right:auto; border-style: solid; border-color: #00247D; border-width: 1px; padding: 10px; text-align: left; ">
    • If suitable, change the phrasing on the login prompt and change the formatting from "<h2>" to just plain paragraphs ("<p>"):

      <p>You are accessing <strong><%= loginContext.getRelyingPartyId() %></strong></p>
      <p>Please login with your YOUR-INSTITUTION username and password.</p>
      

As of Shibboleth IdP 2.3.0 and newer, the default login page now displays not just the service entityID but also the service DisplayName and Description if available in the metadata. This is facilitated through tags from the idpui tag library, documented at the IdPAuthUserPassLoginPage. However, some of the features used by the default login page (like the service logo) are not available in the metadata produced by the Federation Registry, so we still recommend that you customize this page heavily: remove the left/right frame arrangement, and also display the service hostname (extracted from the entityID.

  • Add the following code snippet into login.jsp to construct the hostname:

    <!-- Local extension: display the name of the service -->
    <%!
    String GetHostnameByURI(String uri)
    {
      /* reusing uApprove's Controller.getResourceHost code where I've contributed */
        int i1 = uri.indexOf("//");
        int i2 = uri.indexOf("/", i1+2);
        // LOG.debug("uri received = \"" + uri + "\"");
    
        // return just the sp.example.org component out of https://sp.example.org/shibboleth
        if ( i2 >= 0 )
           uri = uri.substring(i1 + 2, i2);
        else if ( i1 >= 0 )
           uri = uri.substring(i1 + 2);
    
        // return just the sp.example.org component out of urn:mace:federation.org:sp.example.org
        if (uri.indexOf(':')>=0) {
            uri = uri.substring(uri.lastIndexOf(':')+1);
        }
        //LOG.debug("hostname extracted = \"" + uri + "\"");
    
      return uri;
    }
    %>
    
    <!-- getting relying party full name -->
    <%@ page import="edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfigurationManager" %>
    <%@ page import="edu.internet2.middleware.shibboleth.idp.util.HttpServletHelper" %>
    <%@ page import="org.opensaml.util.storage.StorageService" %>
    <%@ page import="edu.internet2.middleware.shibboleth.idp.authn.LoginContext" %>
    <%@ page import="org.opensaml.saml2.metadata.EntityDescriptor" %>
    <%
       StorageService storageService = HttpServletHelper.getStorageService(application);
       LoginContext loginContext = HttpServletHelper.getLoginContext(storageService,application, request);
       String hostname = (loginContext != null ? loginContext.getRelyingPartyId() : null);
       try {
           if (hostname != null) {
               hostname = GetHostnameByURI(loginContext.getRelyingPartyId());
           };
       } catch (Exception e) {
           /* Intentionally ignored:
            * Could not get detailed service name, will display basic name only */
       };
    %>
    

    Note: this snippet uses code from https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAuthUserPassLoginPage as well as code developed for the Tuakiri project.

  • Further edits to login.jsp:
    • Comment out the <div class="rightpane"> section with the right panel.
    • Comment out the opening and closing div tags for loginbox, leftpane and content.

    • Replace the prompt "The web site described to the right has asked you to log in..." with:

                 <p>You are accessing service <strong><idpui:serviceName/><%= (hostname != null ? " at " + hostname : "" ) %></strong><br>
                 <em><idpui:serviceDescription/></em></p>
                 <p>This site has asked you to log in and you have chosen <strong>YOUR-INSTITUTION</strong> as your home institution.<br>
                 Please login with your YOUR-INSTITUTION username and password.</p></p>
      
  • Finally, re-deploy the IdP with:

    cd $SHIB_INST_HOME
    ./install.sh
    service $TOMCAT_NAME restart
    

To see a sample implementation of all of the changes described above, please refer to the attached login-jsp-idp230.diff diff file (or see the older version for IdP 2.2.x: login-jsp-idp220.diff).

Customizing and branding uApprove

The uApprove by default displays "blank branding" (a logo placeholder). Customize this your institution - display the institution logo, and possibly adjust the page style to match local branding policies.

The files to customize are in $SHIB_INST_HOME/src/main/webapp/uApprove. The logo itself (logo.png) is referenced from attribute-release.jsp (and terms-of-use.jsp if used).

  • Backup the original files: header.jsp file:

    cd $SHIB_INST_HOME/src/main/webapp/uApprove
    for I in *.jsp *.css ; do cp $I $I.dist ; done
    
  • Copy your institution logo into $SHIB_INST_HOME/src/main/webapp/uApprove/inst_logo.gif (adjust filename as suitable)
  • Edit $SHIB_INST_HOME/src/main/webapp/uApprove/attribute-release.jsp
    • Replace link to logo placeholder (logo.png) with your institution logo (inst_logo.gif in the above example)

Note also that the explanation message given to the user (for why the user is visiting this application) can be customized in messages/attribute-release.properties inside $SHIB_INST_HOME/lib/uApprove-2.4.1.jar.

  • Rebuild the IdP web application to pick up the uApprove changes and restart Tomcat:

    cd $SHIB_INST_HOME
    ./install.sh
    service $TOMCAT_NAME restart
    

Friendly attribute names

By default, uApprove would be representing attributes by their local alias - which may not provide the best possible user experience. Names like "eduPersonPrincipalName" look quite cryptic to an ordinary user. The metadata syntax allows to provide friendly names (even locale-specific multiple names) in the attribute-resolver.xml file, and uApprove will pick the attribute names from there.

The syntax for specifying the attribute names is:

    <resolver:AttributeDefinition xsi:type="ad:Simple" id="email" sourceAttributeID="mail">
        <resolver:Dependency ref="myLDAP" />
        <resolver:DisplayName xml:lang="en">Email address</resolver:DisplayName>
        <resolver:AttributeEncoder xsi:type="enc:SAML1String" name="urn:mace:dir:attribute-def:mail" />
        <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:0.9.2342.19200300.100.1.3" friendlyName="mail" />
    </resolver:AttributeDefinition>

Add the following attribute descriptions for the respective attributes into attribute-resolver.xml, right between the Dependency and AttributeEncoder elements:

uid:                           <resolver:DisplayName xml:lang="en">Local user ID</resolver:DisplayName>
email:                         <resolver:DisplayName xml:lang="en">Email address</resolver:DisplayName>
commonName:                    <resolver:DisplayName xml:lang="en">Common name</resolver:DisplayName>
surname:                       <resolver:DisplayName xml:lang="en">Surname</resolver:DisplayName>
givenName:	               <resolver:DisplayName xml:lang="en">Given name</resolver:DisplayName>
eduPersonPrincipalName:        <resolver:DisplayName xml:lang="en">Global username (EPPN)</resolver:DisplayName>
displayName:	               <resolver:DisplayName xml:lang="en">Display name</resolver:DisplayName>
organizationName:              <resolver:DisplayName xml:lang="en">Institution name</resolver:DisplayName>
organizationalUnit:            <resolver:DisplayName xml:lang="en">Organisational Unit</resolver:DisplayName>
homeOrganization:              <resolver:DisplayName xml:lang="en">Institution domain</resolver:DisplayName>
homeOrganizationType:          <resolver:DisplayName xml:lang="en">Institution type</resolver:DisplayName>
eduPersonAffiliation:          <resolver:DisplayName xml:lang="en">Affiliation type</resolver:DisplayName>
eduPersonScopedAffiliation:    <resolver:DisplayName xml:lang="en">Affiliation type (with institution)</resolver:DisplayName>
eduPersonPrimaryAffiliation:   <resolver:DisplayName xml:lang="en">Primary affiliation type</resolver:DisplayName>
eduPersonEntitlement:          <resolver:DisplayName xml:lang="en">Entitlements</resolver:DisplayName>
eduPersonAssurance:            <resolver:DisplayName xml:lang="en">Identity assurance level</resolver:DisplayName>
eduPersonTargetedID:           <resolver:DisplayName xml:lang="en">Targeted ID (opaque per-service username)</resolver:DisplayName>
auEduPersonSharedToken:        <resolver:DisplayName xml:lang="en">Shared token</resolver:DisplayName>
auEduPersonLegalName:          <resolver:DisplayName xml:lang="en">Legal name</resolver:DisplayName>
auEduPersonAffiliation         <resolver:DisplayName xml:lang="en">Affiliation type (Australian extensions)</resolver:DisplayName>
postalAddress                  <resolver:DisplayName xml:lang="en">Business postal address</resolver:DisplayName>
telephoneNumber                <resolver:DisplayName xml:lang="en">Business phone number</resolver:DisplayName>
mobileNumber                   <resolver:DisplayName xml:lang="en">Mobile phone number</resolver:DisplayName>

Testing

The best way to test an IdP is to try to log into a Service Provider in the federation.  Tuakiri provides a service specifically designed for this purpose, the Attribute Validator.  The Attribute Validator displays all of the attributes received from the IdP, and in addition to that performs a number of checks to confirm the values are valid.  Tuakiri is running an attribute reflector in both Tuakiri-production and Tuakiri-TEST federations. Both reflectors are running as standalone services at URLs listed below and are requesting all attributes available in the federation - hence, they work very well for testing all the attributes released by your IdP.

The attribute reflector URLs are:

An alternative tool for testing IdP is the Attribute Authority Command Line Interface client - aacli.sh. For a given user TEST_USERNAME, invoke the tool with:

# For Tuakiri Production environment
$SHIB_HOME/bin/aacli.sh --principal $TEST_USERNAME --requester https://attributes.tuakiri.ac.nz/shibboleth
# For Tuakiri Staging environment (Test Federation)
$SHIB_HOME/bin/aacli.sh --principal $TEST_USERNAME --requester https://attributes.test.tuakiri.ac.nz/shibboleth
  • The tool output is the whole set of attributes that would be released for this user to the given user (the Tuakiri Attribute Validator in this case). If testing for another service, pass the entityId of the service in the --requester option.
  • Note that the tool may fail with: ClassNotFoundException: javax.servlet.ServletRequest. To remedy this, link the Tomcat servlet.jar library into $SHIB_HOME/lib (needs to be re-done after each rebuild of the Shibboleth IdP):

    ln -s /usr/share/java/servlet.jar $SHIB_HOME/lib/
  • No labels