Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Wiki Markup
{span:style=font-size:2em;font-weight:bold} JAX-RS Kerberos Support {span}

{toc}

h1. Introduction

Please see [MIT Kerberos Tutorial|http://www.kerberos.org/software/tutorial.html] for a good introduction to Kerberos.
The [Windows guide|http://msdn.microsoft.com/en-us/library/aa378747%28v=vs.85%29] is also worth checking.

h2. Setup

h3. Unix

TODO

h3. Windows

Please check the relevant Windows configuration guide such as [this one|http://technet.microsoft.com/en-us/library/cc753173%28v=ws.10%29].

h2. HTTP Negotiate scheme 

'Negotiate' authentication scheme is used to pass Kerberos service tickets over HTTP.
Example:
{code:java}
Authorization: Negotiate "the encrypted service ticket"
{code} 

h2. GSS API

Please see [this|http://docs.oracle.com/javase/7/docs/technotes/guides/security/jgss/tutorials/index.html] GSS API tutorial as well as
 check this [blog|http://www.javaactivedirectory.com/] for a number of GSS API examples.

h1. Client configuration

h2. HTTPConduit

Please see [this page|http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-SpnegoAuthentication%28Kerberos%29] for the information about Spnego/Kerberos HTTPConduit client support. 

h2. Interceptor

org.apache.cxf.jaxrs.security.KerberosAuthOutInterceptor can be used as an alternative to configuring HTTPConduit.

KerberosAuthOutInterceptor and the HTTPConduit Spnego handler share the same base code. Having HTTPConduit configuration can be enough in many cases
especially when SSL is also being setup at the conduit level. Using the interceptor can be handy when testing as well as when setting few extra properties which is not easy to set up at the generic HTTP Conduit Authorization Policy level. 

The interceptor properties are explained in the following sub-sections

h3. Authorization Policy

As explained on [this page|http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-SpnegoAuthentication%28Kerberos%29], Authorization Policy typically needs to have its type set to "Negotiate" and its "authorization" property set to the name of the JAAS context. AuthorizationPolicy is set as a "policy" property on the interceptor, example:

{code:java}
WebClient wc = WebClient.create("http://localhost:" + PORT + "/bookstore/books/123");
        
KerberosAuthOutInterceptor kbInterceptor = new KerberosAuthOutInterceptor();
        
AuthorizationPolicy policy = new AuthorizationPolicy();
policy.setAuthorizationType(HttpAuthHeader.AUTH_TYPE_NEGOTIATE);
policy.setAuthorization("KerberosClientKeyTab");
        
kbInterceptor.setPolicy(policy);
WebClient.getConfig(wc).getOutInterceptors().add(kbInterceptor);
        
Book b = wc.get(Book.class);
{code}


h3. Configuring the service principal name

By default, the service principal name is calculated by concatenating "HTTP", "/" and the name of the target host, example, when invoking on "http://localhost:8080/services", the service principal name is set to "HTTP/localhost".

The "servicePrincipalName" and "realm" properties can be used to customize it, example, setting "servicePrincipalName" to "HTTP/www.mycompany.com" and realm to "services.org" will result in the "HTTP/www.mycompany.com@services.org" service principal name being used. 

h3. Using JAAS Configuration

Both HTTPConduit and interceptor handlers need a "java.security.auth.login.config" system property set up. This property needs to point to the file containing the configuration of the specific Kerberos login module.

Instead of setting this system property and maintaining a configuration file, one might want to use an implementation of javax.security.auth.login.Configuration and set it on the interceptor as a "loginConfig" property.    

h1. Server configuration

org.apache.cxf.jaxrs.security.KerberosAuthenticationFilter can be used to protected JAX-RS endpoints and enforce that a Negotiate authentication scheme is used by clients, example:

{code:xml}

<bean id="kerberosFilter" class="org.apache.cxf.jaxrs.security.KerberosAuthenticationFilter">
   <property name="loginContextName" value="KerberosServiceKeyTab"/>
</bean>

<jaxrs:server>
  <jaxrs:serviceBeans>
    <bean class="org.mycompany.MyCompanyResource"/>
  </jaxrs:serviceBeans>
  <jaxrs:providers>
    <ref bean="kerberosFilter">
  </jaxrs:providers>
</jaxrs:server>
{code}

KerberosAuthenticationFilter will set a CXF [SecurityContext|http://svn.apache.org/repos/asf/cxf/trunk/api/src/main/java/org/apache/cxf/security/SecurityContext.java] on the current message if the authentication has been successful. This SecurityContext will return an instance of KerberosAuthenticationFilter$KerberosPrincipal, this Principal will return a 'simple' and 'kerberos' source principal names, example, given "HTTP/localhost@myrealm.com", Principal#getName will return "HTTP/localhost", and KerberosPrincipal#getKerberosName will return "HTTP/localhost@myrealm.com".

h2. Service principal name and JAAS Configuration

Service principal name and JAAS Configuration can be optionally set up the same way they can be with KerberosAuthOutInterceptor, using 'servicePrincipalName' + 'realm' and "loginConfig" properties. 

h2. CallbackHandler

javax.security.auth.callback.CallbackHandler needs to be registered if no Kerberos key tabs are used, here is an example of setting it up from Java:

{code:java}
public class TestResource {
 public static void main(String[] args) {
   JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
   sf.setResourceClasses(BookStore.class);
   KerberosAuthenticationFilter filter = new KerberosAuthenticationFilter();
   filter.setLoginContextName("KerberosServer");
   
   CallbackHandler handler = 
     new org.apache.cxf.interceptor.security.NamePasswordCallbackHandler("HTTP/localhost", "http"); 
   filter.setCallbackHandler(handler);

   //filter.setLoginContextName("KerberosServerKeyTab");
   //filter.setServicePrincipalName("HTTP/ktab");
   sf.setProvider(filter);
   sf.setAddress("http://localhost:" + PORT + "/");
      
   sf.create();
 }
}
{code} 


h1. Credential Delegation

Please see this [section|http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-CredentialDelegation] on the way client-side credential delegation can be both enabled and implemented at the HTTP conduit level.

Note that if you have a JAX-RS KerberosAuthenticationFilter protecting the endpoints, then the filter will have an  org.ietf.jgss.GSSContext instance available in the current CXF SecurityContext, via its KerberosAuthenticationFilter$KerberosSecurityContext implementation, which can be used to get to  org.ietf.jgss.GSSCredential if the credential delegation is supported for a given source principal. The current credential if any can be set as a client property next, for example:

{code:java}

import org.ietf.jgss.GSSCredential;

import org.apache.cxf.jaxrs.security.KerberosAuthenticationFilter;
import org.apache.cxf.jaxrs.security.KerberosAuthenticationFilter.KerberosSecurityContext;

@Path("service")
public class MyResource {

   @Context 
   private javax.ws.rs.core.SecurityContext securityContext;

   @GET
   public Book getBookFromKerberosProtectedStore() {
       WebClient wc = webClient.create("http://internal.com/store");
       if (securityContext instanceof KerberosSecurityContext) {
           KerberosSecurityContext ksc = (KerberosSecurityContext)securityContext;
           GSSCredential cred = ksc.getGSSContext().getDelegCred();
           if (cred != null) {
               WebClient.getConfig(wc).getRequestContext().put(GSSCredential.class.getName(), cred);
           } 
       }
       return wc.get(Book.class); 
   }

}
{code}

The HTTPConduit or KerberosAuthOutInterceptor handler will use the available GSSCredential.


Also note that KerberosAuthOutInterceptor can have its "credDelegation" property set to "true" if it is used instead of HTTPConduit on the client side, when enabling the delegation initially.