Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse a SAML assertion request in .Net

I'm trying to implement a SAML SSO solution in .Net, but I'm having a problem parsing the assertion.

I have a sample assertion (looks like byte[] data as text) and corresponding .p7b file.

I want to load the keys from the .p7b and decrypt the assertion to an XML document.

So far I think I'm reading the keys correctly:

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

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

var samlCertificates = cms.Certificates;

Then I try to parse the assertion I get a problem:

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

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

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

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

That last statement throws an exception, stating that it can't parse the XML content.

I think this means that I'm missing a step decrypting the assertion - getting the byte[] as text converted to a SAML format XML document.

Anyone know how to add this step? Am I missing something else?

like image 518
Keith Avatar asked May 23 '11 15:05

Keith


People also ask

How does SAML assertion work?

SAML works by exchanging user information, such as logins, authentication state, identifiers, and other relevant attributes between the identity and service provider. As a result, it simplifies and secures the authentication process as the user only needs to log in once with a single set of authentication credentials.


1 Answers

I've figured this out - I was missing part of the SAML specification.

The assertion is sent (rather weirdly, since it isn't encrypted) as base64 data, and it was being URL encoded twice as it was sent.

So adding this step gives us a valid assertion:

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

// the sample data sent us may be already encoded, 
// which results in double encoding
if (rawSamlData.Contains('%'))
{
    rawSamlData = HttpUtility.UrlDecode(rawSamlData);
}

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

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

The authentication still isn't working, but I now have valid XML so it's a different problem.

like image 85
Keith Avatar answered Sep 20 '22 02:09

Keith