我正在开发一个JAX-WS Web服务,它必须根据XML数字签名规范验证传入的SOAP消息。我必须操纵传入的按摩来匹配对参考beferore签名进行的一些转换,而不是在XML文档中报告。我使用JDOM来做到这一点。我注意到一个奇怪的行为,我可以验证第一个传入的消息,但随后的消息验证失败(在签名和引用上)。如果我重新启动Application Server(Websphere),我可以验证第一条消息。此问题是否与subsequnt Web服务调用之间共享的脏数据有关?
这是SOAP Handler实现:
@Override
public boolean handleMessage(SOAPMessageContext messageContext) {
// get the message from the context
SOAPMessage message = messageContext.getMessage();
// is an outgoing message?
Boolean isOutgoing = (Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(!isOutgoing){
// incoming message...
// Retrieve the SOAP part of the incoming message
SOAPPart soapPart = message.getSOAPPart();
InputStream inStream = null;
try {
Document doc = null;
// Retrieve the SOAP Envelope of the incoming message
Source source = soapPart.getContent();
inStream = ((StreamSource)source).getInputStream();
// Instantiate a Document containing the SOAP Envelope
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(inStream);
// Use JDOM to retrieve the CommandMessage element and add the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" namespace declaration
org.jdom2.input.DOMBuilder jdomBuilder = new org.jdom2.input.DOMBuilder();
org.jdom2.Document jdomDocument = jdomBuilder.build(doc);
org.jdom2.Element jdomBodyElement = jdomDocument.getRootElement().getChild("Body", org.jdom2.Namespace.getNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/"));
org.jdom2.Element jdomCommandMessageElement = jdomBodyElement.getChild("CommandMessage", org.jdom2.Namespace.getNamespace("", "http://www.cryptomathic.com/ckms"));
jdomCommandMessageElement.addNamespaceDeclaration(org.jdom2.Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"));
// Instantiate W3C Document to be validated
org.jdom2.Document jdomSignedDocument = new org.jdom2.Document(jdomCommandMessageElement.detach());
org.jdom2.output.DOMOutputter outputter = new org.jdom2.output.DOMOutputter();
Document signedDocument = outputter.output(jdomSignedDocument);
// Find Signature element
NodeList nl = signedDocument.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
// Create a DOMValidateContext and specify a KeyValue KeySelector and document context
DOMValidateContext valContext = new DOMValidateContext(new KeyValueKeySelector(), nl.item(0));
// Create a DOM XMLSignatureFactory that will be used to unmarshal the
// document containing the XMLSignature
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
// unmarshal the XMLSignature
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
boolean coreValidity = signature.validate(valContext);
// Check core validation status
if (coreValidity == false) {
System.out.println("Signature failed core validation");
boolean sv = signature.getSignatureValue().validate(valContext);
System.out.println("signature validation status: " + sv);
// check the validation status of each Reference
Iterator i = signature.getSignedInfo().getReferences().iterator();
for (int j=0; i.hasNext(); j++) {
Reference ref = (Reference) i.next();
boolean refValid = ref.validate(valContext);
System.out.println("ref["+j+"] validity status: " + refValid);
}
} else {
System.out.println("Signature passed core validation");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
inStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return true;
}
这是第一个请求的控制台输出:
签名通过核心验证
但对于后续请求:
签名失败核心验证
签名验证状态:false
ref [0]有效状态:false
此致 乔瓦尼