Подписание ответа SAML генерирует CryptographicException: контекст XmlDocument необходим для конвертированных преобразований - PullRequest
2 голосов
/ 12 апреля 2019

Я пытаюсь подписать следующее утверждение SAML с помощью System.Security.Xml.

<saml:Assertion xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" mlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfx96e500ef-d656-e97c-17ee-bbeff75c7235" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
  <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
  <saml:Subject>
    <saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
    <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
      <saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
    </saml:SubjectConfirmation>
  </saml:Subject>
  <saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
    <saml:AudienceRestriction>
      <saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
    </saml:AudienceRestriction>
  </saml:Conditions>
  <saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
    <saml:AuthnContext>
      <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
    </saml:AuthnContext>
  </saml:AuthnStatement>
  <saml:AttributeStatement>
    <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
      <saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
    </saml:Attribute>
    <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
      <saml:AttributeValue xsi:type="xs:string">test@example.com</saml:AttributeValue>
    </saml:Attribute>
    <saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
      <saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue>
      <saml:AttributeValue xsi:type="xs:string">examplerole1</saml:AttributeValue>
    </saml:Attribute>
  </saml:AttributeStatement>
</saml:Assertion>

И следующий код:

    [TestMethod]
    public void SignAssertion()
    {
        var xmlDoc = new XmlDocument { PreserveWhitespace = true };
        xmlDoc.Load("UnsignedAssertion.xml");
        var certStore = new X509Store("MY", StoreLocation.CurrentUser);
        certStore.Open(OpenFlags.ReadOnly);
        X509Certificate2Collection certs;
        try
        {
            certs = certStore.Certificates.Find(X509FindType.FindBySubjectName, "AValidCertificate", true);
        }
        finally
        {
            certStore.Close();
        }
        var cert = certs[0];
        var signedXml = new SignedXml(xmlDoc);
        var transforms = new TransformChain();
        transforms.Add(new XmlDsigEnvelopedSignatureTransform());
        transforms.Add(new XmlDsigExcC14NTransform());
        var reference = new Reference
        {
            Id = "#pfx96e500ef-d656-e97c-17ee-bbeff75c7235",
            TransformChain = transforms
        };
        signedXml.AddReference(reference);
        signedXml.SigningKey = cert.PrivateKey;
        signedXml.ComputeSignature();
    }

Ошибка вызова ComputeSignature со следующей ошибкой:

Сообщение: метод теста SamlPoc.UnitTest1.SignAssertion вызвал исключение: System.Security.Cryptography.CryptographicException: контекст XmlDocument необходим для конвертированных преобразований.

и следующеетрассировка стека:

at System.Security.Cryptography.Xml.XmlDsigEnvelopedSignatureTransform.GetOutput() 
at System.Security.Cryptography.Xml.TransformChain.TransformToOctetStream(Object inputObject, Type inputType, XmlResolver resolver, String baseUri)   
at System.Security.Cryptography.Xml.TransformChain.TransformToOctetStream(Stream input, XmlResolver resolver, String baseUri)    
at System.Security.Cryptography.Xml.Reference.CalculateHashValue(XmlDocument document, CanonicalXmlNodeList refList)    
at System.Security.Cryptography.Xml.SignedXml.BuildDigestedReferences()   
at System.Security.Cryptography.Xml.SignedXml.ComputeSignature()

Мне кажется, что я передал действительный XmlDocument в SignedXml, который следует рассматривать как действительный контекст XMLDocument.Чего мне не хватает?

Ответы [ 2 ]

1 голос
/ 22 апреля 2019

Я перепутал свойство Id ссылки со свойством Uri. Требуется свойство Uri ссылки , даже если для него задана пустая строка.Пустая строка установит ссылку на весь документ xml.С другой стороны, я мог бы установить Uri на Id утверждения, которому предшествует символ #.

    public void SignAssertion()
    {
        var xmlDoc = new XmlDocument { PreserveWhitespace = false };
        xmlDoc.Load("UnsignedAssertion.xml");
        var signedXml = new SignedXml(xmlDoc);
        signedXml.SigningKey = getCert().PrivateKey;
        signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

        var canMethod = (XmlDsigExcC14NTransform)signedXml.SignedInfo.CanonicalizationMethodObject;
        canMethod.InclusiveNamespacesPrefixList = "Sign";
        var transforms = new TransformChain();
        transforms.Add(new XmlDsigEnvelopedSignatureTransform());
        var reference = new Reference
        {
            Id = "#pfx96e500ef-d656-e97c-17ee-bbeff75c7235",
            TransformChain = transforms,
            Uri = "" // This is the solution...
        };
        signedXml.AddReference(reference);
        signedXml.ComputeSignature();
    }
0 голосов
/ 22 апреля 2019

Этот вопрос показывает, где находится подпись в конверте в подписанном XML-документе.Существует разница между с конвертами и с конвертами .

Если вы начинаете с:

<saml:Assertion>
  ...
</saml:Assertion>

и подписываете этот документ на уровне корневого узла (Assertion), вы создаете конверт , а не конверт в конверте, поскольку подпись содержит всю подписанную информацию.Вот почему, когда вы добавляете:

transforms.Add(new XmlDsigEnvelopedSignatureTransform());

, вы получаете:

Контекст XmlDocument необходим для конвертированных преобразований

как подпись в конверте требует, чтобы в качестве конверта использовалась XmlDocument.

В конечном итоге то, что вы делаете, правильно, но в качестве теста, без полного SAML Response, вы видитеэта ошибка.На производстве Assertion не будет отправлено само по себе, оно будет содержать XmlDocument, такое как:

<saml:Response>
  <saml:Assertion...
  </saml:Assertion>
</saml:Response>

, а элемент <saml:Response> обеспечит необходимый контекст XmlDocument дляподпись для работы.

Чтобы пройти тест, заключите Assertion в Response и подпишите узел Assertion, используя XmlDsigEnvelopedSignatureTransform.

...