When the SAML token is created by using of SbbSecurityTokenSerializer as shown in this example, the WCF builds XML file, which is signed according to Xml Signature specification.
One example of some test SAML token created this way is shown below:
<?xml version="1.0" encoding="utf-8" ?> <saml:Assertion MajorVersion="1" MinorVersion="1" AssertionID="DaenetSamlTest" Issuer="damir" IssueInstant="2007-02-22T09:44:18.379Z" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"> <saml:AttributeStatement> <saml:Subject> <saml:NameIdentifier>My Subject</saml:NameIdentifier> </saml:Subject> <saml:Attribute AttributeName="My ATTR Value" AttributeNamespace="http://daenet.eu/saml"> <saml:AttributeValue>Some Value 1</saml:AttributeValue> <saml:AttributeValue>Some Value 2</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> <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/2000/09/xmldsig#rsa-sha1" /> <Reference URI="#DaenetSamlTest"> <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/2000/09/xmldsig#sha1" /> <DigestValue>6PvoHy2nU7Qs2KQY5PRCoIVVvIA=</DigestValue> </Reference> </SignedInfo>
<SignatureValue>jo5KyTTBRHYwNGywNx5Vy7EndkeEt7fhOeBLld1l1SV0IH128/AQ1GhzdStpc0GljRizYyOTG660sc55Ic+qT7ZHTJdTzptKsIGpQUVPWzZen9MMgpwdrpr8PNG8c11iG/UX9SJADafdEMHQmG00m1glzEJFJ1gfAbESPhWp8bg=</SignatureValue> <KeyInfo> <o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1">VFw7jpfZn9dcdetSxpCDIAiLT1A=</o:KeyIdentifier> </o:SecurityTokenReference> </KeyInfo> </Signature> </saml:Assertion> |
The shown XML is SAML assertion with ID = DaenetSamlTest and the XML signature which starts at node Signature. By definition, one signature element can contain a number of references (node Reference), which signes a specific part of document. In this example the only reference contains the signature of the node with assertion ID = DaenetSamlTest (defined by reference URI) In other words the signature in element Reference is the signature of the all XML document (excluding signature). Similar, it is possible even to specify the XPath, which points the specific subset of the document.
Now, if the same token is signed by the JAVA Open XML library, the output document looks little different. Following example shows some SAML assertion signed by Open XML library:
<Assertion AssertionID="dd224eb134595686a04faf14680e02b1" IssueInstant="2007-02-22T18:10:58.406Z" Issuer="http://sbb.deutschepost.de/samlauthority" MajorVersion="1" MinorVersion="1" xmlns="urn:oasis:names:tc:SAML:1.0:assertion"> <Conditions NotBefore="2007-02-22T17:10:57.000Z" NotOnOrAfter="2007-03-04T18:10:57.000Z" xmlns="urn:oasis:names:tc:SAML:1.0:assertion"> <AudienceRestrictionCondition xmlns="urn:oasis:names:tc:SAML:1.0:assertion"> <Audience xmlns="urn:oasis:names:tc:SAML:1.0:assertion">http://sbb.deutschepost.de/serviceconsumer1</Audience> <Audience xmlns="urn:oasis:names:tc:SAML:1.0:assertion">http://sbb.deutschepost.de/serviceconsumer2</Audience> </AudienceRestrictionCondition> </Conditions> <AuthenticationStatement AuthenticationInstant="2007-02-22T17:10:57.000Z" AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" xmlns="urn:oasis:names:tc:SAML:1.0:assertion"> <Subject xmlns="urn:oasis:names:tc:SAML:1.0:assertion"> <NameIdentifier NameQualifier="pNameQualifierValue" xmlns="urn:oasis:names:tc:SAML:1.0:assertion">SOPAdministrator</NameIdentifier> <SubjectConfirmation xmlns="urn:oasis:names:tc:SAML:1.0:assertion"> <ConfirmationMethod xmlns="urn:oasis:names:tc:SAML:1.0:assertion"> urn:oasis:names:tc:SAML:1.0:cm:holder-of-key</ConfirmationMethod> </SubjectConfirmation> </Subject> </AuthenticationStatement> <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/2000/09/xmldsig#rsa-sha1" /> <ds:Reference URI=""> <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="code ds kind rw saml samlp typens #default" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" /> </ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>T4mAhF2OIA53JDjYTGgCMMLiCz4=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>5OenGctGaWbtVr0SKBFaAZWtrDHujo+OAsKIz9Rp6DH0xtZD4LSmY3g514nVhSTE2SbIUU3YOqtu n+BAjv4AOfP6OqcCcXu/OUA4gfRp1sE/gol8SSpMUtamtOMTq8odJ0lxyNHJ1B7zp4F+q/JS7/c/ /2gHGgbViGbPuVdL4+U=</ds:SignatureValue> </ds:Signature> </Assertion> |
Note that token in this example is some other token than the token in previous example. AT this point it is interesting that the reference URI is an empty string. According to SAML specification, this signature reference by default should be related to the root of the document. In other words, it is a signature of the whole document (excluding Signature itself) with the assertion ID = dd224eb134595686a04faf14680e02b1.
That means that these two examples are semantically the same. Unfortunately, the WCF class SbbSecurityTokenSerializer throws an cryptographic exception (UnableToResolveReferenceUriForSignature) if the reference URI is an empty string. The exact method of deserializing of the token is shownhere.
To exactly understand what is going on here, we decided to deep down in the WCF source code and found following code which throws exactly this exception:
public string ExtractReferredId() {
if (this.referredId == null)
{
if (((this.uri == null) || (this.uri.Length < 2)) || (this.uri[0] != '#'))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString("UnableToResolveReferenceUriForSignature", new object[] { this.uri })));
}
this.referredId = this.uri.Substring(1);
}
return this.referredId;
} |
I'm not sure, but it seems that the WCF implementation of the class Reference which contained in System.IdentityModel.Dll does not implement exactly the SAML specification. The condition in the code above explicitely does not allow that reference URI be an empty string. I would be glad if somebody comment this example.
In the few days DAENET team will post a very simply work around which shows how to verify the token by avoiding of SbbSecurityTokenSerializer and WCF and by sing directly the class SignedXml.
Posted
Feb 23 2007, 10:59 AM
by
Damir Dobric