Tuesday, October 11, 2011

Using Kerberos with Web Services - part II

This is the second of a two-part series on using Kerberos with Web Services, with Apache WSS4J and CXF. Part I showed how to set up a KDC distribution, and how to generate client and service principals to use in some CXF system tests. The system tests showed how to obtain a Kerberos token from a KDC, package it in a BinarySecurityToken, and send it to a service endpoint for validation. In other words, part I illustrated how to use Kerberos for client authentication in a web service setting.

This article builds on part I by showing how to use the secret key associated with a Kerberos Token to secure (sign and encrypt) the request. This functionality was added as part of WSS4J 1.6.3, and the related WS-SecurityPolicy functionality was released as part of CXF 2.4.3.

1) Setting up the Kerberos system tests in Apache CXF 

If you have not done so already, follow the instructions in part I to install a Kerberos distribution and to generate client and service principals to run the CXF Kerberos system tests. The KerberosTokenTest in Apache CXF contains a number of different Kerberos tests. In this article we will examine the tests that involve obtaining a Kerberos Token, and using the associated secret key to secure some part of the request.

Firstly, make sure that the JDK has unlimited security policies installed, and then checkout the CXF trunk via:
svn co https://svn.apache.org/repos/asf/cxf/trunk/
Go into the "trunk" directory, and compile and install CXF via "mvn -Pfastinstall" (this will avoid running tests). Finally go into the WS-Security system tests in "systests/ws-security"

1.1) Installing a custom KerberosTokenDecoder


Once the client obtains an AP-REQ token from the KDC, the client also has easy access to the session key, which can be used to secure the request in some way. Unfortunately, there appears to be no easy way to obtain the session key on the receiving side. WSS4J does not support extracting a Kerberos session key on the receiving side to decrypt/verify a secured request out-of-the-box. Instead, a KerberosTokenDecoder interface is provided, which defines methods for setting the AP-REQ token and current Subject, and a method to then get a session key. An implementation must be set on the KerberosTokenValidator to obtain a session key to decrypt or verify a signed request.

To run the Kerberos system tests that require a secret key on the receiving side, download an implementation of the KerberosTokenValidator interface here, and copy it to "systests/ws-security/src/test/java/org/apache/cxf/systest/ws/kerberos/server". The implementation is based on code written by the Java Monkey, and uses internal sun APIs, and so can't be shipped in Apache CXF/WSS4J. Once this implementation has been copied into the ws-security module, then you must compile or run any tests with the "-Pnochecks" profile enabled, as otherwise the code fails checkstyle.

Open the server configuration file ("src/test/resources/org/apache/cxf/systest/ws/kerberos/server/server.xml"), and uncomment the "kerberosTicketDecoderImpl" bean, and the property of the "kerberosValidator" bean that refers to it:
<bean id="kerberosTicketDecoderImpl"   class="org.apache.cxf.systest.ws.kerberos.server.KerberosTokenDecoderImpl"/>

<bean id="kerberosValidator"
       class="org.apache.ws.security.validate.KerberosTokenValidator">
        <property name="contextName" value="bob"/>
        <property name="serviceName" value="bob@service.ws.apache.org"/>
        <property name="kerberosTokenDecoder" ref="kerberosTicketDecoderImpl"/>
</bean>
1.2) Running the tests

Open KerberosTokenTest.java and comment out the "@org.junit.Ignore" entries for the last four tests, "testKerberosOverTransportEndorsing", "testKerberosOverAsymmetricEndorsing", "testKerberosOverSymmetricProtection" and "testKerberosOverSymmetricDerivedProtection". Finally, run the tests via:
mvn -Pnochecks test -Dtest=KerberosTokenTest -Djava.security.auth.login.config=src/test/resources/kerberos.jaas
2) The tests in more detail

In this section, we'll look at the tests in more detail. 

2.1) WS-SecurityPolicy configuration

The wsdl that defines the service endpoints contains WS-SecurityPolicy expressions that define the security requirements of the endpoints. The following security policies are used for the four tests defined above:
  • testKerberosOverTransportEndorsing: A (one-way) transport binding is defined, with a KerberosToken required as an EndorsingSupportingToken. 
  • testKerberosOverAsymmetricEndorsing: An asymmetric binding is used, where a KerberosToken is required as an EndorsingSupportingToken.
  • testKerberosOverSymmetricProtection: A symmetric binding is used, where a KerberosToken is specified as a ProtectionToken of the binding.
  • testKerberosOverSymmetricDerivedProtection: The same as the previous test-case, except that any secret keys that are used must be derived.
The first two test-cases use an EndorsingSupportingToken, which means that the secret key associated with the KerberosToken is used to sign (endorse) some message part (the timestamp for the Transport binding). This illustrates proof-of-possession. For the latter two test-cases, the KerberosToken is defined as a ProtectionToken, meaning that the secret key is used to sign/encrypt the request (e.g. instead of using an X.509 Token to encrypt a session key).

2.2) Kerberos LoginModule configuration

Both the CXF client and service endpoint use JAAS to authenticate to the KDC. The JAAS file used as part of the system test is passed to the tests via the System property "java.security.auth.login.config". The client (alice) uses the following login module:
alice {
    com.sun.security.auth.module.Krb5LoginModule required
    refreshKrb5Config=true useKeyTab=true keyTab="/etc/alice.keytab"
    principal="alice";
};
and the service endpoint (bob) uses:
bob {
    com.sun.security.auth.module.Krb5LoginModule required
    refreshKrb5Config=true useKeyTab=true storeKey=true
    keyTab="/etc/bob.keytab" principal="bob/service.ws.apache.org";
};
2.3) Service endpoint configuration

The service endpoints are spring-loaded. Each endpoint definition contains the JAX-WS property "ws-security.bst.validator" which is defined in SecurityConstants. WSS4J uses Validator implementations to perform validation on received security tokens. This particular property means that BinarySecurityTokens are to be validated by the given reference, e.g.:

<jaxws:endpoint ...>
    <jaxws:properties>      
        <entry key="ws-security.bst.validator" value-ref="kerberosValidator"/>
    </jaxws:properties>
</jaxws:endpoint>
"kerberosValidator" is a KerberosTokenValidator instance given above. It requires a "contextName" property, which corresponds to the JAAS context name, as well as an optional "serviceName" property, and an optional "kerberosTokenDecoder" property to use to obtain a secret key. Combined with the JAAS properties file, this is all that is required for the service endpoint to validate a received Kerberos Token. 

2.4 Client configuration

Finally, the client must contact a KDC and obtain a Kerberos Token, once it sees that the service endpoint has a security policy that requires a KerberosToken. The client configuration is available here. A sample configuration for the Kerberos Test case is as follows:
<jaxws:client name="{...}DoubleItKerberosTransportPort"
       createdFromAPI="true">
       <jaxws:properties>
           <entry key="ws-security.kerberos.client">
               <bean class="org.apache.cxf.ws.security.kerberos.KerberosClient">
                   <constructor-arg ref="cxf"/>
                   <property name="contextName" value="alice"/>
                   <property name="serviceName" value="bob@service.ws.apache.org"/>
               </bean>           
           </entry>
       </jaxws:properties>
</jaxws:client>
The JAX-WS property "ws-security.kerberos.client" (again, defined in SecurityConstants) corresponds to a KerberosClient object. Similar to the KerberosTokenValidator on the receiving side, this is configured with a JAAS context Name and service Name.

3 comments:

  1. Hi, I wonder if you can help me. I have to do a web service that shows this kind of structure during WS consumption:

    soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsk="...

    soapenv:Body>

    <ws:

    I put just the part I need to fit.
    I've checked on internet and it look like this have sort of kerberos integration, but I can't reach it.

    ReplyDelete
  2. I don't know how to change the definition from ws to wsk

    ReplyDelete

  3. Feel free to ask on the CXF user list: http://cxf.apache.org/mailing-lists.html

    Colm.

    ReplyDelete