Designing claims-based tokens using Security Assertion Markup Language

The Security Assertion Markup Language (SAML) specification is an open security standard envisioned by Organization for the Advancement of Structured Information Standards (OASIS) Technical Committee for the exchange of security context across service boundaries. The SAML tokens are XML-based (can be transmitted using SOAP/HTTP) and provide a way of implementing claims-based identity that is particularly useful in interoperable scenarios across the identity providers and the service providers. This recipe shows how to create the SAML security tokens using the System.IdentityModel assembly in .NET Framework 4.0.

Getting ready

If you are not familiar with the SAML v1.1 specification, you can get the standard set and the schema files from http://www.oasis-open.org/standards#samlv1.1.

How to do it...

To generate a SAML v1.1 token, the System.IdentityModel.Tokens namespace in the System.IdentityModel assembly provides a SamlSecurityToken class that inherits from System.IdentityModel.Tokens.SecurityToken, the base class for creating all types of security tokens. To create a SamlSecurityToken, we will be extending the solution created in the previous recipe:

  1. Right-click on the WindowsIdentityToClaimsConsole project, and add reference to the System.ServiceModel assembly, as shown in the following screenshot:
    How to do it...
  2. Open the Program.cs file, and include the System.IdentityModel tokens and System.ServiceModel security namespaces.
  3. Before we can create SamlSecurityToken, we need to create an instance of the SamlAssertion object that holds the claims information abstracted from the current windows identity. We will write a private static method that accepts a collection of the Claim objects and returns a SamlAssertion object:
    var accessControlClaims = claims.FindClaims(ClaimTypes.Sid, Rights.PossessProperty);
    SamlAssertion assertion = CreateSamlAssertionFromWindowsIdentityClaims(accessControlClaims);
    

    Note

    The WindowsClaimSet instance is filtered to fetch only the claims of the SecurityIdentifier type and having the PossessProperty right.

  4. Inside the CreateSamlAssertionFromWindowsIdentityClaims method, first we will create an instance of the SamlAttributeStatement class and assign SamlSubject to it. In our example, we have named the subject as Windows Group Claim:
    SamlSubject subject = new SamlSubject()
    {
    Name = "Windows Group Claim"
    };
    SamlAttributeStatement statement = new SamlAttributeStatement()
    {
    SamlSubject = subject
    };
    
  5. Next, we will create an instance of SamlAssertion and assign the AssertionId and Issuer properties. The issuer could be self when the claims are self-asserted. In our example, we have specified System because the claims are issued by Windows:
    SamlAssertion assertion = new SamlAssertion()
    {
    AssertionId = string.Format("_{0}", Guid.NewGuid().ToString()),
    Issuer = "System"
    };
    

    Note

    AssertionId is prepended with an underscore. According to the specification, AssertionId must start with a non-numeric character.

  6. Iterate the collection of claims and create the SamlAttribute instances using the Claim properties:
    foreach (var claim in claims)
    {
    Claim samlClaim = new Claim(claim.ClaimType, GetResourceFromSid(claim.Resource as SecurityIdentifier), claim.Right);
    SamlAttribute attribute = new SamlAttribute(samlClaim);
    statement.Attributes.Add(attribute);
    }
    

    Note

    The Resource property of the Claim instance is type casted into SecurityIdentifier, and the translated named string is used to create the attribute.

  7. We can now create SamlSecurityToken using the SamlAssertion instance returned by the CreateSamlAssertionFromWindowsIdentityClaims method:
    SamlSecurityToken token = new SamlSecurityToken(assertion);
    
  8. Compile and run the project. A SAML v1.1 token is generated and saved into the filesystem under C drive (change the path in code to map to an accessible location in your machine). The console window will display the message—Saml Token Successfully Created. Open the token file (Saml.xml) in an XML editor, and you will find the claims fetched from your Windows Identity listed as the saml attributes:
    How to do it...

How it works...

The System.IdentityModel.Tokens namespace exposes the objects that can be serialized into the XML elements corresponding to the SAML v1.1 security token specification. According to the specification, claims are abstracted in SamlAssertion (<saml:Assertion>) in the form of one or more SamlAttributeStatement (<saml:AttributeStatement>) instances containing a subject (<saml:Subject>) and a set of attributes (<saml:Attribute>) representing the claim type (AttributeName) and claim value (<saml:AttributeValue>). SamlAssertion is uniquely identified using AssertionId and Issuer. You will notice that in our solution we are not storing the Claim object directly into SamlAttribute. SAML v1.1 specification puts a restriction that only resources identifiable by a named string can be used as a SamlAttribute value. In our example, we are using a helper method to translate SecurityIdentifier into readable NTAccount named permissions:

private static string GetResourceFromSid(SecurityIdentifier sid)
{
try
{
return sid.Translate(typeof(NTAccount)).ToString();
}
catch (Exception)
{
return sid.Value;
}
}

Note

The translation exercise queries the Active Directory for name resolution. Your system must be plugged into the network if your credentials are provided by a domain controller.

There's more...

SamlAssertion is digitally signed using a certificate to create SamlSecurityToken. This token can be serialized and included in a SOAP header to be transmitted across security boundaries. Additional policies for SamlSecurityToken can be provided by using the SamlAdvice and SamlCondition classes corresponding to the<saml:SamlAdvice> and<saml:SamlConditions> elements of the SAML v1.1 specification.

Signing an assertion digitally

The SAML token needs to be digitally signed using a certificate to validate the authenticity of the issuer. In our solution, we are signing the assertion using a self-issued X.509 certificate. The SamlAssertion class exposes a SigningCredentials property that is used to digitally sign the SAML assertion:

private static void SignSamlAssertion(SamlAssertion assertion)
{
X509Certificate2 certificate2 = GetCertificateFromStore(StoreLocation.CurrentUser, DateTime.Now, "CN=SamlTokenSigningCertificate");
if (certificate2 != null)
{
X509AsymmetricSecurityKey securityKey = new X509AsymmetricSecurityKey(certificate2);
assertion.SigningCredentials = new SigningCredentials(
securityKey,
SecurityAlgorithms.RsaSha1Signature,
SecurityAlgorithms.Sha1Digest,
new SecurityKeyIdentifier(new X509ThumbprintKeyIdentifierClause(certificate2)));
}
}

Serializing SamlSecurityToken

The System.ServiceModel.Security namespace has a WSSecurityTokenSerializer class that can be used to serialize and deserialize the security tokens conforming to the WS-Security and the WS-Trust specifications. In our solution, we are using a XmlWriter class to persist the token into the filesystem:

private static void SerializeSamlTokenToFile(SamlSecurityToken token)
{
using (XmlWriter writer = XmlWriter.Create(@"c:saml.xml"))
{
try
{
WSSecurityTokenSerializer keyInfoSerializer = new WSSecurityTokenSerializer();
keyInfoSerializer.WriteToken(writer, token);
Console.WriteLine("Saml Token Successfully Created");
}
catch (Exception)
{
Console.WriteLine("Failed to save Saml Token to Disk");
}
}
}

SamlAdvice and SamlConditions

The SamlAssertion class contains the SamlAdvice and SamlCondition properties that provide additional information to the service provider while processing a token. These properties conform to the<saml: Advice> and<saml: Conditions> elements of the SAML v1.1 specification. SamlAdvice could be used to provide supporting information about an issuer. Similarly, conditions such as SamlDoNotCacheCondition and SamlAudienceRestrictionCondition are defined by the SAML v1.1 specification and are used to apply the token caching and audience restriction policies respectively.

See also

The complete source code for this recipe can be found in the Chapter 1Recipe 2 folder. In addition, the MSDN article at http://msdn.microsoft.com/en-us/magazine/cc163366.aspx by Keith Brown provides useful information about claims-based identity and the security identifier translation used in our recipe is sourced from this article.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.216.254