Thursday, March 29. 2018
Configuring kerberos/spnego login in tomcat
Another quick entry this time. The past week I needed to configure kerberos/spnego login in tomcat. I have never done this setup before and it has some specific things, so I prefer to write an entry and do not lose time if I need this a second time. The kerberos/spnego login can be configured by default in tomcat, you do not need anything extra. The entry will comment step by step the configuration.
Install the last version of tomcat (9.0.6 right now).
unzip apache-tomcat-9.0.6.zip cd apache-tomcat-9.0.6/bin chmod u+x *.sh
Create the kerberos user for the service principal name (SPN), this is always the same and commented in all the previous entries about kerberos. I am going to use a machine called jboss.sample.com, so the user is created as follows.
In the account tab the options Password never expires and This account supports Kerberos AES 256 bit encryption are selected.
Then the keytab is created with all the cartographic algorithms.
ktpass -princ HTTP/jboss.sample.com@SAMPLE.COM -mapuser jboss@SAMPLE.COM -pass XXXXX -crypto ALL -ptype KRB5_NT_PRINCIPAL -out jboss-all.keytab
Follow the instructions in the tomcat site to configure kerberos in the continer. Some files need to be prepared in the conf directory of the installation. First the krb5.ini is configured (I reused a previous vm, my windows server is a 2016 essentials called sampleserver.sample.com).
[libdefaults] default_realm = SAMPLE.COM default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes256-cts aes128-cts-hmac-sha1-96 aes128-cts rc4-hmac default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes256-cts aes128-cts-hmac-sha1-96 aes128-cts rc4-hmac permitted_enctypes = aes256-cts-hmac-sha1-96 aes256-cts aes128-cts-hmac-sha1-96 caes128-cts rc4-hmac forwardable = true dns_lookup_realm = false dns_lookup_kdc = false [realms] SAMPLE.COM = { kdc = sampleserver.sample.com default_domain = SAMPLE.COM } [domain_realm] .SAMPLE.COM = SAMPLE.COM SAMPLE.COM = SAMPLE.COM
Then the jaas.conf is configured to use the previous keytab, which is also copied to the conf directory.
com.sun.security.jgss.krb5.initiate { com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=true principal="HTTP/jboss.sample.com@SAMPLE.COM" useKeyTab=true keyTab="/opt/jboss/apache-tomcat-9.0.6/conf/jboss-all.keytab" storeKey=true debug=true; }; com.sun.security.jgss.krb5.accept { com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=true principal="HTTP/jboss.sample.com@SAMPLE.COM" useKeyTab=true keyTab="/opt/jboss/apache-tomcat-9.0.6/conf/jboss-all.keytab" storeKey=true debug=true; };
Add some options to the tomcat startup, I added them to the beginning of the catalina.sh. Those options are to add debug and the configuration for the previous files.
# krb5 opts JAVA_OPTS="$JAVA_OPTS -Djava.security.krb5.conf=/etc/tomcat/krb5.ini -Djava.security.auth.login.config=/etc/tomcat/jaas.conf -Dsun.security.krb5.debug=true -Dsun.security.spnego.debug=true -Djava.security.egd=file:/dev/./urandom"
Finally an AD realm should be added as the user repository for tomcat (the user will be authenticated using SPNEGO and then the user will be searched in the AD for groups). This point is the one that is very specific for tomcat (at least for me), until I understood that I needed to create a valid realm for the kerberos login I was a bit lost. A JNDI realm is added and configured to search the user and get the roles via the memberOf attribute in the user (no role search, roles will be the complete DN).
<Realm className="org.apache.catalina.realm.JNDIRealm" resourceName="UserDatabase" debug="9" connectionName="cn=Admin,cn=users,dc=sample,dc=com" connectionPassword="XXXXX" connectionURL="ldap://sampleserver.sample.com:389" userRoleName="memberOf" userBase="cn=users,dc=sample,dc=com" userSearch="(&(objectClass=user)(sAMAccountName={0}))" userSubtree="true" useDelegatedCredential="false" />
And that is all. Now you just need to deploy the application that should be configured to use a SPNEGO login configuration. In my case the app is a simple JSP and the web.xml just protects all the application.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <display-name>hello-spnego-tomcat</display-name> <security-constraint> <display-name>Protect all app</display-name> <web-resource-collection> <web-resource-name>exampleWebApp</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>*</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>SPNEGO</auth-method> <realm-name>SPNEGO</realm-name> </login-config> <security-role> <description>Role required to log in to the Application</description> <role-name>*</role-name> </security-role> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
And the JSP uses this idea to get the GSSCredential which could be used to delegate the token to another web service (calling another web service or, in general, reuse the kerberos token for delegation). In tomcat the credential is inside its specific principal implementation.
This is the video of the single sign-on using the kerberos token.
Today's entry is simple, just a kerberos application using tomcat and the default spnego authentication to provide SSO in a windows environment. I personally had never configured tomcat to use kerberos and it always takes some time to setup new things. A JNDI realm is needed, the user obtained via kerberos is searched in the AD and the principal is created (username, roles and GSS credential are stored inside the principal). The configuration for the web application has no special characteristics. My simple JSP to test in in this war file (I have not even created a maven to test this).
Regards!
Comments