Integrating Shibboleth and Tomcat
This page describes some of the issues integrating Shibboleth and Tomcat.
Contents:
Contents
1. Versions
We're using tomcat 5.5.16, mod_jk connector 1.2.15 and the reference implementation of Shibboleth version 1.3c. We're running on a Linux (RedHat Enterprise / Scientific Linux) environment.
Our goal is to provide Shibboleth authenticatiion information to a Sakai portal server running under Tomcat, but the initial experiments described here have been conducted using one of the Tomcat example servlets /jsp-examples/snp/snoop.jsp, since this also echoes the remote username for the serviced request.
2. General setup
To perform Shibboleth authentication, we are using Apache httpd to front the Tomcat servlet environment. The Shibboleth service provider (the so-called C SP module) installs as an Apache module (mod_shib) and a supporting daemon process (shibd). The Apache server communicates with Tomcat using AJP/1.3 protocol via the JK connector.
Configuration details can be found at http://wiki.oss-watch.ac.uk/TomcatNotes#JKConnector.
Note in particular that the connector configuration in Tomcat's server.xml file must specify tomcatAuthentication="false" in order to recognize Apache https authentication (including the authenticated username, which is provided using a REMOTE_USER header):
<!-- Define an AJP 1.3 Connector on port 8009 --> <Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" address="127.0.0.1" tomcatAuthentication="false" />
We configure Shibboleth to set the value of REMOTE_USER to the value of urn:mace:dir:attribute-def:oucsPrimaryUsername, which itself was derived from the oucsPrimaryUsername in the underlying OUCS LDAP entry.
3. Apache httpd authentication and Tomcat
The above configuration is sufficient for Tomcat servlets to be able to retrieve the authenticated username using request.getRemoteUser(), but does not of itself establish servlet invocation as being authenticated. For this, it is necessary to place a <security-constraint> on the context URI that is used to invoke the servlet. This is done in the web applications web.xml file.
For example, to authenticate use of the "snoop.jsp" example page that is part of the standard Tomcat "jsp-examples" application, edit $CATALINA_HOME/webapps/jsp-examples/WEB-INF/web.xml to contain the following:
<security-constraint> <display-name>Snoop Security Constraint</display-name> <web-resource-collection> <web-resource-name>Snoop page</web-resource-name> <!-- Define the context-relative URL(s) to be protected --> <url-pattern>/snp/*</url-pattern> <!-- If you list http methods, only those methods are protected --> <http-method>DELETE</http-method> <http-method>GET</http-method> <http-method>POST</http-method> <http-method>PUT</http-method> </web-resource-collection> <auth-constraint> <!-- Anyone with one of the listed roles may access this area --> <role-name>*</role-name> </auth-constraint> </security-constraint>
This requires that any acess to /jsp-examples/snp/* be authenticated to any of the roles declared to Tomcat elsewhere in the web.xml file. The problem with this when receiving authentication information from Apache httpd via mod_jk is that we have not found any way to associate role membership with the authenticated user. As a result, Tomcat refuses access to the servlet, even though we do appear to have successfully conveyed authenticated user information to Tomcat.
It appears that when Tomcat's own authentication is bypassed (using tomcatAuthentication="false" noted above), Tomcat's mechanisms for assigning roles to users (e.g. from tomcat-users.xml) are also bypassed, so the authentication is effectively useless for invoking servlets.
Thus, we need to find another way of getting Tomcat to recognize Shibboleth authentication information, and thus provide authenticatuion services (JAAS) to the running servlet.
4. SPIE JAAS module
The SPIE JAAS module https://spie.oucs.ox.ac.uk/Wiki.jsp?page=JAASmodule2 can be used to provide attributes from a Shibboleth SAML assertion conveyed in an HTTP request header via normal servlet authentication interfaces (i.e. as principals in a JAAS framework structure).
Grab 3 .jar files and 1 .war file from http://rts-anoncvs.oucs.ox.ac.uk/cgi-bin/cvsweb/SpieJaas/dist/; e.g. yielding:
spiejaasmodule.1.15.jar spiejaasprincipals.1.13.jar spiejaaswebappsupport.1.16.jar spietestservlet.1.21.war
Copy the 3 .jar files to $CATALINA_HOME/common/lib/
Copy the .war file to $CATALINA_HOME/webapps/
Add path "/spietestservlet" to those that are services via mod_jk, by adding something like the following line to /etc/httpd/conf.d/jk.conf:
JkMount /spietestservlet/* ajp13w
Add a line like this to the Cataline startup script $CATALINA_HOME/bin/startup.sh:
export CATALINA_OPTS="-Djava.security.auth.login.config=$CATALINA_HOME/conf/SpieJaas.conf"
and create a file $CATALINA_HOME/conf/SpieJaas.conf thus:
SpieJaas { uk.ac.oxford.middleware.auth.shib.SpieJaasModule required; };
SpieJaas { uk.ac.oxford.middleware.auth.shib.SpieJaasModule required debug=true; };
For Servlet Container-based authentication, tell Tomcat which JAAS Module to use by defining a JAASRealm within an <Engine>, <Host> or <Context> at $CATALINA_HOME/conf/server.xml (we are placing this within the <engine name="Catalina" ...> element):
<Realm className="org.apache.catalina.realm.JAASRealm" appName="SpieJaas" userClassNames="uk.ac.oxford.middleware.auth.shib.SpieShibPrincipal" roleClassNames="uk.ac.oxford.middleware.auth.shib.SpieShibRole" debug="99"/>
Force Shibboleth authentication when accessing the SPIE test servlet, by adding this to file /etc/httpd/conf.d/shib-sp.conf (or shib.conf in a default Shibboleth installation):
<Location /spietestservlet> AuthType shibboleth ShibRequireSession On ShibExportAssertion On require valid-user </Location>
- Restart httpd, shibd and tomcat:
Stuart: This much seems to work now with the spietestservlet. (This servlet is v. useful -- check out the headers display!) I've applied an edit to resolver.ldap.xml so that oucsPrimaryName is released as eduPersonPrincipalName (noted on the relevant wiki page). Next steps are to (a) repeat tests with the jsp-example snoop page - this gives us a kind of independent test Done - see below. Then return to testing the Sakai login.
Testing with spietestservlet to date shows we are getting the username into the JAAS module. The notes below indicate how roles might (should?) be handled. This may need a touch of fancy LDAP mapping?
The following was added to SakaiVre/SakaiUserDirectoryProvider, but I think some of it also belongs here, so I've duplicated it for now.
In order to get Shib-EP-Principalname passed to Tomcat, uncomment the following in AAP.xml (and edit the "Header=" attribute if necessary):
<AttributeRule Name="urn:mace:dir:attribute-def:eduPersonPrincipalName" Scoped="true" Header="Shib-EP-EduPersonPrincipalName" Alias="user"> <AnySite> <Value Type="regexp">^[^@]+$</Value> </AnySite> </AttributeRule>
The refers to application context parameters or servlet init parameters that may be defined in the application's web.xml configuration file. This example comes from the SPIE test servlet configuration:
<context-param> <!-- use this attribute as username when logging in --> <param-name>attributeAsUsername</param-name> <param-value>Shib-EP-PrincipalName</param-value> <!-- Recommended attributes are Shib-EP-PrincipalName, Shib-EP-TargetedId, ... that uniquely identify a user --> </context-param> <context-param> <!-- the value(s) of this shib-attribute will be used as JAAS roles --> <param-name>attributeAsRoles</param-name> <param-value>Shib-EP-Entitlement</param-value> </context-param>
Here, parameter 'attributeAsUsername' indicates Shibboleth attributes that are mapped to JAAS principals, and 'attributeAsRoles' indicates an attribute that conveys roles that have been assigned to the authenticated user.
4.1. Testing with https://wayf.internet2.edu/InQueue/sample.jsp
The login procedure proceeds as expected, and the test page displays the following information. Of particular note is that we're now seeing Shib-EP-PrincipalName, which is the Shibboleth attribute name used (by the SPIE project, at least) for conveying the user id information to an application/portal.
- Shib-Origin-Site is: urn:mace:inqueue:oucs.ox.ac.uk
- Shib-Identity-Provider is: urn:mace:inqueue:oucs.ox.ac.uk
Shib-Authentication-Method is: urn:oasis:names:tc:SAML:1.0:am:unspecified
- Shib-Person-surname is: Klyne
Shib-InetOrgPerson-displayName is: Graham Klyne
Shib-EP-PrincipalName is: XXXXXX@oucs.ox.ac.uk
Shib-InetOrgPerson-initials is: G
Shib-InetOrgPerson-givenName is: Graham
- Shib-Person-commonName is: Graham Klyne
The attribute in the SAML assertion corresponding to Shib-EP-PrincipalName is this:
<Attribute AttributeName="urn:mace:dir:attribute-def:eduPersonPrincipalName" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri"> <AttributeValue Scope="oucs.ox.ac.uk">XXXXXX</AttributeValue> </Attribute>
(I've obscured my actual Oxford login name above as XXXXXX, but the values actually given were correct.)
This actually tests less than the JAAS test module, since it only echos what is provided by the InQueue sample.jsp in conjunction with its AAP.
I'm currently a little puzzled by this result - does it mean that the inQueue AAP happens to contain the same AttributeRule as we have just created?
5. References
-- StuartYeates 2006-07-12 14:06:24

