我正在使用Apache CXF来构建Web服务。它使用Apache WSS4J来提供WS-Security功能。我需要发出SOAP请求,并且必须签名。
这是我传递给WSS4J的属性文件的内容:
org.apache.ws.security.crypto.provider = org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type = PKCS12
org.apache.ws.security.crypto.merlin.keystore.provider = BC
org.apache.ws.security.crypto.merlin.keystore.password = 12345678
org.apache.ws.security.crypto.merlin.keystore.alias = my-alias
org.apache.ws.security.crypto.merlin.keystore.file = my_certificate.p12
我想删除那一行,我的密码写成纯文本。我删除了那一行并为我的WSS4JOutInterceptor提供了一个密码回调处理程序,就像上面的代码一样:
public SoapInterceptor newSignerInterceptor() {
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put(WSHandlerConstants.ACTION, "Signature");
outProps.put(WSHandlerConstants.USER, config.getKeyAlias());
outProps.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
outProps.put(WSHandlerConstants.USE_REQ_SIG_CERT, WSHandlerConstants.SIGNATURE_USER);
outProps.put(WSHandlerConstants.USE_SINGLE_CERTIFICATE, "false");
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, this.getClass().getName());
outProps.put(WSHandlerConstants.SIG_PROP_FILE, config.getPropertiesFileName());
return new WSS4JOutInterceptor(outProps);
}
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof WSPasswordCallback) {
((WSPasswordCallback) callbacks[i]).setPassword(password);
}
}
}
但那没用。它在属性文件中找不到密码,并使用默认密码“security”。
如何让它使用回调来获取密码?
答案 0 :(得分:5)
您可以实施CallbackHandler:
public class PasswordCallbackHandler implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for(Callback callBack:callbacks){
if(callBack instanceof WSPasswordCallback){
((WSPasswordCallback)callBack).setPassword("password");
}
}
}
}
然后将处理程序添加到属性:
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, PasswordCallbackHandler.class);
您也可以使用PW_CALLBACK_REF来设置处理程序的引用。
答案 1 :(得分:-1)
Merlin不会调用Keystore密码的回调,因此密码必须始终位于属性文件中。幸运的是,它可以加密。
这里很好地描述了解决方案: Encrypting passwords in Crypto property files
上述链接中的复制解决方案:
encrypt input=real_keystore_password password=master_password algorithm=PBEWithMD5AndTripleDES
将编码输出放在属性
中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
在CallbackHandler中,输入您曾经使用过的master_password 生成编码的:
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");
}
}
}
}