1) Crypto properties
Apache WSS4J uses the Crypto interface to get keys and certificates for encryption/decryption and for signature creation/verification. WSS4J currently ships with three implementations:
- Merlin: The standard implementation, based around two JDK keystores for key/cert retrieval, and trust verification.
- CertificateStore: Holds an array of X509 Certificates. Can only be used for encryption and signature verification.
- MerlinDevice: Based on Merlin, allows loading of keystores using a null InputStream - for example on a smart-card device.
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 in WSS4J 2.0.0 the "org.apache.ws.security.crypto" prefix used previously is now "org.apache.wss4j.crypto", however both prefixes are accepted by the code.
2) Encrypting passwords in a Crypto properties file
Note in the example above 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 way this works is as follows. The WSPasswordCallback class has an additional "usage" called WSPasswordCallback.PASSWORD_ENCRYPTOR_PASSWORD, which is used to return the password used with a PasswordEncryptor implementation to decrypt encrypted passwords stored in Crypto properties files. 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 the (master) password to decrypt the encrypted password
using the WSPasswordCallback usage tag given above.
It is possible to pass a custom PasswordEncryptor implementation to WSS4J via the new configuration tag ConfigurationConstants.PASSWORD_ENCRYPTOR_INSTANCE ("passwordEncryptorInstance").
Thanks for the insights on WSS4J!
ReplyDeleteAt the time being we use WSS4J embedded in CXF and we load the trustsotre and keystore from jks files using merlin.
Is there a way to configure WSS4J and CXF to read certs and PK from a database?
Thanks
Hi Matteo,
ReplyDeleteThere is no "out-of-the-box" way to do this. However, it is quite straightforward to implement the Crypto interface yourself and plug this into WSS4J/CXF. For example, there is an implementation in CXF that gets certs from an XKMS server:
http://svn.apache.org/viewvc/cxf/trunk/services/xkms/xkms-client/src/main/java/org/apache/cxf/xkms/crypto/provider/XkmsCryptoProvider.java?view=markup
Colm.
Oh! And if I understood correctly, CXF provides also a XKMS server. I did't know that.
ReplyDeleteMany thanks
From the org.apache.cxf.ws.security.wss4j.SamlTokenInterceptor, it seems always get a Crypto with null PasswordEncryptor. Therefore, the Jasypt encrypted password is not properly decypted. Any advise to bypass this issue?
ReplyDeletecxf version 3.1.2, with wss4j 2.1.2
--------------------
getInstance(properties, Loader.getClassLoader(CryptoFactory.class), null);
--------------------------
public static Crypto getInstance(Properties properties) throws WSSecurityException {
if (properties == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Cannot load Crypto instance as properties object is null");
}
throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
"empty", new Object[] {"Cannot load Crypto instance as properties object is null"});
}
return getInstance(properties, Loader.getClassLoader(CryptoFactory.class), null);
}
I just fixed this.
ReplyDelete