1. 程式人生 > >WSS4J 1.5和1.6中實現WS Security的Merlin配置上的差異以及其它

WSS4J 1.5和1.6中實現WS Security的Merlin配置上的差異以及其它

通過org.apache.ws.security.components.crypto.Merlin來實現對客戶端發出的報文進行WSS加密,在1.6以後的版本中,client_sign.properties通常會是像下面這樣的:

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keyStorePassword
org.apache.ws.security.crypto.merlin.keystore.alias=myAlias
org.apache.ws.security.crypto.merlin.keystore.file=client_keystore.jks

而在WSS4J的1.5.x版本中keystore file的配置項是這個:
org.apache.ws.security.crypto.merlin.file=client_keystore.jks

以上兩個配置項在1.6.x的版本中都支援,如果是在1.5.x的版本中使用配置項,將會報找不到alias的錯誤,而實際上是因為keystore檔案沒有被載入的原因。

另外WS官方建議,將1.5.x升級為1.6.x,因為在1.6.x中修復了一些安全性問題,

The 1.5.x series of releases of WSS4J is deprecated. You should switch to a 1.6.x release as a matter of priority, as this branch contains up to date security fixes. For example, WSS4J 1.6.x uses the "secure validation" mode of Apache XML Security for Java, which protects against a number of attacks on XML Signature. 

詳見:http://ws.apache.org/wss4j/best_practice.html

如果你的client keystore是沒有密碼的,那麼可以實現自己的merlin,用以解決空密碼的問題,以下兩個自己實現的Merlin分別適用於wss1.5.x及1.6.x:

適用於1.5.x的空密碼的BlankPasswordMerlin:

public class BlankPasswordMerlin implements Crypto {

	private Merlin merlin;
	
	private static final String CRYPTO_KEYSTORE_PASSWORD = "org.apache.ws.security.crypto.merlin.keystore.password";

	public BlankPasswordMerlin(Properties properties) throws CredentialException,
			IOException {
		setKeyStorePassword(properties);
		merlin = new Merlin(properties);
	}

	public BlankPasswordMerlin(Properties properties, ClassLoader loader)
			throws CredentialException, IOException {
		setKeyStorePassword(properties);
		merlin = new Merlin(properties, loader);
	}

	private void setKeyStorePassword(Properties properties) {
		properties.put(CRYPTO_KEYSTORE_PASSWORD, "");
	}

	public X509Certificate loadCertificate(InputStream in)
			throws WSSecurityException {
		return merlin.loadCertificate(in);
	}

	public X509Certificate[] getX509Certificates(byte[] data, boolean reverse)
			throws WSSecurityException {
		return merlin.getX509Certificates(data, reverse);
	}

	public byte[] getCertificateData(boolean reverse, X509Certificate[] certs)
			throws WSSecurityException {
		return merlin.getCertificateData(reverse, certs);
	}

	public PrivateKey getPrivateKey(String alias, String password)
			throws Exception {
		return merlin.getPrivateKey(alias, password);
	}

	public X509Certificate[] getCertificates(String alias)
			throws WSSecurityException {
		return merlin.getCertificates(alias);
	}

	public String getAliasForX509Cert(Certificate cert)
			throws WSSecurityException {
		return merlin.getAliasForX509Cert(cert);
	}

	public String getAliasForX509Cert(String issuer) throws WSSecurityException {
		return merlin.getAliasForX509Cert(issuer);
	}

	public String getAliasForX509Cert(String issuer, BigInteger serialNumber)
			throws WSSecurityException {
		return merlin.getAliasForX509Cert(issuer, serialNumber);
	}

	public String getAliasForX509Cert(byte[] skiBytes)
			throws WSSecurityException {
		return merlin.getAliasForX509Cert(skiBytes);
	}

	public String getDefaultX509Alias() {
		return merlin.getDefaultX509Alias();
	}

	public byte[] getSKIBytesFromCert(X509Certificate cert)
			throws WSSecurityException {
		return merlin.getSKIBytesFromCert(cert);
	}

	public String getAliasForX509CertThumb(byte[] thumb)
			throws WSSecurityException {
		return merlin.getAliasForX509CertThumb(thumb);
	}

	public KeyStore getKeyStore() {
		return merlin.getKeyStore();
	}

	public CertificateFactory getCertificateFactory()
			throws WSSecurityException {
		return merlin.getCertificateFactory();
	}

	public boolean validateCertPath(X509Certificate[] certs)
			throws WSSecurityException {
		return merlin.validateCertPath(certs);
	}

	public String[] getAliasesForDN(String subjectDN)
			throws WSSecurityException {
		return merlin.getAliasesForDN(subjectDN);
	}

}
適用於1.6.x的空密碼的BlankPasswordMerlin:
public class BlankPasswordMerlin implements Crypto {
	private Merlin merlin;
	private static final String CRYPTO_KEYSTORE_PASSWORD = "org.apache.ws.security.crypto.merlin.keystore.password";

	public BlankPasswordMerlin(Properties properties) throws CredentialException, IOException {
		setKeyStorePassword(properties);
		this.merlin = new Merlin(properties);
	}

	public BlankPasswordMerlin(Properties properties, ClassLoader loader) throws CredentialException, IOException {
		setKeyStorePassword(properties);
		this.merlin = new Merlin(properties, loader);
	}

	private void setKeyStorePassword(Properties properties) {
		properties.put("org.apache.ws.security.crypto.merlin.keystore.password", "");
	}

	public X509Certificate loadCertificate(InputStream in) throws WSSecurityException {
		return this.merlin.loadCertificate(in);
	}

	public byte[] getSKIBytesFromCert(X509Certificate cert) throws WSSecurityException {
		return this.merlin.getSKIBytesFromCert(cert);
	}

	public KeyStore getKeyStore() {
		return this.merlin.getKeyStore();
	}

	public CertificateFactory getCertificateFactory() throws WSSecurityException {
		return this.merlin.getCertificateFactory();
	}

	public byte[] getBytesFromCertificates(X509Certificate[] certs) throws WSSecurityException {
		return this.merlin.getBytesFromCertificates(certs);
	}

	public X509Certificate[] getCertificatesFromBytes(byte[] certs) throws WSSecurityException {
		return this.merlin.getCertificatesFromBytes(certs);
	}

	public String getCryptoProvider() {
		return this.merlin.getCryptoProvider();
	}

	public String getDefaultX509Identifier() throws WSSecurityException {
		return this.merlin.getDefaultX509Identifier();
	}

	public PrivateKey getPrivateKey(X509Certificate cert, CallbackHandler handler) throws WSSecurityException {
		return this.merlin.getPrivateKey(cert, handler);
	}

	public PrivateKey getPrivateKey(String param1, String param2) throws WSSecurityException {
		return this.merlin.getPrivateKey(param1, param2);
	}

	public X509Certificate[] getX509Certificates(CryptoType cryptoType) throws WSSecurityException {
		return this.merlin.getX509Certificates(cryptoType);
	}

	public String getX509Identifier(X509Certificate cert) throws WSSecurityException {
		return this.merlin.getX509Identifier(cert);
	}

	public void setCertificateFactory(String provider, CertificateFactory certFactory) {
		this.merlin.setCertificateFactory(provider, certFactory);
	}

	public void setCryptoProvider(String provider) {
		this.merlin.setCryptoProvider(provider);
	}

	public void setDefaultX509Identifier(String identifier) {
		this.merlin.setDefaultX509Identifier(identifier);
	}

	public boolean verifyTrust(X509Certificate[] certs) throws WSSecurityException {
		return this.merlin.verifyTrust(certs);
	}

	public boolean verifyTrust(PublicKey publicKey) throws WSSecurityException {
		return this.merlin.verifyTrust(publicKey);
	}

	public boolean verifyTrust(X509Certificate[] certs, boolean boo) throws WSSecurityException {
		return this.merlin.verifyTrust(certs, boo);
	}
}

那麼此時client_sign.properties中就不用配置keystore的密碼,配置應該會是這樣:
org.apache.ws.security.crypto.provider=com.xxx.BlankPasswordMerlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.alias=sre
org.apache.ws.security.crypto.merlin.file=sre.jks