====== Java servlet container for Shibboleth IdP ======
**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 [[en:tech:idp:shibboleth|Shibboleth IdP]].**
----
====== Jetty ======
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 [[https://wiki.shibboleth.net/confluence/display/IDP30/Installation|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 [[https://webtide.com/why-choose-jetty/|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.**
===== Prerequisites =====
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
===== Installation =====
Jetty installation is very simple. Just downloading [[https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.3.14.v20161028/|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 (**W**eb application **AR**chive) 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 {{https://www.eduid.cz/jetty/idp.xml|online}} and contains the following lines.
/opt/shibboleth-idp/war/idp.war
/idp
false
false
true
/opt/jetty/tmp
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.
===== SSL certificate =====
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
# 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
# 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.
===== SSL configuration =====
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 {{:en:tech:idp:tweak-ssl.xml|content}} of //tweak-ssl.xml// file is as follows.
- .*DES.*
- .*DSS.*
- .*MD5.*
- .*NULL.*
- .*RC4.*
- .*_RSA_.*MD5$
- .*_RSA_.*SHA$
- .*_RSA_.*SHA1$
- TLS_DHE_RSA_WITH_AES_128.*
- TLS_DHE_RSA_WITH_AES_256.*
- SSL
- SSLv2
- SSLv2Hello
- SSLv3
- TLS_DHE_RSA.*
- TLS_ECDHE.*
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.
===== Starting Jetty =====
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 [[en:tech:idp:shibboleth|Shibboleth IdP]] installation.**