Hi all,
I’ve been trying to create and test a CXF client that’s consuming a web service
secured with SPNEGO/Kerberos authentication on a Windows 2008 server. I’m
neither a Windows nor a security guru by any stretch of the imagination, but
mainly following Groovy Tom’s advice at
http://groovyjava-tom.blogspot.com/2012/01/cxf-and-ms-crm-2011.html, I believe
I’ve gotten very close to making this work. I’ve hit a snag near the end,
though, that I’m hoping someone here can provide me some insight into.
I’ve created the web service client from the WSDL using CXF without issue, and
my test code is essentially wrapping the basics there with what I found in the
blog post. Here’s the code:
System.setProperty("java.security.auth.login.config",
"/home/developer/apache-cxf-2.7.14/login.conf");
System.setProperty("java.security.krb5.conf",
"/home/developer/apache-cxf-2.7.14/krb5.conf");
System.setProperty("sun.security.krb5.debug", "true");
AgentInventoryService service = new AgentInventoryService();
IAgentInventoryService port = service.getWSHttpBindingIAgentInventoryService();
Client client = ClientProxy.getClient(port);
client.getRequestContext().put("ws-security.kerberos.jaas.context",
"spnego-client");
client.getRequestContext().put("ws-security.kerberos.spn",
"RestrictedKrbHost/nxesideploy4");
client.getRequestContext().put("ws-security.spnego.client.action", new
XRMSpnegoClientAction());
Bus bus = ((EndpointImpl) client.getEndpoint()).getBus();
PolicyInterceptorProviderRegistry pipr =
bus.getExtension(PolicyInterceptorProviderRegistry.class);
pipr.register(new XRMAuthPolicyProvider());
CallbackHandler callbackHandler = new NamePasswordCallbackHandler(kuser, kpass);
client.getRequestContext().put("ws-security.callback-handler", callbackHandler);
STSClient sts = new STSClient(bus);
sts.setFeatures(Arrays.asList(new Feature() {
@Override
public void initialize(Server server, Bus bus) {
}
@Override
public void initialize(Client client, Bus bus) {
bus.getProperties().put("soap.no.validate.parts", true);
}
@Override
public void initialize(InterceptorProvider interceptorProvider, Bus bus) {
}
@Override
public void initialize(Bus bus) {
}
}));
client.getRequestContext().put("ws-security.sts.client", sts);
AgentUser agentUser = new AgentUser();
agentUser.setAgentId("007-DEF");
agentUser.setFirstName("Mark");
agentUser.setLastName("Durant");
Integer result = port.save(agentUser);
System.out.println("result = " + result);
I’ve tested my krb5.conf with kinit, and it’s working fine. With Kerberos
debugging on, I can see that that part of the application is working, too.
After getting that token, though, the library seems to gets caught in a loop,
continually reaching out to the domain controller for a new token. The looping
starts in SpnegoContextTokenOutInterceptor's handleMessage(SoapMessage) call:
It tries to get the "ws-security.token.id" from the message, but it's not
there; so seeing that it has a null token, it requests a security token from
the STSClient, and that request gets caught up in the same interceptor where
the ws-security.token.id is null, and it just keeps rolling from there under I
get a StackOverflow error. Here’s the stack trace:
Jan 23, 2015 12:46:23 PM org.apache.cxf.phase.PhaseInterceptorChain
doDefaultLogging
WARNING: Interceptor for
{http://schemas.xmlsoap.org/ws/2005/02/trust/wsdl}SecurityTokenService#{http://schemas.xmlsoap.org/ws/2005/02/trust/wsdl}RequestSecurityToken
has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: General security error (An error occurred in
trying to obtain a TGT: java.lang.StackOverflowError
at java.net.PlainDatagramSocketImpl.receive0(Native Method)
at
java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:145)
at java.net.DatagramSocket.receive(DatagramSocket.java:786)
at sun.security.krb5.internal.UDPClient.receive(NetClient.java:207)
at sun.security.krb5.KdcComm$KdcCommunication.run(KdcComm.java:386)
at sun.security.krb5.KdcComm$KdcCommunication.run(KdcComm.java:339)
at java.security.AccessController.doPrivileged(Native Method)
at sun.security.krb5.KdcComm.send(KdcComm.java:323)
at sun.security.krb5.KdcComm.send(KdcComm.java:219)
at sun.security.krb5.KdcComm.send(KdcComm.java:191)
at sun.security.krb5.KrbAsReqBuilder.send(KrbAsReqBuilder.java:319)
at sun.security.krb5.KrbAsReqBuilder.action(KrbAsReqBuilder.java:364)
at
com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:721)
at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:580)
at sun.reflect.GeneratedMethodAccessor16.invoke(Unknown Source)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:784)
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:203)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:698)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:696)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:695)
at javax.security.auth.login.LoginContext.login(LoginContext.java:594)
at
org.apache.ws.security.spnego.SpnegoTokenContext.retrieveServiceTicket(SpnegoTokenContext.java:121)
at
org.apache.ws.security.spnego.SpnegoTokenContext.retrieveServiceTicket(SpnegoTokenContext.java:89)
at
org.apache.ws.security.spnego.SpnegoTokenContext.retrieveServiceTicket(SpnegoTokenContext.java:70)
at
org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.issueToken(SpnegoContextTokenOutInterceptor.java:114)
at
org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.handleMessage(SpnegoContextTokenOutInterceptor.java:73)
at
org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.handleMessage(SpnegoContextTokenOutInterceptor.java:46)
at
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:572)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:481)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:382)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:335)
at
org.apache.cxf.ws.security.trust.AbstractSTSClient.issue(AbstractSTSClient.java:855)
at
org.apache.cxf.ws.security.trust.STSClient.requestSecurityToken(STSClient.java:62)
at
org.apache.cxf.ws.security.trust.STSClient.requestSecurityToken(STSClient.java:56)
at
org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.issueToken(SpnegoContextTokenOutInterceptor.java:134)
at
org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.handleMessage(SpnegoContextTokenOutInterceptor.java:73)
at
org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.handleMessage(SpnegoContextTokenOutInterceptor.java:46)
at
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:572)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:481)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:382)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:335)
at
org.apache.cxf.ws.security.trust.AbstractSTSClient.issue(AbstractSTSClient.java:855)
at
org.apache.cxf.ws.security.trust.STSClient.requestSecurityToken(STSClient.java:62)
at
org.apache.cxf.ws.security.trust.STSClient.requestSecurityToken(STSClient.java:56)
at
org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.issueToken(SpnegoContextTokenOutInterceptor.java:134)
at
org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.handleMessage(SpnegoContextTokenOutInterceptor.java:73)
at
org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.handleMessage(SpnegoContextTokenOutInterceptor.java:46)
at
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
That repeats until the application dies.
This is all done with CXF 2.7.14. I tried it with 3.0.3 originally, and hit
the same problem, but backed down to 2.7 since that was where the blog post was
successful.
If there’s anything else I can provide that might give a hint about what’s
happening, please let me know.
Thanks,
Mark