I want to know how digestValue was calculated when we have AttributeStatement in the SAML 2 Response. I can calculate and get the same digestValue when I do not have any "saml2:AttributeStatement" returned in SAML response by:
- Deleting ds:Signature segment
- Canonicalizing XML payload
- Applying SHA-256 to calculate digest value (as I configured on IDP part)
But when I configured in IDP side to add "saml2:AttributeStatement" in the response along with one attribute, I can no longer calculate the same digestvalue as IDP returned to me no matter I kept "saml2:AttributeStatement" or not.
What shall I do here to calculate the correct value? FYI, I am using OKTA IDP.
My SAML Assertion in my SAML response is as follows:
<saml2:Assertion ID="id2725281198079267683856882"
IssueInstant="2021-09-20T07:18:33.051Z"
Version="2.0"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
>http://www.okta.com/exk1mv3c9ke9u3tz25d7
</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="#id2725281198079267683856882">
<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#">
<ec:InclusiveNamespaces PrefixList="xs"
xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"
/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<ds:DigestValue>uHowdunaQ+0tDsHrEGgJFUWwd23L08Qubp9HFS2In2Q=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>S9YQNf7t...</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDq...
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">[email protected]</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="a3b3ff8jicf316993316069j03bdjfj"
NotOnOrAfter="2021-09-20T07:23:33.051Z"
Recipient="http://localhost:8080/saml/SSO"
/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2021-09-20T07:13:33.051Z"
NotOnOrAfter="2021-09-20T07:23:33.051Z"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
>
<saml2:AudienceRestriction>
<saml2:Audience>http://localhost:8080/saml/metadata</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2021-09-20T07:18:33.051Z"
SessionIndex="a3b3ff8jicf316993316069j03bdjfj"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
>
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:Attribute Name="email"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
>
<saml2:AttributeValue
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="xs:string"
>[email protected]
</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
Issue resolved. There is a gap between OKTA performing Canonicalization and what is provided in Java org.apache.xml.security.c14n.Canonicalizer.getInstance(String). In Java implementation they deleted namespace xmlns:xs="http://www.w3.org/2001/XMLSchema", but OKTA kept it. After I added this namespace in canonicalized SAML Assertion and calculated digest value, I got same value as OKTA.