Another Way to do IdP-initiated SSO in .NET

| | Comments (0) | TrackBacks (0)
In my last post, I wrote about how to do IdP-initiated SSO using WIF. It was pretty easy stuff (once I got my digital signature's bytes where they belonged). From that post, you can see that it's not hard to generate a SAML assertion, put it in a form, and post it to a SAML service provider (SP). This can be done using ComponentSoft's SAML lib as well. It's equally as simple w/ one difference: The toolkit is all about SAML, so it exposes the nitty gritty parts of the protocol, making it easy to support more exotic use cases.

In my last example, the SAML response was more or less an envelope containing the SAML assertion. In some cases, you might want to do more w/ the response. For example, you might want to sign it, add a destination, an issuer, etc. You can absolutely do this w/ just WIF and .NET, but doing it w/ ComponentSoft's toolkit makes it really simple. To see how this might work, the previous example can be modified to use the following code to sign the SAML response rather than the assertion, serialize the message, etc.

using ComponentSoft.Saml2;
...

public partial class _Default2 : System.Web.UI.Page
{
    ...

    private string CreateSamlResponse()
    {
        var samlResponse = new ComponentSoft.Saml2.Response();
        var assertion = CreateAssertion();

        samlResponse.Assertions.Add(assertion);
        samlResponse.Status = new Status(SamlPrimaryStatusCode.Success, null);
        samlResponse.Issuer = new Issuer(issuer);
        samlResponse.Destination = assertionConsumerEndpoint;
        samlResponse.Sign(CertificateUtil.GetCertificate(StoreName.My,
            StoreLocation.CurrentUser, signingCertCommonName));

        return samlResponse.ToBase64String();
    }

    private Assertion CreateAssertion()
    {
        var userName = claimDescriptors[ClaimTypes.NameIdentifier];
        var subject = new Subject(new NameId(userName));
        var assertion = new Assertion
        {
            Issuer = new Issuer(issuer),
            Subject = subject,
        };

        AddConfirmationData(assertion);
        AddAuthenticationStatement(assertion);
        AddAttributeStatement(assertion);

        return assertion;
    }

    private void AddAttributeStatement(Assertion assertion)
    {
        var attributes = new AttributeStatement();

        foreach (var claim in claimDescriptors)
        {
            attributes.Attributes.Add(new Attribute(claim.Key, claim.Key, claim.Value, claim.Value));
        }

        assertion.Statements.Add(attributes);
    }

    private void AddAuthenticationStatement(Assertion assertion)
    {
        var authenticationMethod = "url:none";
        var authetnicationStatement = new AuthnStatement
        {
            AuthnContext = new AuthnContext
            {
                AuthnContextClassRef = new AuthnContextClassRef(authenticationMethod),
            },
        };
        
        assertion.Statements.Add(authetnicationStatement);
    }

    private static void AddConfirmationData(Assertion assertion)
    {        
        var subjectConfirmationData = new SubjectConfirmationData
        {
            Recipient = assertionConsumerEndpoint,
            NotOnOrAfter = System.DateTime.UtcNow.AddMinutes(tokenLifetime),
        };
        var subjectConfirmation = new SubjectConfirmation
        {
            Method = SamlSubjectConfirmationMethod.Bearer,
            SubjectConfirmationData = subjectConfirmationData,
        };
        var audienceRestriction = new AudienceRestriction();

        audienceRestriction.Audiences.Add(new Audience(appliesTo));
        assertion.Conditions = new Conditions();
        assertion.Conditions.ConditionsList.Add(audienceRestriction);

        assertion.Subject.SubjectConfirmations.Add(subjectConfirmation);
    }
}

So, there you have another way work w/ SAML in .NET. One additional thing about using ComponentSoft's toolkit that's nice is that it provides support for not only IdP-initiated SSO like I've shown here but also other use cases such as SP-initiated SSO, SLO, etc.