Greetings all, I am attempting to connect to a .NET web service using CXF.
The requirements for the request's security headers are a Timestamp and a
BinarySecurityToken from an X509 Certificate. The response only includes a
Timestamp. I think it is important to note that I do not have any control
over the web service, and we were provided a public key by the vendor to use
for generating the BST, so we do not have the private key, nor a password
for the key.
I have been working from the CXF samples and have read every blog and
mailing list post I can find, but am still having trouble. I can
successfully generate the Timestamp, and even a UsernameToken (which is not
needed for this project), but I cannot get a BinarySecurityToken to
generate. When I add the 'Signature' action, I get this
NullPointerException:
/java.lang.NullPointerException at
org.apache.ws.security.message.WSSecSignature.getSigningCerts(WSSecSignature.java:786)/
I have read other posts that imply this error indicates the keystore either
cannot be found, or cannot be opened. I have tried putting the keystore in
my JAR as a resource, in the local directory I am running from, in a
different directory, explicitly referencing it in my classpath, etc., but to
no avail. If I include 'Signature' in the action, I get this error.
I would greatly appreciate any help I can get on this. Our team attempted
this task using Axis2 for several weeks, and now I'm just starting a new
approach using CXF and need to get it done ASAP. Now I seem to be at about
the same roadblock the Axis2 route got to...
Thank you all.
Note: in my source snippets, I have used {} to indicate masked items to
protect sensitive information
*Here is my cxf.xml file:*
/<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:client name="STWebService-CXF" createdFromAPI="true">
<jaxws:inInterceptors>
<ref bean="Timestamp_Response"/>
<bean
class="org.apache.cxf.ws.security.wss4j.DefaultCryptoCoverageChecker"/>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<ref bean="Timestamp_Request"/>
</jaxws:outInterceptors>
</jaxws:client>
<bean
class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"
id="Timestamp_Request">
<constructor-arg>
<map>
<entry key="action" value="Timestamp Signature"/>
<entry key="user" value="{key alias with spaces}"/>
<entry key="passwordType" value="PasswordDigest"/>
<entry key="signaturePropFile"
value="clientKeystore.properties"/>
</map>
</constructor-arg>
</bean>
<bean
class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"
id="Timestamp_Response">
<constructor-arg>
<map>
<entry key="action" value="Timestamp"/>
</map>
</constructor-arg>
</bean>
</beans>
/
*Here is my clientKeystore.properties file:*
/
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.file=public_cert.jks
org.apache.ws.security.crypto.merlin.keystore.password={keystorepass}
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.alias={key alias with spaces}
/
*Here is a snippet of my client, using the CXF-generated client until I can
get it working, then will be moving logic into my own classes:*
/
...
SpringBusFactory bf = new SpringBusFactory();
URL busFile = {Client}.class.getResource("/wssec.xml");
Bus bus = bf.createBus(busFile.toString());
BusFactory.setDefaultBus(bus);
// Out Interceptor
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put("action", "Timestamp Signature");
outProps.put("passwordType", "PasswordDigest");
outProps.put("user", "{key alias with spaces}");
outProps.put("passwordCallbackClass",
"{package}.KeystorePasswordCallback");
bus.getOutInterceptors().add(new WSS4JOutInterceptor(outProps));
// In Interceptor
Map<String, Object> inProps = new HashMap<String, Object>();
inProps.put("action", "Timestamp");
bus.getInInterceptors().add(new WSS4JInInterceptor(inProps));
SynchMethod ss = new SynchMethod(wsdlURL, SERVICE_NAME);
SynchMethodSoap port = ss.getSynchMethodSoap();
System.out.println("Invoking web service method...");
{package}.ArrayOfResponse _return = port.{method}({params...});
System.out.println("_rerturn=" + _return);
...
/
*
Here is my 'standard' KeystorePasswordCallback class:*
/
package {package}
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
/**
* Really callback for key passwords. Configure it with a map
* of key-alias-to-password mappings. Obviously this could
* be extended to encrypt or obfuscate these passwords if desired.
*/
public class KeystorePasswordCallback implements CallbackHandler
{
private Map<String, String> passwords = new HashMap<String, String>();
/**
* {@inheritDoc}
*
* @see
javax.security.auth.callback.CallbackHandler#handle(javax.security.auth.callback.Callback[])
*/
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof WSPasswordCallback) {
WSPasswordCallback pc = (WSPasswordCallback)callback;
String pass = passwords.get(pc.getIdentifier());
if (pass != null) {
pc.setPassword(pass);
return;
}
}
}
}
/**
* @return the passwords
*/
public Map<String, String> getPasswords() {
return passwords;
}
/**
* @param passwords the passwords to set
*/
public void setPasswords(Map<String, String> passwords) {
this.passwords = passwords;
}
}
/
--
View this message in context:
http://cxf.547215.n5.nabble.com/CXF-client-to-NET-web-service-attempting-to-create-BinarySecurityToken-BST-tp5726168.html
Sent from the cxf-user mailing list archive at Nabble.com.