Working with SAML 2.0 in C# .NET 4.5

bugnuker picture bugnuker · Mar 20, 2013 · Viewed 92.3k times · Source

I am trying to use pure .NET (no external classes, controls, helpers) to create a SAML message. I found some code on the interwebs; this is what I have:

private static SamlAssertion createSamlAssertion()
{
    // Here we create some SAML assertion with ID and Issuer name. 
    SamlAssertion assertion = new SamlAssertion();
    assertion.AssertionId = "AssertionID";
    assertion.Issuer = "ISSUER";
    // Create some SAML subject. 
   SamlSubject samlSubject = new SamlSubject();
    samlSubject.Name = "My Subject";

    // 
    // Create one SAML attribute with few values. 
    SamlAttribute attr = new SamlAttribute();
    attr.Namespace = "http://daenet.eu/saml";
    attr.AttributeValues.Add("Some Value 1");
    //attr.AttributeValues.Add("Some Value 2");

    attr.Name = "My ATTR Value";

    // 
    // Now create the SAML statement containing one attribute and one subject. 
    SamlAttributeStatement samlAttributeStatement = new SamlAttributeStatement();
    samlAttributeStatement.Attributes.Add(attr);
    samlAttributeStatement.SamlSubject = samlSubject;

    // Append the statement to the SAML assertion. 
    assertion.Statements.Add(samlAttributeStatement);

    //return assertion
    return assertion;

}

and here is the code I am using to get the XML:

var sb = new StringBuilder();
var settings = new XmlWriterSettings
{
    OmitXmlDeclaration = true,
    Encoding = Encoding.UTF8
};
using (var stringWriter = new StringWriter(sb))
using (var xmlWriter = XmlWriter.Create(stringWriter, settings))
using (var dictionaryWriter = XmlDictionaryWriter.CreateDictionaryWriter(xmlWriter))
{
    var samlAssertSerializer = new SamlSerializer();
    var secTokenSerializer = new WSSecurityTokenSerializer();
    assertion.WriteXml(
        dictionaryWriter,
        samlAssertSerializer,
        secTokenSerializer
    );
}

This seemed like it was going to work. However, the message is produces is SAML version 1.0 - I need to work with 2.0.

I know I can do some sloppy work and replace some values here and there and this system would work fine. There are very little differences in the message, version being the most important. I am having a hard time finding information on SAML 2.0 for .NET. I do know SAML 2.0 was implemented into .NET recently. I am using Framework 4.5 so I should have access to it. The MSDN page for SamlAssertion says the "majorVersion" is a constant, always set to '1'.

I'm guessing there is another namespace I could be working with, but I haven't found it. My requirement is just to get the XML SAML message. I don't need to sign with X509, I don't need the token. Just the SAML XML message.

Again, this is a question trying to find out how to do this in native .NET. I have found several SAML helpers and lots of code on how to build the message manually- I'm trying to find the CORRECT solution, if it exists.

EDIT: I have found I can use Saml2Assertion. However, I am unable to find a way to get the SAML message written to xml now.

EDIT2: I have found how to write the Saml2Assersion object to xml. Sadly, it does not keep the SAML syntax, it writes in pure XML without <saml> tags.

Answer

bugnuker picture bugnuker · Mar 21, 2013

.NET 4.5 has WIF (Windows Identity Foundation) built into it. This now supports SAML 2.0. To make use of SAML 2.0, just use .NET 4.5. The class name is Saml2XXXX (where XXXX is the token, assertion, serializer etc) Here is a link to SAML 2.0 Assertion: http://msdn.microsoft.com/en-us/library/microsoft.identitymodel.tokens.saml2.saml2assertion.aspx

This will create a SAML 2.0 Assertion object. To get the XML, this is the code I used:

using System.Xml;
using System.IdentityModel.Tokens;

namespace YOUR.SPACE
{
    public class Saml2Serializer : Saml2SecurityTokenHandler
    {
        public Saml2Serializer()
        {
            Configuration = new SecurityTokenHandlerConfiguration()
                {

                };
        }

        public void WriteSaml2Assertion(XmlWriter writer, Saml2Assertion data)
        {
            base.WriteAssertion(writer, data);
        }
    }
}

This will serialize your assertion object into XML. This is where I ran into problems. The XML is will create does NOT contain the saml namespace (e.g. <saml:Assertion>). I was not able to find a solution for this, so a Replace("<", "<saml:") had to be used.