2

我正在开发一个 JAX-WS Web 服务,它必须根据 XML 数字签名规范验证传入的 SOAP 消息。我必须操纵传入的消息以匹配在签名之前对引用所做的一些转换,并且未在 XML 文档中报告。我使用 JDOM 来做到这一点。我注意到一个奇怪的行为,我可以验证第一条传入的消息,但随后的消息(签名和引用)验证失败。如果我重新启动应用程序服务器(Websphere),我可以验证第一条消息。这个问题是否与后续 Web 服务调用之间共享的脏数据有关?

这是 SOAP 处理程序的实现:

@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

问候,乔瓦尼

4

0 回答 0