====== 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.**