What is the correct format for SAML 2.0 Assertions?

24,529

Solution 1

It turns out that the above XML is valid (ADFS adds the namespace to the overall XML but not each element). The problem was that the ComponentSpace library has different methods for getting Signed or Encrypted Assertions and I was just calling the generic GetAssertions. ADFS was generating signed assertions and I needed to call the other function.

Here is the code we ended up with:

IList<EncryptedAssertion> encryptedAssertions = samlResponse.GetEncryptedAssertions();
if (encryptedAssertions.Count > 0 && x509Certificate != null) {

    // Decrypt the assertion
    EncryptedAssertion encryptedAssertion = encryptedAssertions[0];
    XmlElement decryptedElement = encryptedAssertion.DecryptToXml(x509Certificate, null);
    LogMessage("Decrypted assertion: " + decryptedElement.OuterXml);

    // Then verify the signature.
    VerifySignature(x509Certificate, decryptedElement);
    samlAssertion = new SAMLAssertion(decryptedElement);
} else {

    if (samlResponse.GetSignedAssertions().Count > 0) {
        // Get the signed assertion and verify the signature.
        XmlElement signedAssertionElement = samlResponse.GetSignedAssertions()[0];
        LogMessage("Signed assertion: " + signedAssertionElement.OuterXml);

        VerifySignature(x509Certificate, signedAssertionElement);
        samlAssertion = new SAMLAssertion(signedAssertionElement);
    } else {
        // Assertion is not encrypted or signed.
        if (samlResponse.GetAssertions().Count > 0) {
            samlAssertion = samlResponse.GetAssertions()[0];
            LogMessage("Assertion: " + samlAssertion.ToXml().OuterXml);
        } else {
            LogFatalError("No assertions in response");
        }
    }
}

Solution 2

A correct SAML response should contain namespace-qualified elements

<saml2p:Response Destination="https://www.google.com/a/squaresquare.biz/acs" IssueInstant="2010-08-04T17:47:20.956Z" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" InResponseTo="djfnhepndikoonjjkeomgplmkjofobhdbdieihpa" Version="2.0" ID="_bd24b4a3514fd93800d2a43cafc98edb">
  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://my.ssodemo.url.demo.google.com/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:CanonicalizationMethod>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
      <ds:Reference URI="#_bd24b4a3514fd93800d2a43cafc98edb">
        <ds:Transforms>
          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
            <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="dssaml2saml2p"></ec:InclusiveNamespaces>
          </ds:Transform>
        </ds:Transforms>
        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
        <ds:DigestValue>m/lUCS3nvfGuSJFKAtIz+ZrfxTU=</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>PLdYgU9u5KirVrMHNSwYvk6fQ401dMbpuiDXpapKf0eOKC6pN3g7tnTEzvfOaXhkDNXVmGN+lXQ6iUDppWpdO2MbvPVZabOBPU1aAO+CWI53ciC0rYsxpFzQLLMC/7x9Wk7VFFmYEecxAJV+lTWvp8ZKXvwqZbhiTO/23EC0xconGhnwSvKjJWQuLnMMaFWSjDFYyzgsp34cR7aX/eqhhJyA/rr2uFdmgEdagAl+/17ppgHgthgK+PJtX16AALtsoXonv6uybRCX/YiDRvM1VsdwusVq5tXh9V+bTMZcgi/3Eh+Em/OZp0En8pqOngvL19U4LfqG0yJZjoDGkpHuhA==</ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data>
        <ds:X509Certificate>MIIDgjCCAmqgAwIBAgIVAKgIqbzZl7+0p2qjxJFVJs3DE/jxMA0GCSqGSIb3DQEBBQUAMDAxLjAsBgNVBAMTJWh0dHA6Ly93cGgtdWJpcTI3LmhvdC5jb3JwLmdvb2dsZS5jb20wHhcNMTAwNzIxMTcxNTA5WhcNMzAwNzIxMTcxNTA5WjAwMS4wLAYDVQQDEyVodHRwOi8vd3BoLXViaXEyNy5ob3QuY29ycC5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAioQsJycRmjPjB2xlH0iSGn14lNbO/jIVgiGIlzZwlPkH1s2TTdwoTKKQBSe2s8AnJ4LliXlne/qWun3peYht0+RhejtB20L+Bw/I+iKQBGpHzgIKdkPGZnemWl9KqWQ/ZYKnY2x6qMEBmhUfYZcawzs26em5a+iaYlrTJNVEZ+QwWvg2/EOJvJNyBkSfXyxia5eAHV38Uy7xn0G5Zc9ge4ckCYj6b8a/UxpPJM61KztzY5coDwReQsDBq+DciGALJPbFk4783TW...etc.etc</ds:X509Certificate>
      </ds:X509Data>
    </ds:KeyInfo>
  </ds:Signature>
  <saml2p:Status>
    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"></saml2p:StatusCode>
  </saml2p:Status>
  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" IssueInstant="2010-08-04T17:47:20.956Z" ID="_73fe28bcbb68e93df954d8e2f25097b1">
    <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://my.ssodemo.url.demo.google.com/idp/shibboleth</saml2:Issuer>
    <saml2:Subject>
      <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">my_username</saml2:NameID>
      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml2:SubjectConfirmationData NotOnOrAfter="2010-08-04T17:52:20.956Z" InResponseTo="djfnhepndikoonjjkeomgplmkjofobhdbdieihpa" Recipient="https://www.google.com/a/squaresquare.biz/acs" Address="172.24.6.38"></saml2:SubjectConfirmationData>
      </saml2:SubjectConfirmation>
    </saml2:Subject>
    <saml2:Conditions NotOnOrAfter="2010-08-04T17:52:20.956Z" NotBefore="2010-08-04T17:47:20.956Z">
      <saml2:AudienceRestriction>
        <saml2:Audience>google.com</saml2:Audience>
      </saml2:AudienceRestriction>
    </saml2:Conditions>
    <saml2:AuthnStatement SessionIndex="f306dd2bff4e9b3ba9218bd70fbaa87404d38a4c79547ac1edc9436a9f222213" AuthnInstant="2010-08-04T17:47:20.953Z">
      <saml2:SubjectLocality Address="172.24.6.38"></saml2:SubjectLocality>
      <saml2:AuthnContext>
        <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
      </saml2:AuthnContext>
    </saml2:AuthnStatement>
  </saml2:Assertion>
</saml2p:Response>

Solution 3

Namespace qualifications are optional.

Share:
24,529
Brad Patton
Author by

Brad Patton

Senior Software Developer

Updated on June 12, 2020

Comments

  • Brad Patton
    Brad Patton almost 4 years

    We have a customer trying to use ADFS to SSO on to our web application. We are using the ComponentSpace SAML 2.0 library. The assertion being sent to us looks like:

    <Assertion ID="_b8a24809-ab6b-4acd-ad6a-8bcb97bb1889" IssueInstant="2012-05-24T13:30:33.917Z" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
        <Issuer>http://example.com/adfs/services/trust</Issuer>
        <Subject>
            <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">[email protected]</NameID>
            <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <SubjectConfirmationData NotOnOrAfter="2012-05-24T13:35:33.920Z" Recipient="https://example.com/default.aspx" />
            </SubjectConfirmation>
        </Subject>
        <Conditions NotBefore="2012-05-24T13:30:33.907Z" NotOnOrAfter="2012-05-24T14:30:33.907Z">
            <AudienceRestriction>
                <Audience>https://example.com</Audience>
            </AudienceRestriction>
        </Conditions>
        <AttributeStatement>
            <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">
                <AttributeValue>[email protected]</AttributeValue>
            </Attribute>
        </AttributeStatement>
        <AuthnStatement AuthnInstant="2012-05-24T13:30:33.756Z" SessionIndex="_b8a24809-ab6b-4acd-ad6a-8bcb97bb1889">
            <AuthnContext>
                    <AuthnContextClassRef>urn:federation:authentication:windows</AuthnContextClassRef>
            </AuthnContext>
        </AuthnStatement>
    </Assertion>
    

    The ComponentSpace library is pulling the full SamlResponse from the HTTP post but it reports no Assertions (ie samlResponse.GetAssertions().Count == 0). If I use the ComponentSpace examples it works but I notice all of the elements I build with the ComponentSpace library are prefixed with "saml:" (as I believe it should be).

    Should the ComponentSpace library be able to find the Assertion without the saml: prefix or is there a way to configure ADFS to send it correctly?