Hi all,
I like to share this experience about dynamically changing the password
in the xfire layer.
In our application there is a server call that changes the password on
the server. As all messages are sent with a username token I also had to
change the password in the xfire layer.
After updating the keystore I reinitialized the soap service but the new
settings were not loaded. It appeared that the crypto object (which
contains merlin properties and a keystore was cashed in a static
variable.
The solution was to add an out handler that reset the crypto object to
null if the keystore had to be reloaded.
If you are interested you can look at the code below:
public class CredentialsOutHandler extends AbstractWSS4JHandler {
protected static final Log log =
LogFactory.getLog(CredentialsOutHandler.class.getName());
boolean credentialsChanged;
@SuppressWarnings("unchecked")
public CredentialsOutHandler() {
super();
setPhase(Phase.USER);
getAfter().add(DOMOutHandler.class.getName());
getBefore().add(WSS4JOutHandler.class.getName());
}
@SuppressWarnings("unchecked")
public CredentialsOutHandler(Map props) {
this();
setProperties(props);
}
public boolean isCredentialsChanged() {
return credentialsChanged;
}
public void setCredentialsChanged(boolean credentialsChanged) {
this.credentialsChanged = credentialsChanged;
}
public void credentialsChanged() {
this.credentialsChanged = true;
}
public void invoke(MessageContext context) throws Exception {
//System.out.println("invoking CredentialsOutHandler");
if(credentialsChanged) {
//System.out.println("CredentialsOutHandler credentialsChanged");
String refId = getString(WSHandlerConstants.SIG_PROP_REF_ID,
context);
cryptos.remove(refId);
credentialsChanged = false;
}
}
private static void initXFire(String serverURL) {
service = null;
final XFire xfire =
org.codehaus.xfire.XFireFactory.newInstance().getXFire();
final Map<String, Object> config = new HashMap<String, Object>();
TransportManager tm = (xfire.getTransportManager());
Service serviceModel = new AnnotationServiceFactory(
new Jsr181WebAnnotations(), tm, new AegisBindingProvider(
new JaxbTypeRegistry())).create(BAWebService2Impl.class);
try {
service = (BAWebService2Soap)new
XFireProxyFactory().create(serviceModel, serverURL);
Client client =
((XFireProxy)Proxy.getInvocationHandler(service)).getClient();
// SignatureProperties:
// signatureProperties needs only be set if
WSHandlerConstants.SIG_PROP_REF_ID = "signatureProperties"
// is used in configureXXXX(Properties)
client.setProperty(SIGNATURE_PROPERTIES, signatureProperties);
// MTOM: this sends binary data as attachments
// client.setProperty("mtom-enabled", "true");
client.addOutHandler(new DOMOutHandler());
configureSendWithUsernameTokenWithX509SignedBody(config);
client.addOutHandler(credentialsOutHandler);
client.addOutHandler(new WSS4JOutHandler(config));
}
catch(MalformedURLException e) {
e.printStackTrace();
}
}
private static void
configureSendWithUsernameTokenWithX509SignedBody(Map<String, Object>
properties) {
properties.put(WSHandlerConstants.ACTION,
WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.USERNAME_TOKEN);
// Username usage: username in passwordHandler and merlin
signatureProperties and alias in keystore must all match
properties.put(WSHandlerConstants.USER,
credentialsManager.getUsername());
// Password callback: This callback is used to specify password for
given user for keystore
// Give a class name
// properties.put(WSHandlerConstants.PW_CALLBACK_CLASS,
// com.ba.client.transport.impl.PasswordHandler.class.getName());
// Give a reference to an object
properties.put(WSHandlerConstants.PW_CALLBACK_REF, passwordHandler);
// Keystore configuration: for accessing private key in keystore
// configuration in form of a file
//properties.put(WSHandlerConstants.SIG_PROP_FILE,
"outsecurity_sign.properties");
// configuration in the form of a reference
// 'signatureProperties' is the key used for the signature Properties
object registered with the client
properties.put(WSHandlerConstants.SIG_PROP_REF_ID,
SIGNATURE_PROPERTIES);
// Certificate configuration:
// IssuerSerial signs the message with the private key and sends the
message without certificate
// properties.put(WSHandlerConstants.SIG_KEY_ID, "IssuerSerial");
// DirectReference signs the message with the private key and sends
the message with certificate wrapped in a Binary
properties.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
// Signing algorithm: is determined by keystore
// properties.put(WSHandlerConstants.SIG_ALGO, "SHA1RSA");
// Additional UsernameToken elements:
properties.put(WSHandlerConstants.ADD_UT_ELEMENTS,
WSConstants.NONCE_LN + " " + WSConstants.CREATED_LN);
properties.put(WSHandlerConstants.PASSWORD_TYPE,
WSConstants.PW_TEXT);
// Signed parts: defaults to body
// properties.put(WSHandlerConstants.SIGNATURE_PARTS,
"{Element}{}Header; {Element}{}Body;");
}
}