Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

 

 

{span:style=
Span
Wiki Markup
style
font-size:2em;font-weight:bold
} JAX-RS Kerberos Support {span}Support
 

 

 

Table of Contents

Introduction

Please see MIT Kerberos Tutorial for a good introduction to Kerberos.
The Windows guide as well as this Wikipedia page are also worth checking.

...

'Negotiate' authentication scheme is used to pass Kerberos service tickets over HTTP.
Example:

Code Block
java
java

Authorization: Negotiate "the encrypted service ticket"

...

As explained on this page, 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 Block
java
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);

...

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.

When the "servicePrincipalName" is not specified, the target host from the provided endpoint URL is used to construct one as-is.  To perform canonicalization of this hostname (e.g. if a CNAME record host.example.com points to an A record host-x.example.com, then use "host-x.example.com" when constructing the servicePrincipalName), the "useCanonicalHostname" property can be set to "true".

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.

...

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 Block
xml
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>

...

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 Block
java
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();
 }
}

...

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 Block
java
java


import org.ietf.jgss.GSSCredential;

import org.apache.cxf.jaxrs.security.KerberosAuthenticationFilter;
import org.apache.cxf.jaxrs.security.KerberosAuthenticationFilter.KerberosSecurityContext;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.security.SecurityContext;

@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");
       SecurityContext securityContext = PhaseInterceptorChain.getCurrentMessage().get(SecurityContext.class);

       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); 
   }

}

...