3
votes

I have a SAML assertion that I wish to authenticate in .Net using WSSecurityTokenSerializer.

I've got the key-chain and SAML XML, despite a few issues.

First I get the SAML assertion from the HTTPS POST:

// spec says "SAMLResponse=" 
string rawSamlData = Request["SAMLResponse"];

// read the base64 encoded bytes
byte[] samlData = Convert.FromBase64String(rawSamlData);

// read back into a UTF string
string samlAssertion = Encoding.UTF8.GetString(samlData);

// get the SAML data in an XML reader
var assertionPostStream = new StringReader(samlAssertion);
var reader = XmlReader.Create(assertionPostStream);

Then I get the keys provided by my IdP:

// get the key data
byte[] certificateData = System.IO.File.ReadAllBytes("myKeys.p7b");

// decode the keys
var cms = new SignedCms(SubjectIdentifierType.IssuerAndSerialNumber);
cms.Decode(certificateData);

// we have a keychain of X509Certificate2s, we need a collection of tokens
var certificatesAsTokens =
    from X509Certificate2 cert in cms.Certificates
    select new X509SecurityToken(cert) as SecurityToken;

// get a token resolver
var tokens = new ReadOnlyCollection<SecurityToken>(
    certificatesAsTokens.ToList());
var resolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(
    tokens, true);

Finally I get an error thrown here:

// use the WS Security stuff to parse the reader
var securityToken = WSSecurityTokenSerializer.
    DefaultInstance.ReadToken(reader, resolver) as SamlSecurityToken;

When calling that ReadToken I get the following error:

Cannot read the token from the 'Response' element with the 'urn:oasis:names:tc:SAML:2.0:protocol' namespace for BinarySecretSecurityToken, with a '' ValueType. If this element is expected to be valid, ensure that security is configured to consume tokens with the name, namespace and value type specified.

My SAML XML starts with:

<Response xmlns="urn:oasis:names:tc:SAML:2.0:protocol" ...

So clearly I have a Response element in the urn:oasis:names:tc:SAML:2.0:protocol namespace.

Any idea what's wrong/missing here?

1
After days of digging (the documentation on this stuff is terrible) I think that this may be due to WSSecurityTokenSerializer relying on a variant of SAML 1.1 rather than SAML 2.0 - I've switched to trying to verify the signature directly: stackoverflow.com/questions/6126388Keith

1 Answers

5
votes

It looks like you are receiving a SAML2 response. Although there is support for SAML2 in .NET 4.5, there is unfortunately only support for the assertions - not the protocol itself (including the Response message).

To process the SAML2 response in .NET you have to:

  1. Validate the signature on the entire response message.
  2. Extract the assertion part of the message.
  3. Read the token with Saml2SecurityTokenHandler.ReadToken().
  4. Validate the token with Saml2SecurityTokenHandler.DetectReplayedToken().
  5. Validate the token with Saml2SecurityTokenHandler.ValidateConditions()
  6. Use Saml2SecurityTokenHandler.CreateClaims() to create a claims identity.

Unfortunately most of those methods are protected, but you can subclass Saml2SecurityTokenHandler and get access to them.

A complete working example can be found in the Saml2Response class in the Sustainsys.Saml2 project.