1) The test scenario
The scenario is that we have two KDCs. The first KDC has realm "realma.apache.org", with users "alice" and "bob/service.realma.apache.org". The second KDC has realm "realmb.apache.org", with users "carol" and "dave/service.realmb.apache.org". We have a single service with two different endpoints - one which will authenticate users in "realma.apache.org", and the second that will authenticate users in "realmb.apache.org". Both endpoints have keytabs that we have exported from the KDC for "bob" and "dave".
2) Kerberos configuration
Both endpoints have to share the same Kerberos configuration, due to the fact that Java uses system properties to set up JAAS with the Krb5LoginModule. We need to set the following system properties:
- java.security.auth.login.config - The path to the JAAS configuration file for the Krb5LoginModule
- java.security.krb5.conf - The path to the krb5.conf kerberos configuration file
Here we have two entries for "bob" and "dave", each pointing to a keytab file. Note that the principal contains the realm name. This is important as we have no default_realm in the krb5.conf file. The krb5.conf file looks like this:
Here we configure how to reach both KDCs for our different realms.
3) Service configuration
Next, we'll look at how to configure the services. We will show how it's done for a JAX-WS service, but similar configuration exists for JAX-RS. The client will pass the kerberos token in a BinarySecurityToken security header in the message, according to the WS-Security specs. We'll assume the service is using a WS-SecurityPolicy that requires a kerberos token (for more details see here). Here is a sample spring configuration for an endpoint for "dave":
We have a JAX-WS endpoint with a "ws-security.bst.validator" property which points to a KerberosTokenValidator instance. This tells CXF to process a received BinarySecurityToken with the KerberosTokenValidator.
The KerberosTokenValidator is configured with a CallbackHandler implementation, to supply a username and password (see here for a sample implementation). Note that this is not required normally when we have a keytab file, but it appears to be required when we do not define a default realm. The KerberosTokenValidator instance also defines the JAAS context name, as well as the fully qualified principal name. As this is in service name form, we have to set the property "usernameServiceNameForm" to "true" as well.
If we set up the endpoint for "bob" with similar configuration, then our krb5.conf doesn't need the "default_realm" property and we can successfully validate tickets for both realms.