如何使用Java';s的XPath库与XML名称空间结合使用?

如何使用Java';s的XPath库与XML名称空间结合使用?,java,xml,xpath,xml-namespaces,Java,Xml,Xpath,Xml Namespaces,我们希望记录用于对从IdP发送的XML格式SAML响应进行签名的算法。示例性响应如下所示: <?xml version="1.0" encoding="UTF-8"?> <saml2p:Response Destination="https://local.internal.company.de:443/saml/SSO" ID="_f4b74c8bd287c774ff132ad648b74c33"

我们希望记录用于对从IdP发送的XML格式SAML响应进行签名的算法。示例性响应如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response Destination="https://local.internal.company.de:443/saml/SSO" ID="_f4b74c8bd287c774ff132ad648b74c33"
                 InResponseTo="a15je30i854ji72e54egg30bd3jg622" IssueInstant="2020-08-10T08:54:48.272Z" Version="2.0"
                 xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
        https://local.internal.company.de:4443/idp/shibboleth
    </saml2:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <ds:Reference URI="#_f4b74c8bd287c774ff132ad648b74c33">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <ds:DigestValue>+0000000000000000000000000000000000000+0000=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
            00000+00000000000000000000000000000000000000000000000000000000+000000000/000
            000000000000000000000000000000000000000000000/000000000000000000000000000000
            000000000000000000000000000000+0000000000/0000000000+00000000000000000000000
            000000000000000000000000000000000000/000000000000000000000000000000000+00000
            00000000000000000000000000000000000000==
        </ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>
                    000000000000000000000000000/000000+00000000000000000000000000000000000000000
                    0000000000000000000000000000000000000000000000000000000000000000000000000000
                    0000000000000000000000000000000000000000000000000000000000000000000000000000
                    00000000000000000000/00000000000000000000000000000000000000/0000000000000000
                    000/00000000000000000+000000000000000000000000/0000000000000/000000000000000
                    0000000000000000000000000000/000000000000000+00000+0000000000000000000000000
                    000000000000000000000000000000000000000000000000000000000000000000000000/000
                    0000000000/00000000000000000000000000000000000000000000000000000/000+0000000
                    0000000000000000000000000000000000000000000000000000000000000000000000000000
                    000000000000000000000000000000000000000000000000000000000000000/00000000000/
                    00000+0000000000000000000/000000000000000000000000000+00000000000000000+0000
                    0000/0000000/00000000000000000/0000000000000000000000000000000000000000/00+0
                    000000000/0/00000000000000000000000000000000+0000000000000000000000000000000
                    0000000000+000000000000000000000000000000000000000000000000000==
                </ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
    <saml2p:Status>
        <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </saml2p:Status>
    <saml2:EncryptedAssertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
        <xenc:EncryptedData Id="_00000000000000000000000000000000" Type="http://www.w3.org/2001/04/xmlenc#Element"
                            xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
            <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"
                                   xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"/>
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <xenc:EncryptedKey Id="_0000000000000000000000000000000" Recipient="de:company:platform"
                                   xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
                    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"
                                           xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"
                                         xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
                    </xenc:EncryptionMethod>
                    <ds:KeyInfo>
                        <ds:X509Data>
                            <ds:X509Certificate>
                                0000000000000000000000000000000000000000000000000000000000000000000000000000
                                0000000000000000000000000000000000000000000000000000000000000000000000000000
                                0000000000000000000000000000000000000000000000000000000000000000000000000000
                                0000000000000000000000000000000000000000000000000000000000000000000000000000
                                0000000000000000000000000000000000000000000000000000000000000000000000000000
                                0000000000000000000000000000000000000000000000000000000000000000000000000000
                                00000000000000000000000000000000000000000000000000000/0000000000000000000000
                                000000000000000000000000000000000/+00000000000000000000000000000000000000000
                                000000000000000000000000000000000000000000+00000000/000000/00000000000000000
                                000000000000000000000000000000000000/00000000000000000000/00000/000000000000
                                0000000000000000000000000000000000/00000000000000000000000000000000000000+00
                                00000000000000000000000000000/000000000000000000++00000000000000000000+00000
                                0000000000000000000000000000000000000000000000000000000000000000000000000000
                                000000+000000000000000000000000000000000000000000000000000000000000000000000
                                00000000000000000000000000000000000000000000000000/0+00000000000000000000000
                                000000000000000000000+000000000000000000000000000000000000000000000000000000
                                00000000000000000000000000000000000000000000000000000/00000000000/0000000000
                                00000000000000000000000000000000000000000000000+0000000+00000000000000000000
                                000000000000+0000000/0000+0000+000000000000000000000000000/00000000000000000
                                0000000000000000000000000000000000/0000000000000+000000000000000000000000000
                                000/00000000000000000+00000000+0000000000+0000000000000000000000000000000+00
                                0000000000000000000000000000000000000000000000000000000+00000000000000000000
                                0000000000000000000000000000000000/00000000000000000000000000000+00000000000
                                00000000000000000+000000000000000000000000000000000//00000000/00000000000000
                                0000/00/0000000/000000000000+00000000000000000000000000000000000000000000000
                                000+00000000000000000000000000000000000000000000
                            </ds:X509Certificate>
                        </ds:X509Data>
                    </ds:KeyInfo>
                    <xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
                        <xenc:CipherValue>00000000000000000000000000000000000000000000000/000+00/000000000000000000000
                            0000000000000000000000000000+00000000000000000000000000000000000000000000000
                            000000000000/000000000000000000000000000000000000000000000000000000000000000
                            0000000000000000000000000000000000000000000000000000000000000000000000000000
                            0000000000000000000000000000000000000000000000000000000000000000000000000000
                            0000000000000000000000000000000000000000000000+0000000000000000000000000000/
                            0000000000000000000000000000000000000000000000000000000000000000000000000000
                            0000000000000000000000000000000000000000000000000000000000000000000000000000
                            0000+000000000000000000+00000+000000000000000000000000000000000000000000000=
                        </xenc:CipherValue>
                    </xenc:CipherData>
                </xenc:EncryptedKey>
            </ds:KeyInfo>
            <xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
                <xenc:CipherValue>0000000000000000000000/00000000000000000000000000000000000000000000000000000
                    0000000000/000000000000000000000000000000+0000000000000000000000000000000000
                    0000000000000000000000000000000000/00000000000000000000000+00000000000000000
                    00000000000000/000000000000000000000000000/+00000000000000000000000000000000
                    00000000000000000000000000000000000000000000000000000000/0000000000000000000
                    0000000000000000000000000000000000000000000000000000000000000000000000000000
                    0000000/00000000000000000000000000000000000000000000000000000000000000000000
                    0000000000000000000000000000000000000000000000000+00000000000000000000000000
                    0000000000000000000000000000000000000000000000000000000000000000000000+00000
                    00000000000000000+000000000000000000000000/000000000000000000000000000000000
                    000000000000000000==
                </xenc:CipherValue>
            </xenc:CipherData>
        </xenc:EncryptedData>
    </saml2:EncryptedAssertion>
</saml2p:Response>

我不知道如何进一步调试匹配过程,也不知道为什么这个简单的XPath与XML数据中明显存在的节点不匹配。

在调用
setNamespaceContext()
似乎足以表明使用名称空间的意图时,实际上还需要调用


另请参见

谢谢!这就是我们所缺少的,它现在起作用了。如果你把你的评论变成回应,我很乐意接受!不客气。顺便说一句,这个问题提得很好。
private XPathExpression setupXPathExpression(String xPath) throws XPathExpressionException {
    XPath xPathTmp = XPathFactory.newInstance().newXPath();
    xPathTmp.setNamespaceContext(new NamespaceContext() {
        @Override
        public String getNamespaceURI(String prefix) {
            // as per https://coderanch.com/t/649195/java/XPath-escape
            if (prefix == null) {
                throw new NullPointerException("Null prefix");
            } else if ("saml2p".equals(prefix)) {
                return "urn:oasis:names:tc:SAML:2.0:protocol";
            } else if ("saml2".equals(prefix)) {
                return "urn:oasis:names:tc:SAML:2.0:assertion";
            } else if ("ds".equals(prefix)) {
                return "http://www.w3.org/2000/09/xmldsig#";
            } else if ("xenc".equals(prefix)) {
                return "http://www.w3.org/2001/04/xmlenc#";
            }

            return XMLConstants.NULL_NS_URI;
        }

        @Override
        public String getPrefix(String namespaceURI) {
            throw new UnsupportedOperationException();
        }

        @Override
        public Iterator<String> getPrefixes(String namespaceURI) {
            throw new UnsupportedOperationException();
        }
    });

    return xPathTmp.compile(xPath);
}

protected String extractResponseSignatureAlgorithm(String samlResponse) throws IOException, SAXException, XPathExpressionException, ParserConfigurationException {
//   String xPath= "//*";
    String xPath = "//ds:SignatureMethod";
    DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    XPathExpression xPathExpression = setupXPathExpression(xPath);

    InputSource is = new InputSource();
    is.setCharacterStream(new StringReader(samlResponse));
    Document xmlDocument = documentBuilder.parse(is);
    NodeList matches = (NodeList) xPathExpression.evaluate(xmlDocument, XPathConstants.NODESET);

    // manually traverse example XML to verify via debugger that the content is actually there
    Node signatureMethodNode = xmlDocument.getFirstChild().getFirstChild().getNextSibling().getNextSibling().getNextSibling().getFirstChild().getNextSibling().getFirstChild().getNextSibling().getNextSibling().getNextSibling();
    // is in fact "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" when debugging unit test
    String algo = signatureMethodNode.getAttributes().getNamedItem("Algorithm").getNodeValue();

    // is 0 for xPath = "//ds:SignatureMethod";
    // is 32 for xPath= "//*";
    int len = matches.getLength();

    return matches.toString();
}
@Test
public void testExtractResponseSignatureAlgorithm() throws IOException, SAXException, XPathExpressionException, ParserConfigurationException {
    String samlResponse = IOUtils.toString(this.getClass().getResourceAsStream("/saml/sha256-response.xml"));

    String actual = filter.extractResponseSignatureAlgorithm(samlResponse);
    String expected = "http://www.w3.org/2001/04/xmlenc#sha256";

    Assert.assertEquals(expected, actual);
}