How to parse a SAML assertion request in .Net

20,460

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.

Share:
20,460
Keith
Author by

Keith

Keith Henry Chief Software Architect, building offline-first and responsive applications in the recruitment industry. I'm also on Linked In. Email me on Google's email, my address is ForenameSurname.

Updated on July 31, 2022

Comments

  • Keith
    Keith almost 2 years

    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?

  • Lucky Pierre
    Lucky Pierre almost 11 years
    Thanks for posting how you got it working. It just saved me a lot of time.