Hi all,
I'm wrestling with a problem getting my CXF implementation working with a
WCF-based web service that's using wsHttpBindings and SPNEGO/Kerberos
authentication. I've tried several approaches that fail at different points
for different reasons that I'm trying to untangle, but the one below seems
closest (the "{...}" strings are deliberately-removed content for this post):
System.setProperty("java.security.auth.login.config",
"C:\\temp\\apache-cxf-3.3.0\\login.conf");
System.setProperty("java.security.krb5.conf",
"C:\\temp\\apache-cxf-3.3.0\\krb5.ini");
// System.setProperty("sun.security.krb5.debug", "true");
URL wsdl = new
URL("http://{...}/WebServices/AgentInventoryService.svc?wsdl");
QName serviceName
= new QName("{...}/AgentInventory", "AgentInventoryService");
AgentInventoryService service = new AgentInventoryService(wsdl,
serviceName);
IAgentInventoryService iAgentInventoryService =
service.getWSHttpBindingIAgentInventoryService();
Client client = ClientProxy.getClient(iAgentInventoryService);
client.getRequestContext().put("ws-security.kerberos.jaas.context",
"CXFClient");
client.getRequestContext().put("ws-security.kerberos.spn",
"krbtgt/{...}");
client.getRequestContext().put("ws-security.callback-handler",
new NamePasswordCallbackHandler("{...}", "{...}"));
client.getRequestContext().put("ws-security.spnego.client.action", new
XRMSpnegoClientAction());
HTTPConduit httpConduit = (HTTPConduit) client.getConduit();
AuthorizationPolicy authorization = new AuthorizationPolicy();
authorization.setUserName("{...}");
authorization.setPassword("{...}");
authorization.setAuthorizationType(HttpAuthHeader.AUTH_TYPE_NEGOTIATE);
authorization.setAuthorization("CXFClient");
httpConduit.setAuthorization(authorization);
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(36000);
httpClientPolicy.setAllowChunking(false);
httpClientPolicy.setReceiveTimeout(32000);
httpConduit.setClient(httpClientPolicy);
iAgentInventoryService.getAgentUserByAgentId("1");
The XRMSpnegoClientAction is custom, lifted from a post I found somewhere, and
is this:
class XRMSpnegoClientAction implements SpnegoClientAction {
private static final Logger LOG =
LoggerFactory.getLogger(DefaultSpnegoClientAction.class);
private String serviceName;
private GSSContext secContext;
private boolean mutualAuth;
private boolean isUsernameServiceNameForm;
public void setMutualAuth(boolean mutualAuthentication) {
this.mutualAuth = mutualAuthentication;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public byte[] run() {
try {
GSSManager gssManager = GSSManager.getInstance();
Oid oid = new Oid("1.3.6.1.5.5.2");
GSSName gssService = gssManager.createName(serviceName,
GSSName.NT_USER_NAME);
secContext = gssManager.createContext(gssService, oid, null,
GSSContext.DEFAULT_LIFETIME);
secContext.requestMutualAuth(mutualAuth);
secContext.requestCredDeleg(Boolean.FALSE);
byte[] token = new byte[0];
return secContext.initSecContext(token, 0, token.length);
} catch (GSSException e) {
e.printStackTrace();
}
return null;
}
public GSSContext getContext() {
return this.secContext;
}
public void setUserNameServiceForm(boolean isUsernameServiceNameForm) {
this.isUsernameServiceNameForm = isUsernameServiceNameForm;
}
}
Sadly, I'm not entirely clear on what this is doing, but without it I get
Kerberos errors about the server not being found. With it, I seem to pass the
pre-auth, but then some other authentication fails when I get down to the
actual iAgentInventoryService.getAgentUserByAgentId("1") call.
It looks like my HttpConduit and AuthorizationPolicy that I think I'm attaching
to the Client aren't being used, so maybe I'm attaching them wrong...?
This may jog the memory of some folks who've been on here for many years, as I
wrestled with the same problem in a different way back then, and posted here
for help. Colm was able to bring me a good way toward the goal, but we
couldn't get over the final hurdle, and I had to let it go. I'm back at it
now, hoping the latest release would get me over previous hurdles.
Last note: I have confirmed successful Kerberos ticket negotiation with this
code:
System.setProperty("java.security.auth.login.config",
"C:\\temp\\apache-cxf-3.3.0\\login.conf");
System.setProperty("java.security.krb5.conf",
"C:\\temp\\apache-cxf-3.3.0\\krb5.ini");
// System.setProperty("sun.security.krb5.debug", "true");
LoginContext lc = new LoginContext("CXFClient", new
NamePasswordCallbackHandler("{...}", "{...}"));
lc.login();
Subject subject = lc.getSubject();
Set<Principal> principals = subject.getPrincipals();
Set<Object> credentials = subject.getPrivateCredentials();
System.out.println("OK: " + principals);
System.out.println("OK: " + credentials);
Is there anything obviously wrong with what I'm doing here, or is there a
better approach that I might try for this type of integration? It's been a
long and painful week trying to make this work. ;)
Thanks,
Mark