This page describes Jetty installation, a Java servlet container, required by Shibboleth IdP 3 in Linux distribution Debian. After successful installation, the last step is to install Shibboleth IdP.
Shibboleth consortium states that Apache Tomcat 7+ or Jetty 8+ is required to run Shibboleth IdP 3. Debian 8 (Jessie) contains Tomcat versions 7 and 8 as well as Jetty version 8 packages, however, we think it is best to stick to recommendations and use Jetty 9.3 which is being used for Shibboleth IdP development and testing. By the way, only Tomcat 8 and Jetty 9.2–9.3 are supported.
IdP starts much faster when deployed using Jetty compared to Tomcat. There is a way to improve starting time in Tomcat, but still it is not as fast as Jetty. The truth is there is no need to restart Java container after every Shibboleth IdP configuration change, but still we are on our own if we have any troubles. There is quite nice article Why Choose Jetty? with reasons for choosing Jetty over any other servlet container.
If you still prefer Tomcat, you will probably be fine, but you have been warned. Should you have any issues, be prepared that you might be asked to reproduce your problem with Jetty when you are seeking help.
In order to Jetty to run as an HTTP server on the port 443 (standard port for HTTPS protocol) it requires root privileges. Due to security reasons, it is advisable to run Jetty under unprivileged user on the port 8443 and arrange listening on the standard HTTPS port 443 using iptables and ip6tables redirects.
The unprivileged user is going to be named idp and also a member of the group idp. This user will own directories containing Jetty and Shibboleth IdP as well.
# Creating idp group and idp user groupadd idp useradd -m -g idp -s /bin/bash idp
Now port redirects are required. The first command redirects all the traffic for the port 80 at the local interface (so called loopback) to the port 8080 where Jetty listens for unencrypted requests. It takes care only of the local interface lo, thus running Shibboleth IdP scripts such as status.sh, reload-service.sh and others is possible without defining any parameters. No parameters means that those scripts connect to http://localhost/
. The second command redirects all the traffic for the port 443 to the port 8443 which is the port awaiting encrypted communication.
# Redirecting ports using iptables (IPv4) iptables -t nat -A OUTPUT -o lo -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080 iptables -t nat -A PREROUTING -p tcp -m tcp --dport 443 -j DNAT --to-destination :8443
In case of IPv6 (if available on the machine), only encrypted communication needs redirecting.
# Redirecting ports using ip6tables (IPv6) ip6tables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination :8443
iptables and ip6tables rules need to be saved and reloaded after system restart. In Debian, for example, one can save the rules into /etc
directory.
# Saving the rules for iptables and ip6tables iptables-save > /etc/iptables.conf ip6tables-save > /etc/ip6tables.conf
The last thing is to write scripts that will load the saved rules after reboot. Forgetting to set those scripts as executable causes not running them.
# Creating the scripts for reloading the iptables and ip6tables rules echo '#!/bin/bash' > /etc/network/if-up.d/iptables echo 'iptables-restore < /etc/iptables.conf' >> /etc/network/if-up.d/iptables echo '#!/bin/bash' > /etc/network/if-up.d/ip6tables echo 'ip6tables-restore < /etc/ip6tables.conf' >> /etc/network/if-up.d/ip6tables chmod +x /etc/network/if-up.d/iptables /etc/network/if-up.d/ip6tables
Jetty installation is very simple. Just downloading Jetty source code (verifying the fingerprints!), putting it into /opt/src
directory and running a few commands as follows.
# Basic Jetty installation cd /opt mkdir -p src jetty/tmp chown -R idp:idp src jetty su idp cd /opt/src wget https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.3.14.v20161028/jetty-distribution-9.3.14.v20161028.tar.gz \ https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.3.14.v20161028/jetty-distribution-9.3.14.v20161028.tar.gz.sha1 \ https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.3.14.v20161028/jetty-distribution-9.3.14.v20161028.tar.gz.asc \ https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.3.14.v20161028/jetty-distribution-9.3.14.v20161028.tar.gz.asc.asc.sha1 # Verifying the SHA1 fingerprints # The sha1sum output must be the same as the file content # jetty-distribution-9.3.14.v20161028.tar.gz.sha1 sha1sum jetty-distribution-9.3.14.v20161028.tar.gz && cat jetty-distribution-9.3.14.v20161028.tar.gz.sha1 # It is recommended to also verify the source code signature # 8FB67BAC key has to be imported first gpg --keyserver hkp://keys.gnupg.net --search-keys 8FB67BAC # Now the signature can be verified gpg --verify jetty-distribution-9.3.14.v20161028.tar.gz.asc exit tar -xzf src/jetty-distribution-9.3.14.v20161028.tar.gz chown -R idp:idp /opt/jetty-distribution-9.3.14.v20161028 ln -snf /opt/jetty-distribution-9.3.14.v20161028/bin/jetty.sh /etc/init.d/jetty echo "JETTY_HOME=/opt/jetty-distribution-9.3.14.v20161028/" > /etc/default/jetty echo "JETTY_BASE=/opt/jetty" >> /etc/default/jetty echo "JETTY_USER=idp" >> /etc/default/jetty
Now it is time to configure Jetty. The basic configuration is done by running Jetty with defining required modules used for Shibboleth IdP:
# Basic Jetty configuration (as idp user) su idp cd /opt/jetty java -jar /opt/jetty-distribution-9.3.14.v20161028/start.jar \ --add-to-startd=http,https,logging,deploy,jsp,jstl,plus,servlets,annotations,ext,resources,logging,requestlog
It is advisable to limit Jetty for unencrypted communication only via local interface lo. This enables one to easily run Shibboleth IdP scripts such as status.sh, reload-service.sh and others. In the configuration file start.d/http.ini
, a restriction has to be defined.
# Tweaking Jetty configuration for HTTP (as idp user) #su idp vi start.d/http.ini
Uncommenting jetty.http.host
variable and setting it to localhost
value (default is 0.0.0.0
).
// Enabling HTTP only for localhost jetty.http.host=localhost
In /opt/jetty/webapps/root
directory, a simple web page to be shown after accessing Jetty installation should take place. This is not mandatory, however, if a user mistakenly accesses that page a useful information is highly appreciated. The index.html
file content is arbitrary – for example, a redirect to the organizational home page.
# Creating a simple web page for Jetty (as idp user) #su idp mkdir -p /opt/jetty/webapps/root vi /opt/jetty/webapps/root/index.html
Jetty also needs a configuration file for the IdP. This file is idp.xml
and defines which WAR (Web application ARchive) contains the IdP, in this case https://SERVER_HOSTNAME/idp
.
# Downloading idp.xml file (as idp user) #su idp cd /opt/jetty/webapps/ wget https://www.eduid.cz/jetty/idp.xml
The content of /opt/jetty/webapps/idp.xml
is available online and contains the following lines.
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="war">/opt/shibboleth-idp/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="tempDirectory">/opt/jetty/tmp</Set> </Configure>
Now, Jetty is almost ready to run, however, Shibboleth IdP is not installed, so no idp.war
is available and no SSL certificate has been configured to run Jetty via HTTPS protocol.
We need to configure SSL certificate used by Jetty web server, so users are logging in using HTTPS. Jetty uses Java Keystore. It is essential to import not only the certificate, but the whole key chain.
In the following, cert.pem
file contains the server's certificate and chain_TERENA_SSL_CA_2.pem
file contains certificate chain. At first, certificate and chain have to be merged into one file.
# Merging the server certificate with the chain cat cert.pem chain_TERENA_SSL_CA_3.pem >> jetty-cert.txt
Next, it is required to transform the file to PKCS #12 format. We will be asked for a password for the key (file key.pem
) and then for a new password for the new file jetty-cert.pkcs12
.
# Transforming the certificate to PKCS #12 format openssl pkcs12 -export -inkey serverkey-XYZ.pem -in jetty-cert.txt -out jetty-cert.pkcs12
We will be asked for the private key (key.pem
file) password and a new password (marked as #1) for jetty-cert.pkcs12
file which has to be typed twice.
# Terminal output Enter pass phrase for key.pem: Enter Export Password: Verifying - Enter Export Password:
Now it is time to import the certificate in PKCS #12 format (jetty-cert.pkcs12
file) into Java keystore:
# Importing the certificate into keystore /opt/jdk1.8.0_111/bin/keytool -importkeystore -srckeystore jetty-cert.pkcs12 -srcstoretype PKCS12 -destkeystore keystore
Firstly, we will be asked for a newly created keystore (Enter destination keystore password, marked as #2). Next, we will be asked to repeat that password (Re-enter new password). Secondly, we will be asked for the password (marked previously as #1) to the certificate (jetty-cert.pkcs12
file) to be imported to keystore (Enter source keystore password).
# Terminal output Enter destination keystore password: Re-enter new password: Enter source keystore password: Entry for alias 1 successfully imported. Import command completed: 1 entries successfully imported, 0 entries failed or cancelled
When finished, move the keystore into Jetty.
# Moving the keystore to Jetty mv keystore /opt/jetty/etc chown idp:idp /opt/jetty/etc/keystore
To obtain obfuscated passwords for plain text configuration files, jetty-util
from Jetty can be employed.
Obfuscated password (#2) for the keystore:
# Obfuscated password (#2) for the keystore java -cp /opt/jetty-distribution-9.3.14.v20161028/lib/jetty-util-9.3.14.v20161028.jar \ org.eclipse.jetty.util.security.Password <password_(2)_for_the_keystore>
# Terminal output 2015-06-16 15:56:58.986:INFO::main: Logging initialized @322ms keystore OBF:1u9x1vn61z0p1yta1ytc1z051vnw1u9l MD5:5fba3d2b004d68d3c5ca4e174024fc81
Obfuscated password (#1) for the certificate:
# Obfuscated password (#1) for the certificate java -cp /opt/jetty-distribution-9.3.14.v20161028/lib/jetty-util-9.3.14.v20161028.jar \ org.eclipse.jetty.util.security.Password <password_(1)_for_the_certificate>
# Terminal output 2015-06-16 15:57:02.322:INFO::main: Logging initialized @308ms certificate OBF:1sot1w1c1uvk1vo01unz1thb1unz1vn21uum1w261sox MD5:e0d30cef5c6139275b58b525001b413c
Passwords are to be inserted into start.d/ssl.ini
configuration file (jetty.sslContext.keyStorePassword
is identical to jetty.sslContext.trustStorePassword
):
# Entering obfuscated passwords #1 and #2 to Jetty configuration (as idp user) su idp vi /opt/jetty/start.d/ssl.ini
// Configuration changes in the file 'ssl.ini' jetty.sslContext.keyStorePassword=OBF:1u9x1vn61z0p1yta1ytc1z051vnw1u9l # password (#2) jetty.sslContext.keyManagerPassword=OBF:1sot1w1c1uvk1vo01unz1thb1unz1vn21uum1w261sox # password (#1) jetty.sslContext.trustStorePassword=OBF:1u9x1vn61z0p1yta1ytc1z051vnw1u9l # password (#2)
Variables jetty.sslContext.keyStorePassword
and jetty.sslContext.trustStorePassword
have to be set to obfuscated password (#2) to the „keystore“. A variable jetty.sslContext.keyManagerPassword
has to be se to obfuscated password (#1) to the key of certificate (jetty-cert.pkcs12
file). If you set it incorrectly, Jetty will not start.
Default Jetty configuration allows usage of ciphers not trustworthy anymore, so we disable them. For this purpose, we download the prepared tweak-ssl.xml configuration file into /opt/jetty/etc
directory.
# SSL tweaks for Jetty (as idp user) #su idp cd /opt/jetty/etc/ wget https://www.eduid.cz/_media/en/tech/idp/tweak-ssl.xml
The content of tweak-ssl.xml file is as follows.
<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd"> <Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory"> <!-- Prohibit old and untrustworthy ciphers --> <Call name="addExcludeCipherSuites"> <Arg> <Array type="String"> <Item>.*DES.*</Item> <Item>.*DSS.*</Item> <Item>.*MD5.*</Item> <Item>.*NULL.*</Item> <Item>.*RC4.*</Item> <Item>.*_RSA_.*MD5$</Item> <Item>.*_RSA_.*SHA$</Item> <Item>.*_RSA_.*SHA1$</Item> <Item>TLS_DHE_RSA_WITH_AES_128.*</Item> <Item>TLS_DHE_RSA_WITH_AES_256.*</Item> </Array> </Arg> </Call> <!-- Prohibit untrustworthy protocols --> <Call name="addExcludeProtocols"> <Arg> <Array type="java.lang.String"> <Item>SSL</Item> <Item>SSLv2</Item> <Item>SSLv2Hello</Item> <Item>SSLv3</Item> </Array> </Arg> </Call> <!-- Enabling Forward Secrecy --> <Set name="IncludeCipherSuites"> <Array type="String"> <Item>TLS_DHE_RSA.*</Item> <Item>TLS_ECDHE.*</Item> </Array> </Set> </Configure>
Now we just need Jetty to load this configuration file stating the following line into start.d/https.ini:
# Load tweak-ssl.xml into Jetty (as idp user -- then run EXIT command to become 'root' user again!) echo etc/tweak-ssl.xml >> /opt/jetty/start.d/https.ini exit
This configuration changes make Jetty more secure and trustworthy.
The second last thing before starting Jetty is make sure the file permissions to Jetty are set to idp user from idp group.
# Setting file permissions for Jetty and starting it (as root user) chown -R idp:idp /opt/jetty/ /opt/jetty-distribution*/ /etc/init.d/jetty start
Jetty now runs so we check that it listens for unencrypted traffic (port 8080) only at localhost (IPv4 address 127.0.0.1) using netstat
command:
# Checking for unencrypted listening at localhost netstat -an | grep ":8080"
We should see the following.
# Terminal output tcp6 0 0 127.0.0.1:8080 :::* LISTEN
If we now look into Jetty logs, we will see an error. And that this OK at this time. Shibboleth IdP is not installed yet, thus /opt/shibboleth-idp/war/idp.war
file does not exist.
2015-08-05 09:02:22.871:WARN:oejw.WebInfConfiguration:main: Web application not found /opt/shibboleth-idp/war/idp.war 2015-08-05 09:02:22.872:WARN:oejw.WebAppContext:main: Failed startup of context o.e.j.w.WebAppContext@df27fae{/idp,null,null}{/opt/shibboleth-idp/war/idp.war} java.io.FileNotFoundException: /opt/shibboleth-idp/war/idp.war at org.eclipse.jetty.webapp.WebInfConfiguration.unpack(WebInfConfiguration.java:495) at org.eclipse.jetty.webapp.WebInfConfiguration.preConfigure(WebInfConfiguration.java:72) at org.eclipse.jetty.webapp.WebAppContext.preConfigure(WebAppContext.java:474) at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:510) ...
Anyway, Jetty runs and we can check that it is serving our index.html file we have written previously. Try HTTPS access from your computer and HTTP access from the server's command line.
# HTTP access from the server's command line wget -q -O - http://127.0.0.1
You should see the content of /opt/jetty/webapps/root/index.html
file.
The last thing is to set Jetty to autorun after the system boots up.
# Autorun Jetty after system start ups (as root user)
insserv jetty
Now, as Jetty is installed and configured, it is time for Shibboleth IdP installation.
CESNET, z. s. p. o.
Generála Píky 26
16000 Praha 6
info@cesnet.cz
Tel: +420 234 680 222
GSM: +420 602 252 531
support@cesnet.cz