EMERSE   EMERSE Website   Documentation Documentation

Overview

This guide outlines the configuration of Shibboleth, a single sign-on login system, and its integration with EMERSE. Setting up EMERSE with Tomcat and Httpd is out of the scope of this section, please refer to Installation Guide and More for details.

Background

Single sign-on (SSO) is an authentication process that allows users to access multiple applications or systems with just one set of login credentials (such as username and password). Instead of requiring users to remember and enter separate login credentials for each application, SSO enables them to authenticate once and then seamlessly access various resources without needing to re-enter their credentials.

EMERSE 6.6 and subsequent versions provide Single Sign-On (SSO) support via integration with an SSO provider, such as Shibboleth. The instructions in this document assume the setup of Shibboleth on Red Hat Enterprise Linux 8.9 with Apache HTTPD and Tomcat 9.X with AJP protocol.

Installation

Shibboleth

The easiest way to install Shibboleth on RHEL is through RPM installation. This can be done on RHEL by creating a new configuration file for Shibboleth RPM repository. For RHEL 8.9, here is an example

name=Shibboleth (CentOS_8)
# Please report any problems to https://shibboleth.atlassian.net/jira
type=rpm-md
mirrorlist=https://shibboleth.net/cgi-bin/mirrorlist.cgi/CentOS_8
gpgcheck=1
gpgkey=https://shibboleth.net/downloads/service-provider/RPMS/repomd.xml.key
        https://shibboleth.net/downloads/service-provider/RPMS/cantor.repomd.xml.key
enabled=1

If the target OS is different, please using the link to generate this shibboleth.repo file.

On RHEL 8.9, this file shall be saved at:

/etc/yum.repos.d/

Once the repository configuration is done, installing Shibboleth can be done by:

yum install shibboleth.x86_64
  • Shibboleth configuration files will be placed at /etc/shibboleth and the necessary Apache configuration in /etc/httpd/conf.d/shib.conf

  • shibd will be installed to /usr/sbin and may be managed using service and chkconfig (on System V platforms) or with systemctl (on systemd platforms, some additional information available).

  • An version of mod_shib.so appropriate to the OS-supplied Apache and other pluggable modules will be installed to /usr/lib64/shibboleth on a 64-bit OS.

Apache HTTPD and Tomcat

Please follow instructions in the EMERSE installation guide. Make sure HTTPD is configured with strong encryption using the Secure Sockets Layer and Transport Layer Security protocols (SSL/TLS).

Configuration

Shibboleth

SP vs IdP

Service Provider (SP): The Service Provider is the system or application that offers services to users. It’s the entity that users interact with to access resources, such as web applications, services, or APIs. The SP relies on authentication and authorization mechanisms provided by the Identity Provider (IdP) to verify user identities and grant access to its services.

Identity Provider (IdP): The Identity Provider is responsible for authenticating users and providing identity information to service providers. It verifies the user’s identity based on credentials provided by the user, such as usernames and passwords, or using other authentication methods like multi-factor authentication (MFA). Once the user is authenticated, the IdP generates a security token containing identity information (such as user attributes or roles) and sends it to the SP, allowing the user to access the SP’s resources without needing to re-authenticate.

In summary, the SP provides services, while the IdP authenticates users and provides identity information to SPs, enabling seamless access to multiple services with a single authentication event.

PEM files

There are four existing PEM files in /etc/shibboleth after installation: sp-encrypt-key.pem, sp-signing-key.pem, sp-encrypt-cert.pem, and sp-signing-cert.pem. They represent the public-private key pairs of this application server. The first two key PEM files should be identical to the HTTPD’s SSL Certificate Key file. The last two cert PEM files should match the HTTPD’s SSL Certificate file.

To establish communication with the Identity Provider (IdP), Shibboleth requires a copy of the IdP’s certificate. This file should be placed within the /etc/shibboleth directory. In this document, the designated name for this PEM file is preprod-idp.pem.

attribute-map.xml

In Shibboleth, the attribute-map.xml file is used to define mappings between attributes received from an Identity Provider (IdP) and attributes understood by the Service Provider (SP). This file essentially acts as a configuration file that helps in standardizing attribute names and formats, making attribute handling more manageable.

EMERSE configured with Tomcat/AJP expects REMOTE_USER is available in the header if HTTPD is the reversed proxy.

Here is an example of attribute-map.xml

<Attributes xmlns="urn:mace:shibboleth:2.0:attribute-map" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <Attribute name="surname" id="surname"/>
  <Attribute name="displayname" id="displayname"/>
  <Attribute name="uniquename" id="uniquename"/>
  <Attribute name="email" id="email"/>

</Attributes>

uniquename will be specified as the value for REMOTE_USER in shibboleth2.xml

shibboleth2.xml

shibboleth2.xml is a configuration file used by the Shibboleth Service Provider (SP) software, which is part of the Shibboleth System.

The shibboleth2.xml file contains configuration settings that control how the Shibboleth SP interacts with identity providers (IdPs), processes authentication requests, and handles attributes exchanged during the authentication process.

The detailed configuration of shibboleth2.xml is beyond the scope of this document. Only essential components will be addressed herein.

In the ApplicationDefaults tag, the following parameters will be defined.

  • entityID: the root path of Shibboleth

  • REMOTE_USER: the remote user name which shall be mapped from IdP attributes defined in attribute-map.xml, which is specified in the AttributeExtractor tag in shibboleth2.xml

  • SSO IdP entityID: the IdP’s SSO metadata url

  • supportContact: an email that will receive error notification

  • MetadataProvider: Information about IdP metadata provider, these info include remote IdP url and certificate file, which is mentioned in the earlier section as preprod-idp.pem

Any section that is not mentioned is kept as default. Here is an example of shibbolth2.xml. This configuration assumes EMERSE and Shibboleth have been installed on the same server.

<SPConfig xmlns="urn:mace:shibboleth:3.0:native:sp:config"
    xmlns:conf="urn:mace:shibboleth:3.0:native:sp:config"
    clockSkew="180">

    <OutOfProcess tranLogFormat="%u|%s|%IDP|%i|%ac|%t|%attr|%n|%b|%E|%S|%SS|%L|%UA|%a" />

    <ApplicationDefaults entityID="https://MY_EMERSE_SERVER/shibboleth"
        REMOTE_USER="uniquename"
        cipherSuites="DEFAULT:!EXP:!LOW:!aNULL:!eNULL:!DES:!IDEA:!SEED:!RC4:!3DES:!kRSA:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1">

        <Sessions lifetime="28800" timeout="3600" relayState="ss:mem"
                  checkAddress="false" handlerSSL="true" cookieProps="https"
                  redirectLimit="exact">
            <SSO entityID="https://MY_IDP_SERVER/idp/saml2/metadata"
                 discoveryProtocol="SAMLDS" discoveryURL="https://ds.example.org/DS/WAYF">
              SAML2
            </SSO>
            <Logout>SAML2 Local</Logout>
            <LogoutInitiator type="Admin" Location="/Logout/Admin" acl="127.0.0.1 ::1" />
            <Handler type="MetadataGenerator" Location="/Metadata" signing="false"/>
            <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="MY_EMAIL@my.email"
            helpLocation="/about.html"
            styleSheet="/shibboleth-sp/main.css"/>
        <MetadataProvider type="XML" validate="true" url="https://MY_IDP_SERVER/idp/saml2/metadata" reloadInterval="7200">
            <MetadataFilter type="Signature">
                <CredentialResolver type="Chaining">
                <CredentialResolver type="File" certificate="preprod-idp.pem"/>
                </CredentialResolver>
            </MetadataFilter>
        </MetadataProvider>
        <AttributeExtractor type="XML" validate="true" reloadChanges="false" path="attribute-map.xml"/>
        <AttributeFilter type="XML" validate="true" path="attribute-policy.xml"/>
<CredentialResolver type="File" use="signing"
            key="sp-signing-key.pem" certificate="sp-signing-cert.pem"/>
        <CredentialResolver type="File" use="encryption"
            key="sp-encrypt-key.pem" certificate="sp-encrypt-cert.pem"/>
    </ApplicationDefaults>
    <SecurityPolicyProvider type="XML" validate="true" path="security-policy.xml"/>
    <ProtocolProvider type="XML" validate="true" reloadChanges="false" path="protocols.xml"/>
</SPConfig>

Shibboleth OS User

Shibboleth through RPM installation is running as a system service in RHEL with name shibd.service under OS user shibboleth. This can be verified using the command:

systemctl cat shibd

the output may look like:

# /usr/lib/systemd/system/shibd.service
[Unit]
Description=Shibboleth Service Provider Daemon
Documentation=https://wiki.shibboleth.net/confluence/display/SP3/Home
After=network-online.target
Before=httpd.service

[Service]
Type=notify
NotifyAccess=main
User=shibboleth
ExecStart=/usr/sbin/shibd -f -F
StandardInput=null
StandardOutput=null
StandardError=journal
TimeoutStopSec=1m
TimeoutStartSec=5m
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=multi-user.target

For security reason, an institution may disable creating new local level OS users. In this situation, shibd.service’s user should be reset to the available local user, for example `daemon, under Service section, in shibd.service file.

If the user is reset to daemon, make sure it owns the following folders:

  • /var/run/shibboleth

  • /var/log/shibboleth

And can read everything under /etc/shibboleth, especially the private key, PEM files.

Shibboleth service can be started by:

systemctl start shibd

If everything setup correctly, one should be able to reach the metadata page by:

HTTPD Integration

Under /etc/httpd/conf.d, there is Shibboleth’s configuration file shib.conf. Adding the following section for EMERSE if the application is served under https://EMERSE_WEB_SERVER/emerse/:

<Location "/emerse/">
  AuthType shibboleth
  ShibRequestSetting requireSession 0
  require shibboleth
</Location>

HTTPD has to be restarted after the configuration.

Tomcat Integration

In server.xml, the following AJP section is needed:

<Connector
                    protocol="AJP/1.3"
                    port="MY_AJP_PORT"
                    secret="MY_SECRET"
                    tomcatAuthentication="false"
                    />

EMERSE Configuration

In order to switch EMERSE using SSO, the preauth profile needs to be activated.

Here is an example of context.xml file for EMERSE

<Context>
  <Environment name="emerse.properties.filepath"
               value="/MY_EMERSE_PROP_FOLDER/emerse.properties"
               type="java.lang.String"/>
  <Environment name="spring.profiles.active"
               value="ldap,no-scheduler,api,preauth"
               type="java.lang.String"/>
</Context>

preauth.loginUrl is required in emerse.properties file

preauth.loginUrl=https://MY_EMERSE_SERVER/Shibboleth.sso/Login?target=EMERSE_REDIRECT_TARGET

This helps EMERSE understand the possible redirect route inside EMERSE application.

Troublshooting

If you encounter errors when configuring shibboleth, it can be helpful to have an idea of where the issue lies. There are a few things you can check that should tell you whether shibboleth, httpd, tomcat, or EMERSE is to blame for the problem.

The login page doesn’t redirect to the IdP login page

You need to set the preauth.loginUrl in the emerse.properties file. If this is set, then the login page should change so that only the login button appears without a username or password entry. This login button will redirect the browser to the given url. That URL should be then redirect to the IdP beginning the SSO flow. See here.

If you are expecting to see the IdP page before seeing any page served from the EMRESE app, then you need to change the httpd configuration to force auth earlier. We aren’t familiar on how to set up this use case, but it will probably involve changing the require shibboleth line to require valid-user, but check with the shibboleth documentation here.

The SSO login flow starts but has an error

This is probably an issue with the shibboleth configuration, such as public/private keys. It could be a lot of things, so we can’t offer a lot of help here, but it would probably be between the /etc/shibboleth/ configuration and the IdP’s configuration. You may need to restart shibd or httpd for changes to take effect.

The SSO login flow seems successful, but EMERSE shows the login page even after logging in.

Either HTTPD isn’t ending up with an authenticated user, or it isn’t passing it to tomcat, or tomcat is discarding it dispatching the request to EMERSE, or EMERSE isn’t looking in the right place for the user name, or the username sent from HTTPD / the IdP doesn’t match exactly with the user id in the LOGIN_ACCOUNT table.

First, you can check httpd’s access_log to see if it has a username for requests to EMERSE. This file is probably located at /etc/httpd/logs/access_log or var/log/httpd/access_log or somewhere similar. Lines by default should look like:

10.60.2.219 - USERNAME [07/Aug/2024:15:01:54 -0400] "GET /emerse/springmvc/search/spellcheck?input=someword HTTP/1.1" 200 28 "https://emerse.med.umich.edu/emerse/terms/temporary/terms" "Mozilla/5.0 (W

The third item on the line is the authenticated username of the request. This will appear as "" if there is no such username. If you notice this name doesn’t match the a user id in the LOGIN_ACCOUNT table in emerse (including case) then try changing the user id in EMERSE (or creating an new account) to see if login works. If requests after login has been done successfully still don’t have a username here, then there is an issue within httpd or between httpd and shibd daemon where the authentication information isn’t being consumed by httpd. Hard to say what’s going wrong there.

If the login name does appear in the httpd access_log, but it’s not the one you want, change the (or add a) REMOTE_USER attribute on the <ApplicationDefaults> element in the /etc/shibboleth/shibboleth.xml file, and restart shibd and httpd. Be sure the attribute you want is included in the /etc/shibboleth/attribute-map.xml file as it can’t use a value it doesn’t fetch from the IdP. You may need to reconfigure the IdP or re-generated the SP metadata and re-import it into the IdP so that the correct attributes are passed.

If httpd has the right username, then we can check to see if it’s sending it to EMERSE. For this, we will sniff the TCP packets being sent to tomcat, which requires the tcpdump command and root access typically. First, we need to get the name of the loopback device, which is typically lo on linux. However, you can check by doing a ip addr and looking for the entry that mentions localhost, loopback, or the ip 127.0.0.1. If ip addr doesn’t work, try ifconfig (the older command). Once you have that, issue the below tcpdump command with the loopback device name, and the port tomcat’s listening on for AJP requests. That’s the port in the conf/server.xml file for the AJP connector you configured above. It’s typically 8009, but we listed it as MY_AJP_PORT in the documentation above.

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:25:b5:01:00:78 brd ff:ff:ff:ff:ff:ff
    altname eno5
    altname enp27s0f2
    altname ens6f2
    inet 172.20.66.43/23 brd 172.20.67.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
$ sudo tcpdump -i lo -A tcp port 8009

The tcp dump command will hang until you kill it with control-C. As it hangs, it will print any packets seen on the port. This could be a lot of text if you have a lot of traffic or none. While this command is running, do the login flow until you think you should be logged in, and then look through the mess of packet text for your username. Obviously requests before authentication is done won’t have your authenticated username on them, so you’re looking for roughly the last request you made. So, this is best done when there is little to no traffic. AJP is a binary protocol, but must of the data its carrying is text. Requests start with the URL requests, then some header information, and shortly after that will be AJP secret configured in the httpd config file and also in the AJP connector in Tomcat, and right after that is the authenticated username, if present. Most of the periods in the output signify non-printable characters. See below for an example:

.+OI.+O:.4......HTTP/1.1.../emerse/springmvc/attestations...10.60.98.141.....emerse.med.umich.edu..........emerse.med.umich.edu....TMozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0....!application/json, text/plain, */*.....en-US,en;q=0.5.....gzip, deflate, br, zstd....
keep-alive....$https://emerse.med.umich.edu/emerse/..	.\JSESSIONID=0D56EA25A6E08392D64B6A84894D8413; MANY MORE COOKIES...Sec-Fetch-Dest...empty...Sec-Fetch-Mode...cors...Sec-Fetch-Site...same-origin....HERE IS YOUR AJP SECRET....THIS IS WHERE THE USERNAME WILL APPEAR...
shibboleth....TLS_AES_128_GCM_SHA256.	.@dbf65fbb862de02c19899e1ff0d7e325ec43b716aebfde2a5c51c07fefe67cb3....
..AJP_SSL_PROTOCOL...TLSv1.3.
..AJP_REMOTE_PORT...58926.
..AJP_LOCAL_ADDR...172.20.66.43..

If you see the username in the request, the problem lies in tomcat or EMERSE. Otherwise, in HTTPd. I’m not sure what would cause HTTPd to not pass the username if it’s already logging it in its own access_log, but I would look at the proxy pass rules or other auth-based commands in the configuration file.

If it is being passed, then make sure tomcat’s conf/server.xml has the tomcatAuthentication attribute set to false on the AJP connector element, possibly all connector elements. If it isn’t, Tomcat discards the authenticated username sent on AJP. Really, this file should be able to be replaced with exactly this (except for the AJP secret):

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>


  <Service name="Catalina">
    <Connector
	protocol="AJP/1.3"
	port="8009"
	secret="MY_SECRET"
	tomcatAuthentication="false"
	/>
    <Engine name="Catalina" defaultHost="localhost">
      <Host name="localhost" appBase="webapps"
	    unpackWARs="true" autoDeploy="true">
	<Valve className="org.apache.catalina.valves.ErrorReportValve"
	       showReport="false"
	       showServerInfo="false"/>
	<Valve className="org.apache.catalina.valves.AccessLogValve"
	       directory="logs" maxDays="180"
	       prefix="localhost_access_log" suffix=".txt"
	       pattern="%h %l %u %t &quot;%r&quot; %s %b"/>
      </Host>
    </Engine>
  </Service>
</Server>

Tomcat has a lot of commented out stuff by default which is nice for documentation, but sometimes it’s more clear to only include what’s actually being used, and properly deleting everything else.

If this all looks correct, then make sure EMERSE has preauth enabled as a spring profile. This means the spring preauth should be part of the value of the spring.profiles.active property. EMERSE looks in a few places for configuration, so read through the documentation on that and check the various places. Only the "most siginifcant" definition of the spring.profiles.active property is used, so if there are multiple definitions, it’s probably best to consolodate them into one so it’s less confusing.

Rather than logging at static files to see how things are configured, it can be helpful to look directly at the process itself to see how it ended up getting run. This can sometimes find issues where you thing one thing is happening but another thing is actually happing. You can see what the exact commandline of the running tomcat process is by doing ps ax | grep tomcat This alows you to see what the java properties are, as these are parameters to the program; options starting with -Dname=value define the java property name to have value value.

To check envirnoment variables of a running process, get the PID of the running process, which is the first number on the line output by the that ps ax | grep tomcat command, then look at cat /proc/PID/environ where PID is the PID of the process. This will list environment variables in the form name=value separated by binary zeros. (Yes, that’s an nonprintable character so they kinda run together as seen on the console.) /proc/PID/environ is on the "proc" file system, which is not a real file system; reading from these "files" actually causes the OS to query the current state of the associated process. You typically have to be root to read these files, or ower of the process. Not all editions/configurations of linux use the proc file system, so you may not have it.

If you still have trouble getting SSO to work, you can contact us.