0

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

8
  • Do you have to use XmlReader and XPathSelectElement here? There are simpler ways of getting the right element using LINQ to XML. Note that you're asking for /Signature, but the root element is AuthnRequest, then Signature inside that. Perhaps that's actually the problem? Commented Dec 14, 2021 at 11:41
  • I just used the / why it should go down one node under AuthnRequest, but anyway even specifying AuthnRequest / Signature doesn't work Commented Dec 14, 2021 at 12:46
  • Okay, and what about my question about whether you have to use XPathSelectElement? If you're happy with using the Element method then it's trivial. Commented Dec 14, 2021 at 12:47
  • I'm using other methods now, but I was really curious to understand why it didn't work Commented Dec 14, 2021 at 12:52
  • Okay, if your question is specific to using NamespaceManager, please fix the example to include /AuthnRequest. But I suspect the note in learn.microsoft.com/en-us/dotnet/api/… is relevant here - you should be specifying a non-empty prefix, I suspect. Commented Dec 14, 2021 at 13:04

2 Answers 2

2

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);
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, the problem was just to indicate the prefix and put it before the name of each child. It works perfectly with this code: ``` xmlNamespaceManager.AddNamespace("sig", "w3.org/2000/09/xmldsig#"); var signatureValue = xDocument.XPathSelectElement("//sig:Signature/sig:SignatureValue", xmlNamespaceManager); ```
Names spaces create more problems than they solve. Somehow, we can all use hierarchical file system without worry of 2 files with the same name. We just know to put them in different folders (=parent elements). I've never understood why XML elements are any different.
2

It is better to use LINQ to XML API.

It is available in the .Net Framework since 2007.

c#

void Main()
{
    const string filename = @"e:\Temp\pampua84.xml";

    XDocument xdoc = XDocument.Load(filename);
    XNamespace ns = "http://www.w3.org/2000/09/xmldsig#";
    

    string SignatureValue = xdoc.Descendants(ns + "SignatureValue")
        .FirstOrDefault()?.Value;

    string X509Certificate = xdoc.Descendants(ns + "X509Certificate")
        .FirstOrDefault()?.Value;

    Console.WriteLine("SignatureValue='{0}'", SignatureValue);
    Console.WriteLine("X509Certificate='{0}'", X509Certificate);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.