How to parse a SAML assertion request in .Net
Asked Answered
O

2

7

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?

Ohare answered 23/5, 2011 at 15:37 Comment(0)
O
17

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.

Ohare answered 24/5, 2011 at 9:41 Comment(1)
Thanks for posting how you got it working. It just saved me a lot of time.Alejandraalejandrina
D
0

This is my working source code :

            byte[] samlData = Convert.FromBase64String(samlresponse);

            var decompressedStream = SAMLUtility.Decompress(samlData);
            StreamReader reader = new StreamReader(decompressedStream);
            var decodedSaml = reader.ReadToEnd();

            var serializer = new XmlSerializer(typeof(Response));
            Response samlResponse;

            using (TextReader reader1 = new StringReader(decodedSaml))
            {
                samlResponse = (Response)serializer.Deserialize(reader1);
            }

            if (samlResponse.Status.StatusCode.Value.Contains("Success"))
                return samlResponse;
            else
                return null;
Dissymmetry answered 25/7, 2022 at 9:29 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Comstock

© 2022 - 2024 — McMap. All rights reserved.