- Requirements
- Software that will be installed
- Install Instructions
- Configuration Instructions
- Configure Jetty
- Configure SSL on Apache2 (front-end of Jetty)
- Configure Shibboleth Identity Provider Storage
- Configure the Directory (openLDAP or AD) Connection
- Configure Shibboleth Identity Provider to release the persistent NameID
- Configure the attribute resolver (sample)
- Configure Shibboleth Identity Provider to release the eduPersonTargetedID
- Configure the attribute resolution with Attribute Registry
- Configure Shibboleth IdP Logging
- Translate IdP messages into the preferred language
- Disable SAML1 Deprecated Protocol
- Secure cookies and other IDP data
- Configure Attribute Filter Policy to release attributes to Federated Resources
- Register the IdP on the IDEM Test Federation
- Appendix A: Import persistent-id from a previous database
- Appendix B: Useful logs to find problems
- Utilities
- Useful Documentation
- Authors
- CPU: 2 Core (64 bit)
- RAM: 4 GB
- HDD: 20 GB
- OS: Centos 7, Centos 8
- SSL Credentials: HTTPS Certificate & Key
- Logo:
- size: 80x60 px (or other that respect the aspect-ratio)
- format: PNG
- Favicon:
- size: 16x16 px (or other that respect the aspect-ratio)
- format: PNG
- ca-certificates
- chrony
- vim
- Amazon Corretto 11 JDK
- jetty 9.4.x
- apache2 (>= 2.4)
- openssl
- tar
- wget
- mariadb-server (if JPAStorageService is used)
- mysql-connector-java (if JPAStorageService is used)
- apache-commons-dbcp (if JPAStorageService is used)
-
Become ROOT:
sudo su -
-
Update packages:
yum update ; yum upgrade -y
-
Install the packages required:
yum install -y vim wget openssl httpd chrony mod_ssl tar openldap-clients
-
Install Amazon Corretto JDK:
rpm --import https://yum.corretto.aws/corretto.key
wget https://yum.corretto.aws/corretto.repo -O /etc/yum.repos.d/corretto.repo
yum install -y java-11-amazon-corretto-devel
-
Check that Amanzon Corretto JDK is installed and selected:
java -version
update-alternatives --config java
(press [Enter] to leave settings unchanged)
-
Activate Chrony:
systemctl enable chronyd
date
-
Configure the Timezone to "Europe/Rome":
timedatectl set-timezone Europe/Rome
-
Become ROOT:
sudo su -
-
Be sure that your firewall is not blocking the traffic on port 443 and 80.
-
Set the IdP hostname:
-
vim /etc/hosts
<YOUR SERVER IP ADDRESS> idp.example.org <HOSTNAME>
-
hostnamectl set-hostname <HOSTNAME>
(Replace
idp.example.org
with your IdP Full Qualified Domain Name and<HOSTNAME>
with the IdP hostname)
-
-
Set the variable
JAVA_HOME
for the entire environment:echo export JAVA_HOME=/usr/lib/jvm/java > /etc/profile.d/javaenv.sh
chmod 0755 /etc/profile.d/javaenv.sh
The Identity Provider (IdP) is responsible for user authentication and providing user information to the Service Provider (SP). It is located at the home organization, which is the organization which maintains the user's account. It is a Java Web Application that can be deployed with its WAR file.
-
Become ROOT:
sudo su -
-
Download the Shibboleth Identity Provider v4.x.y (replace '4.x.y' with the latest version found here):
cd /usr/local/src
wget http://shibboleth.net/downloads/identity-provider/4.x.y/shibboleth-identity-provider-4.x.y.tar.gz
tar -xzf shibboleth-identity-provider-4.x.y.tar.gz
-
Run the installer
install.sh
:According to NSA and NIST, RSA with 3072 bit-modulus is the minimum to protect up to TOP SECRET over than 2030.
-
cd /usr/local/src/shibboleth-identity-provider-4.x.y/bin
-
bash install.sh -Didp.host.name=$(hostname -f) -Didp.keysize=3072
Buildfile: /usr/local/src/shibboleth-identity-provider-4.x.y/bin/build.xml install: Source (Distribution) Directory (press <enter> to accept default): [/usr/local/src/shibboleth-identity-provider-4.x.y] ? Installation Directory: [/opt/shibboleth-idp] ? Backchannel PKCS12 Password: ###PASSWORD-FOR-BACKCHANNEL### Re-enter password: ###PASSWORD-FOR-BACKCHANNEL### Cookie Encryption Key Password: ###PASSWORD-FOR-COOKIE-ENCRYPTION### Re-enter password: ###PASSWORD-FOR-COOKIE-ENCRYPTION### SAML EntityID: [https://idp.example.org/idp/shibboleth] ? Attribute Scope: [example.org] ?
By starting from this point the variable idp.home refers to the directory:
/opt/shibboleth-idp
Backup the###PASSWORD-FOR-BACKCHANNEL###
value somewhere to be able to find it when you need it. The###PASSWORD-FOR-COOKIE-ENCRYPTION###
will be saved into/opt/shibboleth-idp/credentials/secrets.properties
asidp.sealer.storePassword
andidp.sealer.keyPassword
value.
-
Jetty is a Web server and a Java Servlet container. It will be used to run the IdP application through its WAR file.
-
Become ROOT:
sudo su -
-
Download and Extract Jetty:
cd /usr/local/src wget https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.4.33.v20201020/jetty-distribution-9.4.33.v20201020.tar.gz tar xzvf jetty-distribution-9.4.33.v20201020.tar.gz
-
Create the
jetty-src
folder as a symbolic link. It will be useful for future Jetty updates:ln -nsf jetty-distribution-9.4.33.v20201020 jetty-src
-
Create the user/group
jetty
that can run the web server:useradd --system --home-dir /usr/local/src/jetty-src --user-group jetty
-
Create your custom Jetty configuration that overrides the default one and will survive upgrades:
mkdir /opt/jetty
wget https://registry.idem.garr.it/idem-conf/shibboleth/IDP4/jetty/start.ini -O /opt/jetty/start.ini
-
Create the TMPDIR directory used by Jetty:
mkdir /opt/jetty/tmp ; chown jetty:jetty /opt/jetty/tmp
chown -R jetty:jetty /opt/jetty/ /usr/local/src/jetty-src/
-
Create the Jetty Log's folder:
mkdir /var/log/jetty
mkdir /opt/jetty/logs
chown jetty:jetty /var/log/jetty/ /opt/jetty/logs/
-
Configure /etc/default/jetty:
-
vim /etc/default/jetty
JETTY_HOME=/usr/local/src/jetty-src JETTY_BASE=/opt/jetty JETTY_USER=jetty JETTY_START_LOG=/var/log/jetty/start.log TMPDIR=/opt/jetty/tmp
-
-
Create the service loadable from command line:
cd /etc/init.d
ln -s /usr/local/src/jetty-src/bin/jetty.sh jetty
chkconfig --add jetty
systemctl enable jetty
-
Check if all settings are OK:
systemctl check jetty
(inactive)systemctl start jetty
systemctl check jetty
(active)
(If you receive an error likes "Job for jetty.service failed because the control process exited with error code. See "systemctl status jetty.service" and "journalctl -xe" for details.", try this:
rm /var/run/jetty/jetty.pid
service jetty start
-
Become ROOT:
sudo su -
-
Configure IdP Context Descriptor
-
mkdir /opt/jetty/webapps
-
vim /opt/jetty/webapps/idp.xml
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="war"><SystemProperty name="idp.home"/>/war/idp.war</Set> <Set name="contextPath">/idp</Set> <Set name="extractWAR">false</Set> <Set name="copyWebDir">false</Set> <Set name="copyWebInf">true</Set> <Set name="persistTempDirectory">false</Set> </Configure>
-
-
Make the jetty user owner of IdP main directories:
cd /opt/shibboleth-idp
chown -R jetty logs/ metadata/ credentials/ conf/ system/ war/
-
Restart Jetty:
systemctl restart jetty.service
-
Check IdP Status:
bash /opt/shibboleth-idp/bin/status.sh
The Apache HTTP Server will be configured as a reverse proxy and it will be used for SSL offloading.
-
Create the DocumentRoot:
mkdir /var/www/html/$(hostname -f)
sudo chown -R apache: /var/www/html/$(hostname -f)
-
Create the Virtualhost file (pay attention and follow the starting comment):
-
wget https://registry.idem.garr.it/idem-conf/shibboleth/IDP4/apache2/idp.example.org.conf -O /etc/httpd/conf.d/$(hostname -f).conf
-
-
Put SSL credentials in the right place:
- HTTPS Server Certificate (Public Key) inside
/etc/pki/tls/certs
- HTTPS Server Key (Private Key) inside
/etc/pki/tls/private
- Add CA Cert into
/etc/pki/tls/certs
- If you use GARR TCS (Sectigo CA):
wget -O /etc/pki/tls/certs/GEANT_OV_RSA_CA_4.pem https://crt.sh/?d=2475254782
- If you use ACME (Let's Encrypt):
ln -s /etc/letsencrypt/live/<SERVER_FQDN>/chain.pem /etc/pki/tls/certs/ACME-CA.pem
- If you use GARR TCS (Sectigo CA):
- HTTPS Server Certificate (Public Key) inside
-
Configure the right privileges for the SSL Certificate and Key used by HTTPS:
-
chmod 400 /etc/pki/tls/private/$(hostname -f).key
-
chmod 644 /etc/pki/tls/certs/$(hostname -f).crt
(
$(hostname -f)
will provide your IdP Full Qualified Domain Name)
-
-
Configure SELinux to allow
mod_proxy
to initiate outbound connections:/usr/sbin/setsebool -P httpd_can_network_connect 1
-
Restart Apache:
systemctl restart httpd.service
-
Check that IdP metadata is available on:
-
Verify the strength of your IdP's machine on:
Shibboleth Documentation reference https://wiki.shibboleth.net/confluence/display/IDP4/StorageConfiguration
The IdP provides a number of general-purpose storage facilities that can be used by core subsystems like session management and consent.
The HTML Local Storage requires JavaScript be enabled because reading and writing to the client requires an explicit page be rendered. Note that this feature is safe to enable globally. The implementation is written to check for this capability in each client, and to back off to cookies. The default configuration generates encrypted assertions that a large percentage of non-Shibboleth SPs are going to be unable to decrypt, resulting a wide variety of failures and error messages. Some old Shibboleth SPs or software running on old Operating Systems will also fail to work.
If you don't change anything, the IdP stores data in a long-lived browser cookie that can contain an extremely small number of records. This could bring problems in the long term period.
See the configuration files and the Shibboleth documentation for details.
Check IdP Status:
bash /opt/shibboleth-idp/bin/status.sh
This Storage service will memorize User Consent data on persistent database SQL.
-
Become ROOT of the machine:
sudo su -
-
Install required packages:
yum install mariadb-server mysql-connector-java apache-commons-dbcp
-
Activate MariaDB database service:
systemctl start mariadb.service
-
Address several security concerns in a default MariaDB installation (if it is not already done):
mysql_secure_installation
-
(OPTIONAL) MySQL DB Access without password:
-
vim /root/.my.cnf
[client] user=root password=##ROOT-DB-PASSWORD-CHANGEME##
-
-
Create
StorageRecords
table onstorageservice
database:wget https://registry.idem.garr.it/idem-conf/shibboleth/IDP4/db/shib-ss-db.sql -O /root/shib-ss-db.sql
- fill missing data on
shib-ss-db.sql
before import mysql -u root < /root/shib-ss-db.sql
systemctl restart mariadb.service
-
Rebuild IdP with the needed libraries:
cd /opt/shibboleth-idp
ln -s /usr/share/java/mysql-connector-java.jar edit-webapp/WEB-INF/lib
ln -s /usr/share/java/commons-dbcp.jar edit-webapp/WEB-INF/lib
ln -s /usr/share/java/commons-pool.jar edit-webapp/WEB-INF/lib
bin/build.sh
-
Enable JPA Storage Service:
-
vim /opt/shibboleth-idp/conf/global.xml
and add the following directives to the tail, just before the last
</beans>
tag:<!-- DB-independent Configuration --> <bean id="storageservice.JPAStorageService" class="org.opensaml.storage.impl.JPAStorageService" p:cleanupInterval="%{idp.storage.cleanupInterval:PT10M}" c:factory-ref="storageservice.JPAStorageService.EntityManagerFactory"/> <bean id="storageservice.JPAStorageService.EntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="packagesToScan" value="org.opensaml.storage.impl"/> <property name="dataSource" ref="storageservice.JPAStorageService.DataSource"/> <property name="jpaVendorAdapter" ref="storageservice.JPAStorageService.JPAVendorAdapter"/> <property name="jpaDialect"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" /> </property> </bean> <!-- DB-dependent Configuration --> <bean id="storageservice.JPAStorageService.JPAVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="MYSQL" /> </bean> <!-- Bean to store IdP data unrelated with persistent identifiers on 'storageservice' database --> <bean id="storageservice.JPAStorageService.DataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" lazy-init="true" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/storageservice?autoReconnect=true" p:username="###_SS-USERNAME-CHANGEME_###" p:password="###_SS-DB-USER-PASSWORD-CHANGEME_###" p:maxActive="10" p:maxIdle="5" p:maxWait="15000" p:testOnBorrow="true" p:validationQuery="select 1" p:validationQueryTimeout="5" />
⚠️ IMPORTANT:remember to change "
###_SS-USERNAME-CHANGEME_###
" and "###_SS-DB-USER-PASSWORD-CHANGEME_###
" with your DB user and password data
-
-
Set the consent storage service to the JPA storage service:
-
vim /opt/shibboleth-idp/conf/idp.properties
idp.consent.StorageService = storageservice.JPAStorageService
-
-
Restart Jetty to apply the changes:
systemctl restart jetty.service
-
Check IdP Status:
bash /opt/shibboleth-idp/bin/status.sh
-
Check that you can reach the Directory from your IDP server:
-
For Active Directory:
ldapsearch -x -h <AD-SERVER-FQDN-OR-IP> -D 'CN=idpuser,CN=Users,DC=ad,DC=example,DC=org' -w '<IDPUSER-PASSWORD>' -b 'CN=Users,DC=ad,DC=example,DC=org' '(sAMAccountName=<USERNAME-USED-IN-THE-LOGIN-FORM>)'
(sAMAccountName=<USERNAME-USED-IN-THE-LOGIN-FORM>)
==>(sAMAccountName=$resolutionContext.principal)
searchFilter -
For OpenLDAP:
ldapsearch -x -h <LDAP-SERVER-FQDN-OR-IP> -D 'cn=idpuser,ou=system,dc=example,dc=org' -w '<IDPUSER-PASSWORD>' -b 'ou=people,dc=example,dc=org' '(uid=<USERNAME-USED-IN-THE-LOGIN-FORM>)'
(uid=<USERNAME-USED-IN-THE-LOGIN-FORM>)
==>(uid=$resolutionContext.principal)
searchFilter
-
-
Connect the openLDAP to the IdP to allow the authentication of the users:
(for TLS solutions put the LDAP certificate into
/opt/shibboleth-idp/credentials/ldap-server.crt
)-
For OpenLDAP:
-
Solution 1: LDAP + STARTTLS:
-
vim /opt/shibboleth-idp/credentials/secrets.properties
# Default access to LDAP authn and attribute stores. idp.authn.LDAP.bindDNCredential = ###IDPUSER_PASSWORD### idp.attribute.resolver.LDAP.bindDNCredential = %{idp.authn.LDAP.bindDNCredential:undefined}
-
vim /opt/shibboleth-idp/conf/ldap.properties
The
idp.attribute.resolver.LDAP.exportAttributes
list MUST contains the attribute chosen for the persistent-id generation (idp.persistentId.sourceAttribute)idp.authn.LDAP.authenticator = bindSearchAuthenticator idp.authn.LDAP.ldapURL = ldap://ldap.example.org:389 idp.authn.LDAP.useStartTLS = true idp.authn.LDAP.sslConfig = certificateTrust idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crt # List of attributes to request during authentication idp.authn.LDAP.returnAttributes = passwordExpirationTime,loginGraceRemaining idp.authn.LDAP.baseDN = ou=people,dc=example,dc=org idp.authn.LDAP.subtreeSearch = false idp.authn.LDAP.bindDN = cn=idpuser,ou=system,dc=example,dc=org # The userFilter is used to locate a directory entry to bind against for LDAP authentication. idp.authn.LDAP.userFilter = (uid={user}) # LDAP attribute configuration, see attribute-resolver.xml # Note, this likely won't apply to the use of legacy V2 resolver configurations idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL} idp.attribute.resolver.LDAP.connectTimeout = %{idp.authn.LDAP.connectTimeout:PT3S} idp.attribute.resolver.LDAP.responseTimeout = %{idp.authn.LDAP.responseTimeout:PT3S} idp.attribute.resolver.LDAP.baseDN = %{idp.authn.LDAP.baseDN:undefined} idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined} idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true} idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates:undefined} # The searchFilter is is used to find user attributes from an LDAP source idp.attribute.resolver.LDAP.searchFilter = (uid=$resolutionContext.principal) # List of attributes produced by the Data Connector that should be directly exported as resolved IdPAttributes without requiring actual Attribute Definitions idp.attribute.resolver.LDAP.exportAttributes = ### List space-separated of attributes to retrieve from the directory directly ###
-
-
Solution 2: LDAP + TLS:
-
vim /opt/shibboleth-idp/credentials/secrets.properties
# Default access to LDAP authn and attribute stores. idp.authn.LDAP.bindDNCredential = ###IDPUSER_PASSWORD### idp.attribute.resolver.LDAP.bindDNCredential = %{idp.authn.LDAP.bindDNCredential:undefined}
-
vim /opt/shibboleth-idp/conf/ldap.properties
The
idp.attribute.resolver.LDAP.exportAttributes
list MUST contains the attribute chosen for the persistent-id generation (idp.persistentId.sourceAttribute)idp.authn.LDAP.authenticator = bindSearchAuthenticator idp.authn.LDAP.ldapURL = ldaps://ldap.example.org:636 idp.authn.LDAP.useStartTLS = false idp.authn.LDAP.sslConfig = certificateTrust idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crt # List of attributes to request during authentication idp.authn.LDAP.returnAttributes = passwordExpirationTime,loginGraceRemaining idp.authn.LDAP.baseDN = ou=people,dc=example,dc=org idp.authn.LDAP.subtreeSearch = false idp.authn.LDAP.bindDN = cn=idpuser,ou=system,dc=example,dc=org # The userFilter is used to locate a directory entry to bind against for LDAP authentication. idp.authn.LDAP.userFilter = (uid={user}) # LDAP attribute configuration, see attribute-resolver.xml # Note, this likely won't apply to the use of legacy V2 resolver configurations idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL} idp.attribute.resolver.LDAP.connectTimeout = %{idp.authn.LDAP.connectTimeout:PT3S} idp.attribute.resolver.LDAP.responseTimeout = %{idp.authn.LDAP.responseTimeout:PT3S} idp.attribute.resolver.LDAP.baseDN = %{idp.authn.LDAP.baseDN:undefined} idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined} idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true} idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates:undefined} # The searchFilter is is used to find user attributes from an LDAP source idp.attribute.resolver.LDAP.searchFilter = (uid=$resolutionContext.principal) # List of attributes produced by the Data Connector that should be directly exported as resolved IdPAttributes without requiring actual Attribute Definitions idp.attribute.resolver.LDAP.exportAttributes = ### List space-separated of attributes to retrieve from the directory directly ###
-
-
Solution 3: plain LDAP
-
vim /opt/shibboleth-idp/credentials/secrets.properties
# Default access to LDAP authn and attribute stores. idp.authn.LDAP.bindDNCredential = ###IDPUSER_PASSWORD### idp.attribute.resolver.LDAP.bindDNCredential = %{idp.authn.LDAP.bindDNCredential:undefined}
-
vim /opt/shibboleth-idp/conf/ldap.properties
The
idp.attribute.resolver.LDAP.exportAttributes
list MUST contains the attribute chosen for the persistent-id generation (idp.persistentId.sourceAttribute)idp.authn.LDAP.authenticator = bindSearchAuthenticator idp.authn.LDAP.ldapURL = ldap://ldap.example.org:389 idp.authn.LDAP.useStartTLS = false # List of attributes to request during authentication idp.authn.LDAP.returnAttributes = passwordExpirationTime,loginGraceRemaining idp.authn.LDAP.baseDN = ou=people,dc=example,dc=org idp.authn.LDAP.subtreeSearch = false idp.authn.LDAP.bindDN = cn=idpuser,ou=system,dc=example,dc=org # The userFilter is used to locate a directory entry to bind against for LDAP authentication. idp.authn.LDAP.userFilter = (uid={user}) # LDAP attribute configuration, see attribute-resolver.xml # Note, this likely won't apply to the use of legacy V2 resolver configurations idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL} idp.attribute.resolver.LDAP.connectTimeout = %{idp.authn.LDAP.connectTimeout:PT3S} idp.attribute.resolver.LDAP.responseTimeout = %{idp.authn.LDAP.responseTimeout:PT3S} idp.attribute.resolver.LDAP.baseDN = %{idp.authn.LDAP.baseDN:undefined} idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined} idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true} idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates:undefined} # The searchFilter is is used to find user attributes from an LDAP source idp.attribute.resolver.LDAP.searchFilter = (uid=$resolutionContext.principal) # List of attributes produced by the Data Connector that should be directly exported as resolved IdPAttributes without requiring actual Attribute Definitions idp.attribute.resolver.LDAP.exportAttributes = ### List space-separated of attributes to retrieve from the directory directly ###
-
-
-
For Active Directory:
-
Solution 1: AD + STARTTLS:
-
vim /opt/shibboleth-idp/credentials/secrets.properties
# Default access to LDAP authn and attribute stores. idp.authn.LDAP.bindDNCredential = ###IDPUSER_PASSWORD### idp.attribute.resolver.LDAP.bindDNCredential = %{idp.authn.LDAP.bindDNCredential:undefined}
-
vim /opt/shibboleth-idp/conf/ldap.properties
The
idp.attribute.resolver.LDAP.exportAttributes
list MUST contains the attribute chosen for the persistent-id generation (idp.persistentId.sourceAttribute)idp.authn.LDAP.authenticator = bindSearchAuthenticator idp.authn.LDAP.ldapURL = ldap://ldap.example.org:389 idp.authn.LDAP.useStartTLS = true idp.authn.LDAP.sslConfig = certificateTrust idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crt # List of attributes to request during authentication idp.authn.LDAP.returnAttributes = passwordExpirationTime,loginGraceRemaining idp.authn.LDAP.baseDN = CN=Users,DC=ad,DC=example,DC=org idp.authn.LDAP.subtreeSearch = false idp.authn.LDAP.bindDN = CN=idpuser,CN=Users,DC=ad,DC=example,DC=org # The userFilter is used to locate a directory entry to bind against for LDAP authentication. idp.authn.LDAP.userFilter = (sAMAccountName={user}) # LDAP attribute configuration, see attribute-resolver.xml # Note, this likely won't apply to the use of legacy V2 resolver configurations idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL} idp.attribute.resolver.LDAP.connectTimeout = %{idp.authn.LDAP.connectTimeout:PT3S} idp.attribute.resolver.LDAP.responseTimeout = %{idp.authn.LDAP.responseTimeout:PT3S} idp.attribute.resolver.LDAP.baseDN = %{idp.authn.LDAP.baseDN:undefined} idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined} idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true} idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates:undefined} # The searchFilter is is used to find user attributes from an LDAP source idp.attribute.resolver.LDAP.searchFilter = (sAMAccountName=$resolutionContext.principal) # List of attributes produced by the Data Connector that should be directly exported as resolved IdPAttributes without requiring actual Attribute Definitions idp.attribute.resolver.LDAP.exportAttributes = ### List space-separated of attributes to retrieve from the directory directly ###
-
-
Solution 2: AD + TLS:
-
vim /opt/shibboleth-idp/credentials/secrets.properties
# Default access to LDAP authn and attribute stores. idp.authn.LDAP.bindDNCredential = ###IDPUSER_PASSWORD### idp.attribute.resolver.LDAP.bindDNCredential = %{idp.authn.LDAP.bindDNCredential:undefined}
-
vim /opt/shibboleth-idp/conf/ldap.properties
The
idp.attribute.resolver.LDAP.exportAttributes
list MUST contains the attribute chosen for the persistent-id generation (idp.persistentId.sourceAttribute)idp.authn.LDAP.authenticator = bindSearchAuthenticator idp.authn.LDAP.ldapURL = ldaps://ldap.example.org:636 idp.authn.LDAP.useStartTLS = false idp.authn.LDAP.sslConfig = certificateTrust idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crt # List of attributes to request during authentication idp.authn.LDAP.returnAttributes = passwordExpirationTime,loginGraceRemaining idp.authn.LDAP.baseDN = CN=Users,DC=ad,DC=example,DC=org idp.authn.LDAP.subtreeSearch = false idp.authn.LDAP.bindDN = CN=idpuser,CN=Users,DC=ad,DC=example,DC=org # The userFilter is used to locate a directory entry to bind against for LDAP authentication. idp.authn.LDAP.userFilter = (sAMAccountName={user}) # LDAP attribute configuration, see attribute-resolver.xml # Note, this likely won't apply to the use of legacy V2 resolver configurations idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL} idp.attribute.resolver.LDAP.connectTimeout = %{idp.authn.LDAP.connectTimeout:PT3S} idp.attribute.resolver.LDAP.responseTimeout = %{idp.authn.LDAP.responseTimeout:PT3S} idp.attribute.resolver.LDAP.baseDN = %{idp.authn.LDAP.baseDN:undefined} idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined} idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true} idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates:undefined} # The searchFilter is is used to find user attributes from an LDAP source idp.attribute.resolver.LDAP.searchFilter = (sAMAccountName=$resolutionContext.principal) # List of attributes produced by the Data Connector that should be directly exported as resolved IdPAttributes without requiring actual Attribute Definitions idp.attribute.resolver.LDAP.exportAttributes = ### List space-separated of attributes to retrieve from the directory directly ###
-
-
Solution 3: plain AD
-
vim /opt/shibboleth-idp/credentials/secrets.properties
# Default access to LDAP authn and attribute stores. idp.authn.LDAP.bindDNCredential = ###IDPUSER_PASSWORD### idp.attribute.resolver.LDAP.bindDNCredential = %{idp.authn.LDAP.bindDNCredential:undefined}
-
vim /opt/shibboleth-idp/conf/ldap.properties
The
idp.attribute.resolver.LDAP.exportAttributes
list MUST contains the attribute chosen for the persistent-id generation (idp.persistentId.sourceAttribute)idp.authn.LDAP.authenticator = bindSearchAuthenticator idp.authn.LDAP.ldapURL = ldap://ldap.example.org:389 idp.authn.LDAP.useStartTLS = false # List of attributes to request during authentication idp.authn.LDAP.returnAttributes = passwordExpirationTime,loginGraceRemaining idp.authn.LDAP.baseDN = CN=Users,DC=ad,DC=example,DC=org idp.authn.LDAP.subtreeSearch = false idp.authn.LDAP.bindDN = CN=idpuser,CN=Users,DC=ad,DC=example,DC=org # The userFilter is used to locate a directory entry to bind against for LDAP authentication. idp.authn.LDAP.userFilter = (sAMAccountName={user}) # LDAP attribute configuration, see attribute-resolver.xml # Note, this likely won't apply to the use of legacy V2 resolver configurations idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL} idp.attribute.resolver.LDAP.connectTimeout = %{idp.authn.LDAP.connectTimeout:PT3S} idp.attribute.resolver.LDAP.responseTimeout = %{idp.authn.LDAP.responseTimeout:PT3S} idp.attribute.resolver.LDAP.baseDN = %{idp.authn.LDAP.baseDN:undefined} idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined} idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true} idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates:undefined} # The searchFilter is is used to find user attributes from an LDAP source idp.attribute.resolver.LDAP.searchFilter = (sAMAccountName=$resolutionContext.principal) # List of attributes produced by the Data Connector that should be directly exported as resolved IdPAttributes without requiring actual Attribute Definitions idp.attribute.resolver.LDAP.exportAttributes = ### List space-separated of attributes to retrieve from the directory directly ###
-
UTILITY FOR OPENLDAP ADMINISTRATOR:
slapcat | grep dn
- the baseDN ==>
ou=people,dc=example,dc=org
(branch containing the registered users) - the bindDN ==>
cn=idpuser,ou=system,dc=example,dc=org
(distinguished name for the user that can made queries on the LDAP)
- the baseDN ==>
-
-
-
Restart Jetty to apply the changes:
systemctl restart jetty.service
-
Check IdP Status:
bash /opt/shibboleth-idp/bin/status.sh
Shibboleth Documentation reference https://wiki.shibboleth.net/confluence/display/IDP4/PersistentNameIDGenerationConfiguration
SAML 2.0 (but not SAML 1.x) defines a kind of NameID called a "persistent" identifier that every SP receives for the IdP users. This part will teach you how to release the "persistent" identifiers with a database (Stored Mode) or without it (Computed Mode).
By default, a transient NameID will always be released to the Service Provider if the persistent one is not requested.
-
Become ROOT:
sudo su -
-
Enable the generation of the computed
persistent-id
with:-
vim /opt/shibboleth-idp/conf/saml-nameid.properties
The sourceAttribute MUST be an attribute, or a list of comma-separated attributes, that uniquely identify the subject of the generated
persistent-id
.The sourceAttribute MUST be Stable, Permanent and Not-reassignable attribute.
# ... other things ...# # OpenLDAP has the UserID into "uid" attribute idp.persistentId.sourceAttribute = uid # Active Directory has the UserID into "sAMAccountName" #idp.persistentId.sourceAttribute = sAMAccountName # ... other things ...# # BASE64 will match Shibboleth V2 values, we recommend BASE32 encoding for new installs. idp.persistentId.encoding = BASE32 idp.persistentId.generator = shibboleth.ComputedPersistentIdGenerator
-
vim /opt/shibboleth-idp/conf/saml-nameid.xml
-
Uncomment the line:
<ref bean="shibboleth.SAML2PersistentGenerator" />
-
-
vim /opt/shibboleth-idp/credentials/secrets.properties
idp.persistentId.salt = ### result of 'openssl rand -base64 36' ###
-
-
Restart Jetty to apply the changes:
systemctl restart jetty.service
-
Check IdP Status:
bash /opt/shibboleth-idp/bin/status.sh
-
Become ROOT of the machine:
sudo su -
-
Install required packages:
yum install mariadb-server mysql-connector-java apache-commons-dbcp
-
Activate MariaDB database service:
systemctl start mariadb.service
-
Address several security concerns in a default MariaDB installation (if it is not already done):
mysql_secure_installation
-
(OPTIONAL) MySQL DB Access without password:
-
vim /root/.my.cnf
[client] user=root password=##ROOT-DB-PASSWORD-CHANGEME##
-
-
Create
shibpid
table onshibboleth
database.wget https://registry.idem.garr.it/idem-conf/shibboleth/IDP4/db/shib-pid-db.sql -O /root/shib-pid-db.sql
- fill missing data on
shib-pid-db.sql
before import mysql -u root < shib-pid-db.sql
systemctl restart mariadb.service
-
Rebuild IdP with the needed libraries:
cd /opt/shibboleth-idp
ln -s /usr/share/java/mysql-connector-java.jar edit-webapp/WEB-INF/lib
ln -s /usr/share/java/commons-dbcp.jar edit-webapp/WEB-INF/lib
ln -s /usr/share/java/commons-pool.jar edit-webapp/WEB-INF/lib
bin/build.sh
-
Enable Persistent Identifier's store:
-
vim /opt/shibboleth-idp/conf/global.xml
and add the following directives to the tail, just before the last
</beans>
tag:<!-- Bean to store persistent-id on 'shibboleth' database --> <bean id="MyDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" lazy-init="true" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/shibboleth?autoReconnect=true" p:username="###_SHIB-USERNAME-CHANGEME_###" p:password="###_SHIB-DB-USER-PASSWORD-CHANGEME_###" p:maxActive="10" p:maxIdle="5" p:maxWait="15000" p:testOnBorrow="true" p:validationQuery="select 1" p:validationQueryTimeout="5" />
⚠️ IMPORTANT:remember to change "
###_SHIB-USERNAME-CHANGEME_###
" and "###_SHIB-DB-USER-PASSWORD-CHANGEME_###
" with your DB user and password data
-
-
Enable the generation of the
persistent-id
:-
vim /opt/shibboleth-idp/conf/saml-nameid.properties
The sourceAttribute MUST be an attribute, or a list of comma-separated attributes, that uniquely identify the subject of the generated
persistent-id
.The sourceAttribute MUST be Stable, Permanent and Not-reassignable attribute.
# ... other things ...# # OpenLDAP has the UserID into "uid" attribute idp.persistentId.sourceAttribute = uid # Active Directory has the UserID into "sAMAccountName" #idp.persistentId.sourceAttribute = sAMAccountName # BASE64 will match Shibboleth V2 values, we recommend BASE32 encoding for new installs. idp.persistentId.encoding = BASE32 # ... other things ...# idp.persistentId.generator = shibboleth.StoredPersistentIdGenerator # ... other things ...# idp.persistentId.dataSource = MyDataSource # ... other things ...#
-
vim /opt/shibboleth-idp/credentials/secrets.properties
idp.persistentId.salt = ### result of 'openssl rand -base64 36'###
-
Enable the SAML2PersistentGenerator:
-
vim /opt/shibboleth-idp/conf/saml-nameid.xml
-
Uncomment the line:
<ref bean="shibboleth.SAML2PersistentGenerator" />
-
-
vim /opt/shibboleth-idp/conf/c14n/subject-c14n.xml
-
Uncomment the line:
<ref bean="c14n/SAML2Persistent" />
-
-
(OPTIONAL)
vim /opt/shibboleth-idp/conf/c14n/simple-subject-c14n-config.xml
-
Transform each letter of username, before storing in into the database, to Lowercase or Uppercase by setting the proper constant:
<util:constant id="shibboleth.c14n.simple.Lowercase" static-field="java.lang.Boolean.TRUE"/>
-
-
-
-
Restart Jetty to apply the changes:
systemctl restart jetty.service
-
Check IdP Status:
bash /opt/shibboleth-idp/bin/status.sh
-
Define which attributes your IdP can manage into your Attribute Resolver file. Here you can find a sample attribute-resolver-sample.xml as example:
-
Download the sample attribute resolver provided by IDEM GARR AAI Federation Operators (OpenLDAP / Active Directory compliant):
-
wget https://registry.idem.garr.it/idem-conf/shibboleth/IDP4/attribute-resolver-v4-idem-sample.xml -O /opt/shibboleth-idp/conf/attribute-resolver.xml
If you decide to use the Solutions plain LDAP/AD, remove or comment the following directives from your Attribute Resolver file:
Line 1: useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS:true}" Line 2: trustFile="%{idp.attribute.resolver.LDAP.trustCertificates}"
-
-
Configure the right owner:
chown jetty /opt/shibboleth-idp/conf/attribute-resolver.xml
-
-
Restart Jetty to apply the changes:
systemctl restart jetty.service
-
Check IdP Status:
bash /opt/shibboleth-idp/bin/status.sh
eduPersonTargetedID is an abstracted version of the SAML V2.0 Name Identifier format of "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent". To be able to follow these steps, you need to have followed the previous steps on "persistent" NameID generation.
-
Add the
<AttributeDefinition>
and the<DataConnector>
needed into theattribute-resolver.xml
:-
vim /opt/shibboleth-idp/conf/attribute-resolver.xml
<!-- ...other things ... --> <!-- AttributeDefinition for eduPersonTargetedID - Computed Mode --> <AttributeDefinition xsi:type="SAML2NameID" nameIdFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" id="eduPersonTargetedID"> <InputDataConnector ref="myComputedId" attributeNames="computedID" /> </AttributeDefinition> <!-- ... other things... --> <!-- Data Connector for eduPersonTargetedID - Computed Mode --> <DataConnector id="myComputedId" xsi:type="ComputedId" generatedAttributeID="computedID" salt="%{idp.persistentId.salt}" algorithm="%{idp.persistentId.algorithm:SHA}" encoding="%{idp.persistentId.encoding:BASE32}"> <InputDataConnector ref="myLDAP" attributeNames="%{idp.persistentId.sourceAttribute}" /> </DataConnector>
-
-
Create the custom
eduPersonTargetedID.properties
file:-
wget https://registry.idem.garr.it/idem-conf/shibboleth/IDP4/attributes/custom/eduPersonTargetedID.properties -O /opt/shibboleth-idp/conf/attributes/custom/eduPersonTargetedID.properties
-
-
Restart Jetty to apply the changes:
systemctl restart jetty.service
-
Check IdP Status:
bash /opt/shibboleth-idp/bin/status.sh
-
Add the
<AttributeDefinition>
and the<DataConnector>
needed into theattribute-resolver.xml
:-
vim /opt/shibboleth-idp/conf/attribute-resolver.xml
<!-- ...other things ... --> <!-- AttributeDefinition for eduPersonTargetedID - Stored Mode --> <AttributeDefinition xsi:type="SAML2NameID" nameIdFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" id="eduPersonTargetedID"> <InputDataConnector ref="myStoredId" attributeNames="persistentID" /> </AttributeDefinition> <!-- ... other things... --> <!-- Data Connector for eduPersonTargetedID - Stored Mode --> <DataConnector id="myStoredId" xsi:type="StoredId" generatedAttributeID="persistentID" salt="%{idp.persistentId.salt}" queryTimeout="0"> <InputDataConnector ref="myLDAP" attributeNames="%{idp.persistentId.sourceAttribute}" /> <BeanManagedConnection>MyDataSource</BeanManagedConnection> </DataConnector>
-
-
Create the custom
eduPersonTargetedID.properties
file:-
wget https://registry.idem.garr.it/idem-conf/shibboleth/IDP4/attributes/custom/eduPersonTargetedID.properties -O /opt/shibboleth-idp/conf/attributes/custom/eduPersonTargetedID.properties
-
-
Restart Jetty to apply the changes:
systemctl restart jetty.service
-
Check IdP Status:
bash /opt/shibboleth-idp/bin/status.sh
File(s): conf/attribute-registry.xml
, conf/attributes/default-rules.xml
, conf/attribute-resolver.xml
, conf/attributes/custom/
-
Download
schac.xml
into the right location:-
wget https://registry.idem.garr.it/idem-conf/shibboleth/IDP4/attributes/schac.xml -O /opt/shibboleth-idp/conf/attributes/schac.xml
-
-
Change the
default-rules.xml
to include the newschac.xml
file:-
vim /opt/shibboleth-idp/conf/attributes/default-rules.xml
<!-- ...other things ... --> <import resource="inetOrgPerson.xml" /> <import resource="eduPerson.xml" /> <import resource="eduCourse.xml" /> <import resource="samlSubject.xml" /> <import resource="schac.xml" /> </beans>
-
Enrich IDP logs with the authentication error occurred on LDAP:
-
sed -i '/^ <logger name="org.ldaptive".*/a \\n <!-- Logs on LDAP user authentication - ADDED BY IDEM HOWTO -->' /opt/shibboleth-idp/conf/logback.xml
-
sed -i '/^ <!-- Logs on LDAP user authentication - ADDED BY IDEM HOWTO -->/a \ \ \ \ \<logger name="org.ldaptive.auth.Authenticator" level="INFO" />' /opt/shibboleth-idp/conf/logback.xml
Translate the IdP messages in your language:
- Get the files translated in your language from Shibboleth page
- Put '
messages_XX.properties
' downloaded file into/opt/shibboleth-idp/messages
directory - Restart Jetty to apply the changes with
systemctl restart jetty.service
-
Modify the IdP metadata to enable only the SAML2 protocol:
The
<AttributeAuthorityDescriptor>
role is needed only if you have SPs that use AttributeQuery to request attributes to your IdP. Read details on the Shibboleth Official Documentation.-
vim /opt/shibboleth-idp/metadata/idp-metadata.xml
- Remove completely the initial default comment <EntityDescriptor> Section: - Remove `validUntil` XML attribute. <IDPSSODescriptor> Section: - From the list of "protocolSupportEnumeration" remove: - urn:oasis:names:tc:SAML:1.1:protocol - urn:mace:shibboleth:1.0 - Remove completely the comment on <mdui:UIInfo>. You will add it on the "IDEM Entity Registry", the web application provided by the IDEM GARR AAI to manage metadata. - Remove the endpoint: <ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="https://idp.example.org:8443/idp/profile/SAML1/SOAP/ArtifactResolution" index="1"/> (and modify the index value of the next one to “1”) - Remove comment from SingleLogoutService endpoints - Between the last <SingleLogoutService> and the first <SingleSignOnService> endpoints add these 2 lines: <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat> <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat> (because the IdP installed with this guide will release transient NameID, by default, and persistent NameID if requested.) - Remove the endpoint: <SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://idp.example.org/idp/profile/Shibboleth/SSO"/> - Remove all ":8443" from the existing URL (such port is not used anymore) <AttributeAuthorityDescriptor> Section (Needed ONLY if AttributeQuery is used by specific SPs. Otherwise, remove entirely): - From the list "protocolSupportEnumeration" replace the value: - urn:oasis:names:tc:SAML:1.1:protocol with: - urn:oasis:names:tc:SAML:2.0:protocol - Uncomment: <AttributeService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://idp.example.org/idp/profile/SAML2/SOAP/AttributeQuery"/> - Remove the endpoint: <AttributeService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="https://idp.example.org:8443/idp/profile/SAML1/SOAP/AttributeQuery"/> - Remove the comment starting with "If you uncomment..." - Remove all ":8443" from the existing URL (such port is not used anymore)
-
-
Check that the metadata is available on:
The default configuration of the IdP relies on a component called a "DataSealer" which in turn uses an AES secret key to secure cookies and certain other data for the IdPs own use. This key must never be shared with anybody else, and must be copied to every server node making up a cluster. The Java "JCEKS" keystore file stores secret keys instead of public/private keys and certificates and a parallel file tracks the key version number.
These instructions will regularly update the secret key (and increase its version) and provide you the capability to push it to cluster nodes and continually maintain the secrecy of the key.
See the official Shibboleth documentation: https://wiki.shibboleth.net/confluence/display/IDP4/SecretKeyManagement
-
Create the
updateIDPsecret.sh
script:-
sudo vim /opt/shibboleth-idp/bin/updateIDPsecret.sh
#!/bin/bash set -e set -u # Default IDP_HOME if not already set if [ ! -d "${IDP_HOME:=/opt/shibboleth-idp}" ] then echo "ERROR: Directory does not exist: ${IDP_HOME}" >&2 exit 1 fi function get_config { # Key to lookup (escape . for regex lookup) local KEY=${1:?"No key provided to look up value"} # Passed default value local DEFAULT="${2:-}" # Lookup key, strip spaces, replace idp.home with IDP_HOME value local RESULT=$(sed -rn '/^'"${KEY//./\\.}"'\s*=/ { s|^[^=]*=(.*)\s*$|\1|; s|%\{idp\.home\}|'"${IDP_HOME}"'|g; p}' ${IDP_HOME}/conf/idp.properties) if [ -z "$RESULT" ] then local RESULT=$(sed -rn '/^'"${KEY//./\\.}"'\s*=/ { s|^[^=]*=(.*)\s*$|\1|; s|%\{idp\.home\}|'"${IDP_HOME}"'|g; p}' ${IDP_HOME}/credentials/secrets.properties) fi # Set if no result with default - exit if no default echo ${RESULT:-${DEFAULT:?"No value in config and no default defined for: '${KEY}'"}} } # Get config values ## Official config items ## storefile=$(get_config idp.sealer.storeResource) versionfile=$(get_config idp.sealer.versionResource) storepass=$(get_config idp.sealer.storePassword) alias=$(get_config idp.sealer.aliasBase secret) ## Extended config items ## count=$(get_config idp.sealer._count 30) # default cannot be empty - so "self" is the default (self is skipped for syncing) sync_hosts=$(get_config idp.sealer._sync_hosts ${HOSTNAME}) # Run the keygen utility ${0%/*}/runclass.sh net.shibboleth.utilities.java.support.security.BasicKeystoreKeyStrategyTool \ --storefile "${storefile}" \ --storepass "${storepass}" \ --versionfile "${versionfile}" \ --alias "${alias}" \ --count "${count}" # Display current version echo "INFO: $(tac "${versionfile}" | tr "\n" " ")" >&2 for EACH in ${sync_hosts} do if [ "${HOSTNAME}" == "${EACH}" ] then echo "INFO: Host '${EACH}' is myself - skipping" >&2 elif ! ping -q -c 1 -W 3 ${EACH} >/dev/null 2>&1 then echo "ERROR: Host '${EACH}' not reachable - skipping" >&2 else # run scp in the background scp "${storefile}" "${versionfile}" "${EACH}:${IDP_HOME}/credentials/" & fi done
-
-
Provide the right privileges to the script:
sudo chmod +x /opt/shibboleth-idp/bin/updateIDPsecret.sh
-
Create the CRON script to run it:
-
sudo vim /etc/cron.daily/updateIDPsecret
#!/bin/bash /opt/shibboleth-idp/bin/updateIDPsecret.sh
-
-
Provide the right privileges to the script:
sudo chmod +x /etc/cron.daily/updateIDPsecret
-
Confirm that the script will be run daily with (you should see your script in the command output):
sudo run-parts --test /etc/cron.daily
-
Add the following properties to
idp.properties
if you need to set different values than defaults:idp.sealer._count
- Number of earlier keys to keep (default 30)idp.sealer._sync_hosts
- Space separated list of hosts to scp the sealer files to (default generate locally)
Follow these steps ONLY IF your IdP is accepted into IDEM Production Federation
-
Become ROOT:
sudo su -
-
Create the directory "
tmp/httpClientCache
" used by "shibboleth.FileCachingHttpClient
":mkdir -p /opt/shibboleth-idp/tmp/httpClientCache ; chown jetty /opt/shibboleth-idp/tmp/httpClientCache
-
Modify your
services.xml
:-
vim /opt/shibboleth-idp/conf/services.xml
and add the following two beans on the top of the file, under the first
<beans>
TAG, only one time:<bean id="MyHTTPClient" parent="shibboleth.FileCachingHttpClientFactory" p:connectionTimeout="PT30S" p:connectionRequestTimeout="PT30S" p:socketTimeout="PT30S" p:cacheDirectory="%{idp.home}/tmp/httpClientCache" /> <bean id="IdemAttributeFilterFull" class="net.shibboleth.ext.spring.resource.FileBackedHTTPResource" c:client-ref="MyHTTPClient" c:url="https://registry.idem.garr.it/idem-conf/shibboleth/IDP4/idem-attribute-filter-v4-full.xml" c:backingFile="%{idp.home}/conf/idem-attribute-filter-v4-full.xml"/>
and enrich the "
AttributeFilterResources
" list with "IdemAttributeFilterFull
":<!-- ...other things... --> <util:list id ="shibboleth.AttributeFilterResources"> <value>%{idp.home}/conf/attribute-filter.xml</value> <ref bean="IdemAttributeFilterFull"/> </util:list> <!-- ...other things... -->
-
-
Restart Jetty to apply the changes:
systemctl restart jetty.service
-
Check IdP Status:
bash /opt/shibboleth-idp/bin/status.sh
-
Register you IdP metadata on IDEM Entity Registry (your entity have to be approved by an IDEM Federation Operator before become part of IDEM Test Federation):
https://registry.idem.garr.it/
-
Configure the IdP to retrieve the Federation Metadata:
-
Retrieve the Federation Certificate used to verify signed metadata:
-
wget https://md.idem.garr.it/certs/idem-signer-20220121.pem -O /opt/shibboleth-idp/metadata/federation-cert.pem
-
-
Check the validity:
-
cd /opt/shibboleth-idp/metadata
-
openssl x509 -in federation-cert.pem -fingerprint -sha1 -noout
(sha1: D1:68:6C:32:A4:E3:D4:FE:47:17:58:E7:15:FC:77:A8:44:D8:40:4D)
-
openssl x509 -in federation-cert.pem -fingerprint -md5 -noout
(md5: 48:3B:EE:27:0C:88:5D:A3:E7:0B:7C:74:9D:24:24:E0)
-
-
vim /opt/shibboleth-idp/conf/metadata-providers.xml
and add before the last
</MetadataProvider>
this piece of code:<!-- IDEM Test Federation --> <MetadataProvider id="URLMD-IDEM-Federation" xsi:type="FileBackedHTTPMetadataProvider" backingFile="%{idp.home}/metadata/idem-test-metadata-sha256.xml" metadataURL="http://md.idem.garr.it/metadata/idem-test-metadata-sha256.xml"> <!-- Verify the signature on the root element of the metadata aggregate using a trusted metadata signing certificate. --> <MetadataFilter xsi:type="SignatureValidation" requireSignedRoot="true" certificateFile="${idp.home}/metadata/federation-cert.pem"/> <!-- Require a validUntil XML attribute on the root element and make sure its value is no more than 10 days into the future. --> <MetadataFilter xsi:type="RequiredValidUntil" maxValidityInterval="P10D"/> <!-- Consume only SP in the metadata aggregate --> <MetadataFilter xsi:type="EntityRoleWhiteList"> <RetainedRole>md:SPSSODescriptor</RetainedRole> </MetadataFilter> </MetadataProvider>
-
-
Reload service with id
shibboleth.MetadataResolverService
to retrieve the Federation Metadata:bash /opt/shibboleth-idp/bin/reload-service.sh -id shibboleth.MetadataResolverService
-
Check that your IdP release at least eduPersonScopedAffiliation, eduPersonTargetedID and a saml2:NameID transient/persistent to the testing SP provided by IDEM:
-
bash /opt/shibboleth-idp/bin/aacli.sh -n <USERNAME> -r https://sp.example.org/shibboleth --saml2
(the command will have a
transient
NameID into the Subject of the assertion) -
bash /opt/shibboleth-idp/bin/aacli.sh -n <USERNAME> -r https://sp.aai-test.garr.it/shibboleth --saml2
(the command will have a
persistent
NameID into the Subject of the assertion)
-
-
Wait that your IdP Metadata is approved by an IDEM Federation Operator into the metadata stream and the next steps provided by the operator itself.
-
Follow the instructions provided by IDEM.
Follow these steps ONLY when your need to import persistent-id from another IdP
-
Become ROOT:
sudo su -
-
Create a DUMP of
shibpid
table from the previous DBshibboleth
on the OLD IdP:cd /tmp
-
mysqldump --complete-insert --no-create-db --no-create-info -u root -p shibboleth shibpid > /tmp/shibboleth_shibpid.sql
-
Move the
/tmp/shibboleth_shibpid.sql
of old IdP into/tmp/shibboleth_shibpid.sql
on the new IdP. -
Import the content of
/tmp/shibboleth_shibpid.sql
into the DB of the new IDP:cd /tmp ; mysql -u root -p shibboleth < /tmp/shibboleth_shibpid.sql
-
Delete
/tmp/shibboleth_shibpid.sql
:rm /tmp/shibboleth_shibpid.sql
Follow this if do you want to find a problem of your IdP.
-
Jetty Logs:
cd /opt/jetty/logs
ls -l *.stderrout.log
-
Shibboleth IdP Logs:
cd /opt/shibboleth-idp/logs
- Audit Log:
vim idp-audit.log
- Consent Log:
vim idp-consent-audit.log
- Warn Log:
vim idp-warn.log
- Process Log:
vim idp-process.log
- AACLI: Useful to understand which attributes will be released to the federated resources
export JAVA_HOME=/usr/lib/jvm/java-11-amazon-corretto
bash /opt/shibboleth-idp/bin/aacli.sh -n <USERNAME> -r <ENTITYID-SP> --saml2
- https://wiki.shibboleth.net/confluence/display/IDP4/SpringConfiguration
- https://wiki.shibboleth.net/confluence/display/IDP4/ConfigurationFileSummary
- https://wiki.shibboleth.net/confluence/display/IDP4/LoggingConfiguration
- https://wiki.shibboleth.net/confluence/display/IDP4/AuditLoggingConfiguration
- https://wiki.shibboleth.net/confluence/display/IDP4/FTICKSLoggingConfiguration
- https://wiki.shibboleth.net/confluence/display/IDP4/MetadataConfiguration
- https://wiki.shibboleth.net/confluence/display/IDP4/PasswordAuthnConfiguration
- https://wiki.shibboleth.net/confluence/display/IDP4/AttributeResolverConfiguration
- https://wiki.shibboleth.net/confluence/display/IDP4/LDAPConnector
- https://wiki.shibboleth.net/confluence/display/IDP4/AttributeRegistryConfiguration
- https://wiki.shibboleth.net/confluence/display/IDP4/TranscodingRuleConfiguration
- https://wiki.shibboleth.net/confluence/display/IDP4/HTTPResource
- https://wiki.shibboleth.net/confluence/display/CONCEPT/SAMLKeysAndCertificates
- https://wiki.shibboleth.net/confluence/display/IDP4/SecretKeyManagement
- https://wiki.shibboleth.net/confluence/display/IDP4/NameIDGenerationConfiguration
- https://wiki.shibboleth.net/confluence/display/IDP4/GCMEncryption
- https://wiki.shibboleth.net/confluence/display/IDP4/Switching+locale+on+the+login+page
- https://wiki.shibboleth.net/confluence/display/IDP4/WebInterfaces
- https://wiki.shibboleth.net/confluence/display/IDP4/PasswordAuthnConfiguration#PasswordAuthnConfiguration-UserInterface
- Marco Malavolti ([email protected])