Search code examples
c#xmlxpath.net-5

c# XPathSelectElement return null even if the namespace is specified


I have this xml document in a file:

<samlp:AuthnRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_73c4b43a-d201-4990-b656-e6bab19e1c09" Version="2.0" IssueInstant="2021-12-14T08:09:39.816485Z" Destination="https://localhost/idp/sso/post" ForceAuthn="true" AssertionConsumerServiceIndex="0" AssertionConsumerServiceURL="https://localhost:5002/signin-spid" AttributeConsumingServiceIndex="0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" >
<saml:Issuer NameQualifier="https://localhost:5002" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" >https://localhost:5002</saml:Issuer>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
        <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
        <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
        <Reference URI="#_73c4b43a-d201-4990-b656-e6bab19e1c09">
            <Transforms>
                <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <DigestValue>.........DigestValue...........</DigestValue>
        </Reference>
    </SignedInfo>
    <SignatureValue>..............Signature................</SignatureValue>
    <KeyInfo>
        <X509Data>
            <X509Certificate>...........Certificate.............</X509Certificate>
        </X509Data>
    </KeyInfo>
</Signature>
<samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" />
<saml:Conditions NotBefore="2021-12-14T07:59:39.816485Z" NotOnOrAfter="2021-12-14T08:19:39.816485Z" />
</samlp:AuthnRequest>

I just trying to get the SignatureValue tag value and X509Certificate tag value with this code:

var xDocument = XDocument.Load("Request.xml");
var reader = xDocument.CreateReader();

var namespaceManager = new XmlNamespaceManager(reader.NameTable);
namespaceManager.AddNamespace("", "http://www.w3.org/2000/09/xmldsig#");
var signature = xDocument.XPathSelectElement("/Signature/SignatureValue", namespaceManager);
var x509Certificate = xDocument.XPathSelectElement("/Signature/KeyInfo/X509Data/X509Certificate", namespaceManager);

but Signature and x509Certificate Elements are always null. I also tried to use the method directly on the Root object but it doesn't work the same. What am I doing wrong?
Thanks


Solution

  • Here's a quick one. You have to give a prefix to the empty default namespace. It can be anything really, in this example I called it "root".

    using System.Xml;
    
    NameTable nt = new NameTable();
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);
    nsmgr.AddNamespace("root", "http://www.w3.org/2000/09/xmldsig#");
    
    XmlDocument xml = new XmlDocument();
    xml.Load("c:\\temp\\test.xml");
    XmlNode ndSignature = xml.SelectSingleNode("//root:Signature/root:SignatureValue", nsmgr);
    XmlNode ndCertificate = xml.SelectSingleNode("//root:Signature/root:KeyInfo/root:X509Data/root:X509Certificate", nsmgr);
    
    Console.WriteLine(ndSignature.InnerText);
    Console.WriteLine(ndCertificate.InnerText);