Problem
I'm using Apache CXF 3.0.7, and read that, in the new features you have the ability to store a (BASE-64 encoded) encrypted version of the keystore password in the Crypto properties file, but I don't know how to add it, I didn't find an example of this implementation.
In the apache web says:
A typical example of the contents of a Crypto properties file (for Signature creation) is as follows:
org.apache.wss4j.crypto.provider=org.apache.wss4j.common.crypto.Merlin
org.apache.wss4j.crypto.merlin.keystore.type=jks
org.apache.wss4j.crypto.merlin.keystore.password=security
org.apache.wss4j.crypto.merlin.keystore.alias=wss40
org.apache.wss4j.crypto.merlin.keystore.file=keys/wss40.jks
Note that the password used to load the keystore is in cleartext. One of the new features of Apache WSS4J 2.0.0 is the ability to instead store a (BASE-64 encoded) encrypted version of the keystore password in the Crypto properties file. A new PasswordEncryptor interface is defined to allow for the encryption/decryption of passwords. A default implementation is now provided based on Jasypt called JasyptPasswordEncryptor, which uses "PBEWithMD5AndTripleDES".
The WSPasswordCallback class has an additional "usage" called WSPasswordCallback.PASSWORD_ENCRYPTOR_PASSWORD, which is used to return the master password for use with the PasswordEncryptor implementation. When WSS4J is loading a Crypto implementation via a properties file, and it encounters a password encrypted in the format "ENC(encoded encrypted password)", it queries a CallbackHandler for a password via this WSPasswordCallback usage tag. It is possible to pass a custom PasswordEncryptor implementation to WSS4J via the new configuration tag ConfigurationConstants.PASSWORD_ENCRYPTOR_INSTANCE ("passwordEncryptorInstance").
It is possible to pass a custom PasswordEncryptor implementation to WSS4J via the new configuration tag ConfigurationConstants.PASSWORD_ENCRYPTOR_INSTANCE ("passwordEncryptorInstance").
I guess I have to declare in my properties file something like that:
org.apache.wss4j.crypto.merlin.keystore.password=ENC(?????)
But I don't know how to encrypt my password with the default JasyptPasswordEncryptor implemented. Also, I guessthat in my CallbackHandler I'll have something like that:
if (usage==WSPasswordCallback.PASSWORD_ENCRYPTOR_PASSWORD){
????
}
Solution
Ok, with the test running, I test my solution and now is working.
- Download the jasypt-1.9.2-dist.zip
- Get a Encoded password with this command encrypt input=real_keystore_password password=master_password algorithm=PBEWithMD5AndTripeDES
- Copy the OUTPUT (EXample: 0laAaRahTQJzlsDu771tYi)
- As you're using this algorithm, you need the Java Cryptography Extension (JCE) Unlimited Strength. Put in your JDK.
Put the encoded output in the properties
org.apache.wss4j.crypto.provider=org.apache.wss4j.common.crypto.Merlin org.apache.wss4j.crypto.merlin.keystore.type=jks org.apache.wss4j.crypto.merlin.keystore.password=ENC(0laAaRahTQJzlsDu771tYi) org.apache.wss4j.crypto.merlin.keystore.alias=my_alias org.apache.wss4j.crypto.merlin.keystore.file=/etc/cert/my_keystore.jks
In the CallbackHandler, put the master_password wich you used to generated the encoded one:
public class WsPasswordHandler implements CallbackHandler {
@Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (Callback callback: callbacks){ WSPasswordCallback pwdCallback= (WSPasswordCallback) callback; final int usage =pwdCallback.getUsage(); if (usage==WSPasswordCallback.SIGNATURE||usage==WSPasswordCallback.DECRYPT){ pwdCallback.setPassword("parKeyPassword"); } if (usage==WSPasswordCallback.PASSWORD_ENCRYPTOR_PASSWORD){ pwdCallback.setPassword("master_password"); } } }
}
And this is it... Now I've to figure out how to get this working in a external local.property, with Spring, and so on.. but this is another history.. Thank you!