Hi All,

The attached patch (against 3.0.4 git) implements an additional property, useCanonicalHostname, which is supported by the AbstractSpnegoAuthSupplier, and therefore available to SpnegoAuthSupplier and KerberosAuthOutInterceptor.

The default behavior is not modified. If useCanonicalHostname is set, then the service principal will be created using the canonical name of the remote host.

For example, if there is a CNAME DNS record for host.example.com which refers to an A record host-a-b-c.example.com, the default behavior would be to generate a service principal HTTP/host.example.com. When useCanonicalHostname is set to true, the service principal would be HTTP/host-a-b-c.example.com. Most browsers and many other HTTP user agents perform this kind of canonicalization.

This can be configured in XML as follows:

<bean id="myAuthSupplier" class="org.apache.cxf.transport.http.auth.SpnegoAuthSupplier">
         <property name="useCanonicalHostname" value="true" />
     </bean>
          <http-conf:conduit name="...">
         <http-conf:authorization>
             <sec:AuthorizationType>Negotiate</sec:AuthorizationType>
             <sec:Authorization>CXFClient</sec:Authorization>
         </http-conf:authorization>
                  <http-conf:authSupplier bean="myAuthSupplier" />
     </http-conf:conduit>


Or similarly for KerberosAuthOutInterceptor.

--
Thanks,
David Mansfield
Cobite, INC.

On 05/03/2015 10:20 AM, David Mansfield wrote:
FYI: this much I have confirmed.  Using the following class as
replacement to the default KerberosAuthOutInterceptor does the trick.

A small bit of refactoring and I should have this down in the Abstract
base class.

package com.cobite.cxf.interceptor;

import java.net.InetAddress;
import java.net.URI;
import java.util.logging.Level;

public class KerberosAuthOutInterceptor extends
org.apache.cxf.jaxrs.security.KerberosAuthOutInterceptor {
    private String realm;

    private String getCanonicalHostName(String hostName) {
    String canonicalHostName = hostName;
    try {
        InetAddress in = InetAddress.getByName(hostName);
        canonicalHostName = in.getCanonicalHostName();
        LOG.fine("resolved hostName="+hostName+" to
canonicalHostName="+canonicalHostName);
    } catch (Exception e) {
        LOG.warning("unable to resolve canonical hostname:
"+hostName+": "+e.getMessage());
    }
    return canonicalHostName;
    }
        @Override
    protected String getCompleteServicePrincipalName(URI currentURI) {
        String name = "HTTP/" +
getCanonicalHostName(currentURI.getHost());
        if (realm != null) {
            name += "@" + realm;
        }
        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("Service Principal Name is " + name);
        }
        return name;
    }

    public void setRealm(String realm) {
        this.realm = realm;
    }
}




diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java
index 95239cc..ca82401 100644
--- a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java
@@ -18,6 +18,7 @@
  */
 package org.apache.cxf.transport.http.auth;
 
+import java.net.InetAddress;
 import java.net.URI;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
@@ -62,6 +63,7 @@ public abstract class AbstractSpnegoAuthSupplier {
     private boolean credDelegation;
     private Configuration loginConfig;
     private Oid serviceNameType;
+    private boolean useCanonicalHostname;
     
     public String getAuthorization(AuthorizationPolicy authPolicy,
                                    URI currentURI,
@@ -154,8 +156,17 @@ public abstract class AbstractSpnegoAuthSupplier {
     }
 
     protected String getCompleteServicePrincipalName(URI currentURI) {
-        String name = servicePrincipalName == null 
-            ? "HTTP/" + currentURI.getHost() : servicePrincipalName;
+        String name;
+
+        if (servicePrincipalName == null) {
+            String host = currentURI.getHost();
+            if (useCanonicalHostname) {
+                host = getCanonicalHostname(host);
+            }
+            name = "HTTP/" + host;
+        } else {
+            name = servicePrincipalName;
+        }
         if (realm != null) {            
             name += "@" + realm;
         }
@@ -163,10 +174,20 @@ public abstract class AbstractSpnegoAuthSupplier {
             LOG.fine("Service Principal Name is " + name);
         }
         return name;
-            
-            
     }
-    
+
+    private String getCanonicalHostname(String hostname) {
+        String canonicalHostname = hostname;
+        try {
+            InetAddress in = InetAddress.getByName(hostname);
+            canonicalHostname = in.getCanonicalHostName();
+            LOG.fine("resolved hostname=" + hostname + " to canonicalHostname=" + canonicalHostname);
+        } catch (Exception e) {
+            LOG.log(Level.WARNING, "unable to resolve canonical hostname", e);
+        }
+        return canonicalHostname;
+    }
+
     public void setServicePrincipalName(String servicePrincipalName) {
         this.servicePrincipalName = servicePrincipalName;
     }
@@ -213,4 +234,12 @@ public abstract class AbstractSpnegoAuthSupplier {
         this.serviceNameType = serviceNameType;
     }
 
+    public boolean isUseCanonicalHostname() {
+        return useCanonicalHostname;
+    }
+
+    public void setUseCanonicalHostname(boolean useCanonicalHostname) {
+        this.useCanonicalHostname = useCanonicalHostname;
+    }
+
 }

Reply via email to