SOAP クライアントの送信メッセージに WS-Security ヘッダーを追加する JAX-WS ハンドラーを作成しました。
package com.soap.client;
import javax.xml.namespace.QName;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class ClientHeaderHandler implements SOAPHandler<SOAPMessageContext> {
private static final String WSSECURITY_PREFIX = "wsse";
private static final String WSSECURITY_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
private static final String PASSWORD_TEXT_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
/**
* {@inheritDoc}
* @see javax.xml.ws.handler.Handler#handleMessage(javax.xml.ws.handler.MessageContext)
*/
@Override
public boolean handleMessage(final SOAPMessageContext context) {
boolean outbound = false;
outbound = (Boolean) context.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound) {
try {
addSecurityHeader(context);
} catch (SOAPException e) {
// do nothing
}
}
return true;
}
private void addSecurityHeader(final SOAPMessageContext context) throws SOAPException {
SOAPFactory sf = SOAPFactory.newInstance();
SOAPElement securityElem = sf.createElement("Security", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement tokenElem = sf.createElement("UsernameToken", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement usernameElem = sf.createElement("Username", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
usernameElem.addTextNode("myusername");
tokenElem.addChildElement(usernameElem);
Name passwordTypeName = sf.createName("Type", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement passwordElem = sf.createElement("Password", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
passwordElem.addAttribute(passwordTypeName, PASSWORD_TEXT_TYPE);
passwordElem.addTextNode("mypassword");
tokenElem.addChildElement(passwordElem);
securityElem.addChildElement(tokenElem);
context.getMessage().getSOAPPart().getEnvelope().addHeader().addChildElement(securityElem);
}
}
これはほとんど機能します。ただし、WS-Security ネームスペースとプレフィックスは、それらが使用される各要素で再宣言されます ( xmlns:wsse=http://... ):
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">myusername</wsse:Username>
<wsse:Password wsse:Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">mypassword</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</S:Header>
<S:Body>
<MyBody/>
</S:Body>
</S:Envelope>
QNames、Names などのさまざまな組み合わせを試しましたが、うまくいかないようです。 WS-Security 名前空間が最上位の Security 要素でのみ宣言されるようにするには、何を変更する必要がありますか?
更新:以下の gpeche の提案は私にとってはうまくいきました。SOAPFactory を使用して要素を作成してから addChildElement を介して要素を追加する方法から、addChildElement を介して直接要素を作成する方法に切り替えます。
private void addSecurityHeader(final SOAPMessageContext context) throws SOAPException {
SOAPFactory sf = SOAPFactory.newInstance();
SOAPElement securityElem = context.getMessage().getSOAPPart().getEnvelope().addHeader().addChildElement("Security", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement tokenElem = securityElem.addChildElement("UsernameToken", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement usernameElem = tokenElem.addChildElement("Username", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
usernameElem.addTextNode("myusername");
Name passwordTypeName = sf.createName("Type", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
SOAPElement passwordElem = tokenElem.addChildElement("Password", WSSECURITY_PREFIX, WSSECURITY_NAMESPACE);
passwordElem.addAttribute(passwordTypeName, PASSWORD_TEXT_TYPE);
passwordElem.addTextNode("mypassword");
}
よりクリーンな XML を生成します。
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>myusername</wsse:Username>
<wsse:Password wsse:Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">mypassword</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</S:Header>
<S:Body>
<MyBody/>
</S:Body>
</S:Envelope>