Shibboleth Identity Provider 5
Overview
This guide covers the deployment and verification of Shibboleth Identity Provider 5.2.3 on Microsoft Azure using SecureAnyCloud's preconfigured virtual machine image from the Azure Marketplace.
Shibboleth Identity Provider is the SAML 2.0 identity provider used across research and education federations worldwide, and widely in the public sector. It authenticates your users against your own directory and issues signed SAML assertions to the services they sign in to, so a single sign-on works across every service you federate with. It is open source, published under the Apache License 2.0 by the Shibboleth Consortium.
Shibboleth is a registered trademark of Internet2. SecureAnyCloud is not affiliated with, endorsed by, or sponsored by Internet2 or the Shibboleth Consortium. The name is used here only to identify the software this image runs.
Every secret on this image is generated on your own virtual machine, at first boot. That matters more for an identity provider than for almost any other kind of software.
An identity provider signs assertions with a private key, and any service that trusts your identity provider trusts that key. If the key were baked into the image, every customer who deployed it would hold the same one, and any of them could forge assertions for any other.
So this image does not ship an installed identity provider at all. It ships the pinned upstream distribution. Your first boot runs Shibboleth's own installer, which mints this machine's signing key, encryption key, back-channel keystore, sealer keystore and published metadata. Nothing under /opt/shibboleth-idp exists in the image before you launch it.
What you get:
- Shibboleth Identity Provider 5.2.3, released 18 June 2026, installed from the official distribution tarball with its SHA-256 pinned and verified at build time
- Eclipse Jetty 12.1.13 as the servlet container, pinned and verified from Maven Central. Shibboleth 5.2's web application declares Jakarta Servlet 6.1, so it needs a Jakarta EE 11 container. Jetty 12.0 and Tomcat 10.1 are both too old
- OpenJDK 21 LTS from Ubuntu main
- nginx terminating TLS on port 443 with a certificate generated on your machine at first boot
- OpenLDAP as a co-located directory on the loopback interface, holding one test user so you can prove a sign-in works within a minute of the machine booting
- A self-test service provider registered out of the box, and
shibboleth-idp-roundtrip.py, which drives a complete SAML 2.0 sign-in and checks the assertion that comes back - Ubuntu 24.04 LTS, fully patched at build time, with unattended security upgrades enabled
Exposed ports: 22 and 443, and nothing else. The directory listens on 127.0.0.1:389 and Jetty on 127.0.0.1:8080, and neither is reachable from outside the machine. There is deliberately no port 80 listener.
Before you deploy: choose your hostname
A SAML identity provider has an entity ID, and it is a permanent identifier. Every service provider you federate with records it, and the endpoints in your published metadata are built from your hostname. Changing it later means re-keying and re-registering with every service provider you have.
If you already know the DNS name this identity provider will answer on, set it before the first boot by passing cloud-init user data when you create the VM:
#cloud-config write_files: - path: /etc/sac/shibboleth-idp.conf permissions: '0644' content: | IDP_HOSTNAME=idp.example.ac.uk IDP_SCOPE=example.ac.uk IDP_ENTITY_ID=https://idp.example.ac.uk/idp/shibbolethIf you do not, the first boot uses the machine's public IP address for all three, which is fine for evaluation. Step 6 shows how to move to a real hostname afterwards.
IDP_SCOPE is the domain your scoped attributes are suffixed with, for example eduPersonPrincipalName becomes alice@example.ac.uk. It is normally your organisation's domain.
Deploy the Virtual Machine
Option A: Azure Portal
- Sign in to the Azure Portal and choose Create a resource
- Search for Shibboleth Identity Provider 5 on Ubuntu 24.04 LTS by SecureAnyCloud and select it
- Choose your subscription, resource group and region
- Choose a VM size. Standard_B2ms (2 vCPU, 8 GiB) is the recommended minimum, and the Java heap is set to 1280 MB
- Set the administrator username to
azureuserand upload your SSH public key - Under Inbound port rules, allow SSH (22) and HTTPS (443)
- Review and create
Option B: Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:shibboleth-idp-ubuntu-24-04:default:latest
az vm create \
--resource-group my-resource-group \
--name my-shibboleth-idp \
--image sac1647283583153:shibboleth-idp-ubuntu-24-04:default:latest \
--size Standard_B2ms \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard \
--custom-data cloud-init.yaml
# then open the two ports you need
az vm open-port --resource-group my-resource-group --name my-shibboleth-idp --port 443 --priority 900Wait for the first boot to finish
The first boot creates the directory, runs the Shibboleth installer, mints every key and generates your metadata. It takes about a minute. SSH in and confirm it completed:
ssh azureuser@<vm-ip>
sudo test -f /var/lib/sac/data/shibboleth-idp-firstboot.done && echo "first boot complete"Then check the services and the published metadata:
systemctl is-active slapd shibboleth-idp nginx curl -sk -o /dev/null -w '%{http_code}\n' https://localhost/idp/shibbolethExpected output:
active active active 200The details generated for your machine are in a root-only file:
sudo cat /root/shibboleth-idp-credentials.txtIt contains your entity ID, your metadata URL, the directory's administrator distinguished name and password, and the test user's username and password. Keep it on the machine. It is mode 0600 and owned by root.
Prove a user can sign in
The image ships a self test service provider and a prover that drives a complete SAML 2.0 browser sign in against it. Run it:
sudo bash -c 'SAC_IDP_PW="$(sed -n "s/^IDP_TEST_PASSWORD=//p" /root/shibboleth-idp-credentials.txt)" \
python3 /usr/local/sbin/shibboleth-idp-roundtrip.py 127.0.0.1 shibtest'Expected output:
PASS a login form was presented and submitted PASS SAML status is Success urn:oasis:names:tc:SAML:2.0:status:Success PASS an Assertion was issued PASS the response is signed PASS an AuthnStatement is present PASS the Issuer is this IdP https://<your-host>/idp/shibboleth PASS a NameID was issued PASS the audience is the requesting SP https://selftest.sac.local/sp SHIBBOLETH_SAML_LOGIN_OKDo not rely on the exit status alone. Check for the SHIBBOLETH_SAML_LOGIN_OK line. Shibboleth's own aacli exits zero even when it is refused, so this prover follows the same discipline it asks of you: read the output, not the status.
You can also sign in with a browser. Visit:
https://<vm-ip>/idp/profile/SAML2/Unsolicited/SSO?providerId=https://selftest.sac.local/spYour browser will warn about the certificate, because the one generated at first boot is self-signed. Step 6 covers replacing it. Accept the warning and sign in with the test username and password from the credentials file.
The service you are signing in to is the built-in self-test service provider, which is why it is named on the page. After you sign in, the identity provider posts a signed assertion to that service's assertion consumer URL. That URL is on the loopback interface and does not answer, so your browser shows a connection error. This is expected. The assertion was issued, and the prover above is what reads it.
Visit https://<vm-ip>/idp/profile/Logout to end the session. The page lists the services you accessed during it.
Give your metadata to a service provider
A service provider needs your published metadata in order to trust you. The metadata is served, unauthenticated, at:
https://<your-host>/idp/shibbolethcurl -sk https://localhost/idp/shibboleth | head -20It carries your entity ID, your scope, your single sign on endpoints and the signing and encryption certificates minted on this machine.
To register a service provider with your identity provider, add its metadata to conf/metadata-providers.xml. Save the service provider's metadata to a file and add a provider entry before the closing tag:
sudo tee /opt/shibboleth-idp/metadata/my-service.xml >/dev/null <<'EOF' <!-- paste the service provider's EntityDescriptor here --> EOF sudo chown shibboleth:shibboleth /opt/shibboleth-idp/metadata/my-service.xmlThen edit /opt/shibboleth-idp/conf/metadata-providers.xml and add, immediately before the final </MetadataProvider>:
<MetadataProvider id="MyService" xsi:type="FilesystemMetadataProvider" metadataFile="/opt/shibboleth-idp/metadata/my-service.xml"/>Reload the metadata service without restarting:
sudo -u shibboleth /opt/shibboleth-idp/bin/reload-service.sh \
-u http://127.0.0.1:8080/idp -id shibboleth.MetadataResolverServicereload-service.sh defaults to http://localhost/idp, which is port 80, and this image does not listen on port 80. Pass -u pointing at Jetty on the loopback interface instead. That also avoids the script having to trust the self-signed certificate.
For a federation, use an HTTPMetadataProvider with a SignatureValidationFilter pointing at your federation's signing certificate instead. Never trust remote metadata without validating its signature.
Remove the self-test service provider
Once your own service providers are registered, remove the self-test one. It exists only so the machine can prove itself on first boot:
sudo rm /opt/shibboleth-idp/metadata/sac-selftest-sp.xmlThen delete the SacSelfTestSP entries from conf/metadata-providers.xml and conf/relying-party.xml, and restart:
sudo systemctl restart shibboleth-idpPoint the identity provider at your own directory
The image ships OpenLDAP on 127.0.0.1:389 with one test user, so the machine works out of the box. In production you will point it at your own directory instead.
Edit /opt/shibboleth-idp/conf/ldap.properties as the shibboleth user. Set your own server, base DN and bind account, and turn StartTLS back on. It is disabled here only because the shipped directory is on the loopback interface:
idp.authn.LDAP.authenticator = bindSearchAuthenticator idp.authn.LDAP.ldapURL = ldaps://ldap.example.ac.uk:636 idp.authn.LDAP.useStartTLS = false idp.authn.LDAP.baseDN = ou=people,dc=example,dc=ac,dc=uk idp.authn.LDAP.userFilter = (uid={user}) idp.authn.LDAP.bindDN = cn=shibboleth,ou=services,dc=example,dc=ac,dc=uk idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crtThe bind password goes in idp.authn.LDAP.bindDNCredential inside /opt/shibboleth-idp/credentials/secrets.properties, never in ldap.properties. Restart once both files are in place:
sudo systemctl restart shibboleth-idpOnce your own directory is in use, stop and disable the local one:
sudo systemctl disable --now slapdProduction hardening
Replace the self-signed TLS certificate
The certificate generated at first boot is self-signed. Replace both files with your own, keeping the paths:
sudo install -m 0644 -o root -g root fullchain.pem /etc/sac/tls/idp.crt
sudo install -m 0640 -o root -g www-data privkey.pem /etc/sac/tls/idp.key
sudo nginx -t && sudo systemctl reload nginxThis certificate is for browsers only. It is deliberately unrelated to the identity provider's own signing and encryption keys, which are never used for TLS.
Move to a real hostname
If you deployed without setting a hostname and now want a real one, the entity ID and every endpoint in your metadata must change, so re-run the installer. Do this before you register with any service provider. Afterwards it means re-registering with all of them.
sudo systemctl stop shibboleth-idp
sudo tee /etc/sac/shibboleth-idp.conf >/dev/null <<'EOF' IDP_HOSTNAME=idp.example.ac.uk IDP_SCOPE=example.ac.uk IDP_ENTITY_ID=https://idp.example.ac.uk/idp/shibboleth EOF
sudo rm -f /var/lib/sac/data/shibboleth-idp-firstboot.done
sudo /usr/local/sbin/shibboleth-idp-firstboot.sh
sudo systemctl start shibboleth-idpThis mints a completely new key set and new metadata. Anyone who already trusts the old keys must be given the new metadata.
Administrative endpoints
Shibboleth's administrative endpoints under /idp/profile/admin/ are gated only by an IP access control policy that trusts the loopback address. resolvertest discloses a user's resolved attributes and dumpconfig discloses configuration. This image therefore refuses them at nginx outright.
It also sets X-Forwarded-For from the real client address rather than appending to whatever the caller sent. Without that, a remote caller could send X-Forwarded-For: 127.0.0.1 and be read as loopback.
To use them, run them on the machine itself against Jetty directly:
curl -s "http://127.0.0.1:8080/idp/profile/admin/resolvertest?requester=https://selftest.sac.local/sp&principal=shibtest"/idp/status remains reachable over HTTPS, but the identity provider's own policy allows it only from the loopback address. A remote request therefore receives 403.
Branding the sign-in pages
The sign-in and sign-out pages are plain by design. The upstream sample logo, footer text and dead help links are removed at first boot. Add your own in /opt/shibboleth-idp/messages/messages.properties:
idp.logo = /images/my-logo.png idp.logo.alt-text = Example University idp.footer = Contact the IT Service Desk on 0123 456 7890. idp.url.password.reset = https://accounts.example.ac.uk/reset idp.url.helpdesk = https://help.example.ac.uk/Put the image in /opt/shibboleth-idp/edit-webapp/images/, then rebuild the web application and restart:
sudo -u shibboleth /opt/shibboleth-idp/bin/build.sh
sudo systemctl restart shibboleth-idpMonitoring and patching
/idp/status reports the version, uptime and enabled modules:
curl -sk https://localhost/idp/status | head -12nginx serves an unauthenticated health endpoint for load balancer probes:
curl -sk https://localhost/healthzLogs are in /opt/shibboleth-idp/logs/: idp-process.log for the identity provider, idp-warn.log for warnings and errors, and idp-audit.log for one line per authentication.
Ubuntu security updates are applied automatically by unattended-upgrades. Apply everything and reboot on your own schedule:
sudo apt-get update && sudo apt-get -y dist-upgrade
sudo rebootShibboleth releases are separate from the operating system. Watch the Shibboleth announce list and upgrade with bin/update.sh from a newer distribution when one is published.
Troubleshooting
Sign-in is refused for a user you know exists. Check idp-warn.log and confirm the user is under the configured base DN and that the bind account can search for them:
sudo tail -30 /opt/shibboleth-idp/logs/idp-warn.log
sudo ldapsearch -x -H ldap://127.0.0.1:389 -b "ou=people,dc=sac,dc=local" "(uid=shibtest)" dnA service provider rejects your assertion. The cause is almost always stale metadata, or a hostname that changed after you gave the metadata to the service provider. Compare the certificate it has against the one you publish now:
curl -sk https://localhost/idp/shibboleth | grep -o 'entityID="[^"]*"'
sudo openssl x509 -in /opt/shibboleth-idp/credentials/idp-signing.crt -noout -fingerprint -sha256The identity provider will not start after you rotated a key by hand. Rotating the sealer or the back-channel keystore without updating credentials/secrets.properties fails at start-up with a DataSealerKeyStrategy error rather than an obvious wrong-password message. Re-run the first-boot script from Step 6 instead of rotating keys individually.
/idp/status returns 403 from your laptop. This is correct. The policy allows the loopback address only, so run it on the machine.
Support
SecureAnyCloud provides 24/7 support for this image. Raise a ticket at secureanycloud.com with your Azure subscription ID and the output of:
sudo systemctl is-active slapd shibboleth-idp nginx
sudo tail -40 /opt/shibboleth-idp/logs/idp-warn.logSupport covers the image, its configuration and its deployment. Questions about SAML federation policy belong with your federation operator, and Shibboleth software questions with the Shibboleth community lists.
Licence
Shibboleth Identity Provider is published under the Apache License, Version 2.0. The licence text ships on the image, copied from the distribution at build time:
cat /usr/share/doc/shibboleth-idp/LICENSE.txt | head -3Third party component licences from the distribution are alongside it in the same directory. Shibboleth is a registered trademark of Internet2. SecureAnyCloud is not affiliated with Internet2 or the Shibboleth Consortium, and this image does not use the Shibboleth logo.
Deploy on Azure
Launch Shibboleth Identity Provider 5 on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com