Microsoft Windows Identity Foundation Cookbook

By Sandeep Chanda
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Overview of Claims-based Identity

About this book

Implementing security as a cross-cutting concern has several challenges. Consequently, modern software development practices and Service Oriented Architectures are alluding to the idea of claims-based Identity for access control. Microsoft’s Identity and Access Control paradigm leverages industry standard open specifications and provides tools, runtime and platform support for facilitating the development of claims-enabled applications.

Microsoft Windows Identity Foundation Cookbook explores real world scenarios on building claims-enabled .NET applications using Microsoft Windows Identity Foundation (WIF), Active Directory Federation Services 2.0 (AD FS 2.0) and Windows Azure Access Control Services (ACS).

This book covers all aspects of several real world challenges that professional developers face while enabling support for claims-based identity across interoperable platforms and building claims-enabled applications. The book then goes on to explore AD FS 2.0 and provides step-by-step details on how claims support is enabled in Microsoft’s server technologies.

The book starts by introducing you to the world of claims-based identity in .NET Framework 4.0. It then moves on to showcase the capabilities of the runtime and the associated SDK including the steps to perform identity delegation in ASP.NET MVC 3 applications, create WCF security token services, extend the runtime to provide support for SAML 2.0 specifications and use AppFabric as a trusted source for implementing access control. Further, the book explores AD FS 2.0 and features recipes showcasing steps to configure claims in Microsoft’s server technologies. It also features a chapter on some of the newer capabilities of the runtime including providing support for claims in Windows Workflow Foundation and Windows 8 Metro applications.

Windows Identity Foundation Cookbook provides a mix of recipes from basic to advanced to enable professional developers to implement claims-based identity in enterprise-wide scalable and interoperable applications.

Publication date:
April 2012
Publisher
Packt
Pages
294
ISBN
9781849686204

 

Chapter 1. Overview of Claims-based Identity

As a developer of the Microsoft .NET Framework 4.0 based applications, in this chapter you can look forward to learning the ways of:

  • Abstracting identity with claims

  • Designing the claims-based tokens using Security Assertion Markup Language (SAML)

  • Augmenting security with a claims-based architecture

  • Implementing federated security using a Security Token Service (STS)

  • Implementing Single Sign-On using claims

  • Implementing Single Sign-Out in a trust realm

  • Configuring certificates for the claims-based applications

Introduction

Claims-based identity provides a standard way of acquiring identity information by heterogeneous applications to validate service requests within and outside an organization and also over the Web. This chapter is a precursor to the forthcoming chapters on Windows Identity Foundation (WIF), Windows Azure Access Control Services (ACS 2.0), and Active Directory Federation Services v2.0 (AD FS 2.0), all of these being a part of the Microsoft's initiative in the identity and access management using claims. The chapter explores the recipes for abstracting identity with claims and provides an overview of the Security Assertion Markup Language specifications. In addition, this chapter also explores a few claims-based architectures that help augment existing security infrastructure. The chapter is designed towards preparing the readers for the rest of the book.

Note

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.PacktPub.com. If you purchased this book elsewhere, you can visit http://www.PacktPub.com/support and register to have the files e-mailed directly to you.

 

Introduction


Claims-based identity provides a standard way of acquiring identity information by heterogeneous applications to validate service requests within and outside an organization and also over the Web. This chapter is a precursor to the forthcoming chapters on Windows Identity Foundation (WIF), Windows Azure Access Control Services (ACS 2.0), and Active Directory Federation Services v2.0 (AD FS 2.0), all of these being a part of the Microsoft's initiative in the identity and access management using claims. The chapter explores the recipes for abstracting identity with claims and provides an overview of the Security Assertion Markup Language specifications. In addition, this chapter also explores a few claims-based architectures that help augment existing security infrastructure. The chapter is designed towards preparing the readers for the rest of the book.

Note

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.PacktPub.com. If you purchased this book elsewhere, you can visit http://www.PacktPub.com/support and register to have the files e-mailed directly to you.

 

Abstracting identity with claims


Authentication and authorization are two of the most common aspects of the application security. In Windows, security is generally handled using the Kerberos or the NTLM security tokens. The user is provided with credentials that include a domain user ID and a password, and these credentials are validated against the user's entry in the Active Directory. Role-based security is implemented with the help of authorization managers that control the level of access for the user.

This works well within the boundaries of the Windows ecosystem; however, it gets difficult if the application has to support the users that do not have Windows Active Directory credentials. In the real world, the applications spanning multiple platforms interact with each other and require the security context to be shared. Using a claims-based identity model provides a robust way of handling authentication and authorization across the discrete systems. Throughout this chapter, we will explore the recipes that will help you gain an understanding of how claims-based identity is core to the .NET Framework 4.0 and help you get started on the Microsoft's Identity and Access Management paradigm. In this recipe, we will find out how a Windows identity can be abstracted with claims using the System.IdentityModel assembly in .NET Framework 4.0.

How to do it...

To create a collection of claims from a WindowsIdentity (System.Security.Principal) object, perform the following steps:

  1. 1. Create a new Visual C# Console Application project in Visual Studio 2010.

  2. 2. Add a reference to the System.IdentityModel assembly, as shown in the following screenshot:

  3. 3. Open the Program.cs file, and include the System.IdentityModel.Claims and the System.Security.Principal namespaces.

  4. 4. In the Main method, create a new instance of the WindowsClaimSet class, and pass the current context identity as a parameter to the constructor:

    using (WindowsClaimSet claims = new 
    WindowsClaimSet(WindowsIdentity.GetCurrent()))
    {
    }
    
  5. 5. Loop through the ClaimSet object and print the claim information into the console output:

    using (WindowsClaimSet claims = new WindowsClaimSet(WindowsIdentity.GetCurrent()))
    {
    foreach (var claim in claims)
    {
    Console.WriteLine(string.Format("Claim Type: {0}", claim.ClaimType));
    Console.WriteLine(string.Format("Resource: {0}", claim.Resource.ToString()));
    Console.WriteLine(string.Format("Right: {0}", claim.Right));
    Console.WriteLine ("**********************************************");
    }
    }
    Console.ReadLine();
    
  6. 6. Compile and run the project. The result is displayed in the console window:

How it works...

The WindowsClaimSet class inherits from the System.IdentityModel.Claims.ClaimSet. ClaimSet represents a collection of claims ( System.IdentityModel.Claims.Claim) associated with an entity. The WindowsClaimSet constructor accepts the current Windows user identity as a parameter and returns a ClaimSet object containing the collection of claims that represent the Windows Active Directory groups of the user. The current Windows user identity is fetched using the WindowsIdentity.GetCurrent method. Generated ClaimSet can be used to create a signed security token that can be passed on to a service to create a security context and implement role-based access control. We will see how to create a security token from a ClaimSet object later in the chapter.

Note

The default expiration time for the claims collection is set to 10 hours. You can explicitly set the expiration time in the WindowsClaimSet overloaded constructor.

A claim is used to identify a user or provide access to a particular resource requested by the user. There are three properties exposed by the Claim class:

  • ClaimType: It identifies the type of claim. In our example, Sid (security identifier) and Name are the two claim types displayed in the console window. A list of supported claim types is available at the following URL: http://msdn.microsoft.com/en-us/library/system.identitymodel.claims.claimtypes.aspx.

  • Resource: It identifies the resource associated with the claim.

  • Right: It is a URI representing the Identity or PossessProperty right associated with the claim. PossessProperty determines whether the user has the access to Resource.

Both the Claim and the ClaimSet classes are serialization-friendly, which allows them to be transmitted over service boundaries.

There's more...

In addition to WindowsClaimSet, the System.IdentityModel.Claims namespace provides a DefaultClaimSet class that allows you to create your implementation of claims, and a X509CertificateClaimSet class to abstract claims from an X.509 certificate.

Authorization context

The System.IdentityModel.Policy namespace exposes a AuthorizationContext class that can be used to evaluate the authorization policies in a sent message. The AuthorizationContext class has a ClaimSet property that allows a service to retrieve all the claims associated with the security token in the sent message. You can learn more with an example in the MSDN documentation at http://msdn.microsoft.com/en-us/library/system.identitymodel.policy.authorizationcontext.claimsets.aspx.

See also

The complete source code for this recipe can be found in the \Chapter 1\Recipe 1\ folder.

 

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. 1. Right-click on the WindowsIdentityToClaimsConsole project, and add reference to the System.ServiceModel assembly, as shown in the following screenshot:

  2. 2. Open the Program.cs file, and include the System.IdentityModel tokens and System.ServiceModel security namespaces.

  3. 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. 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. 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. 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. 7. We can now create SamlSecurityToken using the SamlAssertion instance returned by the CreateSamlAssertionFromWindowsIdentityClaims method:

    SamlSecurityToken token = new SamlSecurityToken(assertion);
    
  8. 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 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 1\Recipe 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.

 

Augmenting security with a claims-based architecture


The claims-based architecture can be used to augment your existing security implementation. A common approach will be to create a token service that verifies the consumer identity and creates a signed token including the claims necessary for accessing a resource from a service, living within or outside the security boundaries of the consumer.

The following diagram illustrates this scenario:

The previous recipe showed us the steps to create SamlSecurityToken. In this recipe, we will create a claims service that accepts the client credentials and returns signed SamlSecurityToken using the group-level permissions of the user as claims. In a Single Sign-On scenario, the generated security token will be posted using form variables to the service provider to get authenticated and make a claim for service access. We will limit the scope of this recipe to understand how a token can be generated using the token service and returned back to the client.

Getting ready

Create a Saml11Helper class using the methods from the previous recipe to create SamlSecurityToken using the ClaimSet object. Modify the serialization helper to return a token XML string instead of writing into a file.

public static string SerializeSamlToken(SamlSecurityToken token)
{
StringBuilder samlBuilder = new StringBuilder();
using (XmlWriter writer = XmlWriter.Create(samlBuilder))
{
try
{
WSSecurityTokenSerializer keyInfoSerializer = new WSSecurityTokenSerializer();
keyInfoSerializer.WriteToken(writer, token);
Console.WriteLine("Saml Token Successfully Created");
}
catch (Exception)
{
Console.WriteLine("Failed to seralize token");
}
}
return samlBuilder.ToString();
}

How to do it...

To create a SamlProvider service, perform the following steps:

  1. 1. Create a Visual C# Console Application project, and add reference to the System.IdentityModel and System.ServiceModel assemblies. Include the Saml11Helper class in the project.

  2. 2. Create a SecurityTokenAuthorizationPolicy class to define a custom authorization policy by implementing the IAuthorizationPolicy (System.IdentityModel.Policy) interface. Define a constructor that accepts an instance of the WindowsClaimSet object:

    public class SecurityTokenAuthorizationPolicy : IAuthorizationPolicy
    {
    WindowsClaimSet claims;
    public SecurityTokenAuthorizationPolicy(WindowsClaimSet claims)
    {
    this.claims = claims;
    }
    }
    
  3. 3. Provide an implementation of the Evaluate method:

    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
    evaluationContext.AddClaimSet(this, claims);
    evaluationContext.RecordExpirationTime (DateTime.Now.AddHours(10));
    return true;
    }
    

    Note

    The WindowsClaimSet instance is added to evaluationContext and an expiration policy is set to expire in 10 hours.

  4. 4. Create a ClaimsTokenAuthenticator class to validate the incoming credentials and create a WindowsClaimSet instance using the WindowsIdentity class. The class inherits from WindowsUserNameSecurityTokenAuthenticator (System.IdentityModel.Selectors) and implements the ValidateUserNamePasswordCore method:

    public class ClaimsTokenAuthenticator : WindowsUserNameSecurityTokenAuthenticator
    {
    protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateUserNamePasswordCore(string userName, string password)
    {
    if (IsAuthenticated(userName, password))
    {
    string name = userName.Split('\\')[1];
    List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
    WindowsClaimSet claimSet = new WindowsClaimSet(new WindowsIdentity(name), true);
    policies.Add(new SecurityTokenAuthorizationPolicy(claimSet));
    return policies.AsReadOnly();
    }
    return null;
    }
    private bool IsAuthenticated(string userName, string password)
    {
    //TODO: Call the provider to validate the credentials
    return true;
    }
    }
    

    The IsAuthenticated method can be used to call the identity provider (Active Directory/Forms database) and validate the credentials. For the purpose of our recipe, we will assume that the incoming credentials are valid.

    Note

    The includeGroups parameter should be set to true while creating the WindowsClaimSet instance to include the group claims in the output that can be used for the purpose of authorization.

  5. 5. Create a ClaimsTokenManager class by implementing ServiceCrendentialsSecurityTokenManager (System.ServiceModel.Security). The class implements the abstract method—CreateSecurityTokenAuthenticator to return a ClaimsTokenAuthenticator object:

    public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
    {
    if (tokenRequirement.TokenType == SecurityTokenTypes.UserName)
    {
    outOfBandTokenResolver = null;
    return new ClaimsTokenAuthenticator();
    }
    else
    {
    return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
    }
    }
    
  6. 6. We will also create a custom ServiceCredentials implementation that returns the ClaimsTokenManager object in the overridden method—CreateSecurityTokenManager:

    public class ClaimsProviderServiceCredentials : ServiceCredentials
    {
    public ClaimsProviderServiceCredentials()
    : base()
    {
    }
    protected override ServiceCredentials CloneCore()
    {
    return new ClaimsProviderServiceCredentials();
    }
    public override SecurityTokenManager CreateSecurityTokenManager()
    {
    return new ClaimsTokenManager(this);
    }
    }
    
  7. 7. Create SamlProviderService that retrieves ClaimSet from the service's AuthorizationContext and creates SamlSecurityToken using the Saml11Helper class. In this recipe, the serialized token is returned as an XML string:

    public class ClaimsProviderService : IClaimsProviderService
    {
    public string GetSaml11Token()
    {
    var claimSets = new List<ClaimSet>(ServiceSecurityContext. Current.AuthorizationContext.ClaimSets);
    ClaimSet claimSet = claimSets.Find((Predicate<ClaimSet>)delegate(ClaimSet target)
    {
    WindowsClaimSet defaultClaimSet = target.Issuer as WindowsClaimSet;
    return defaultClaimSet != null;
    });
    var accessControlClaims = claimSet.FindClaims(ClaimTypes.Sid, Rights.PossessProperty);
    SamlAssertion assertion = Saml11Helper.CreateSamlAssertionFromUserNameClaims (accessControlClaims);
    SamlSecurityToken token = new SamlSecurityToken(assertion);
    return Saml11Helper.SerializeSamlToken(token);
    }
    }
    

How it works...

The client creates an instance of the ClaimsProviderService proxy and sets the username and password properties for the ClientCrendentials object:

static void Main(string[] args)
{
string userName = WindowsIdentity.GetCurrent().Name;
Console.WriteLine("Enter your password");
string password = GetPasswordFromConsole();
ClaimsProviderServiceClient client = new ClaimsProviderServiceClient();
client.ClientCredentials.UserName.UserName = userName;
client.ClientCredentials.UserName.Password = password;
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.PeerOrChainTrust;
Console.WriteLine(client.GetSaml11Token());
Console.ReadLine();
}

When the service operation is invoked, the supplied username and password is retrieved by TokenAuthenticator, which then creates a WindowsClaimSet object that gets assigned to the authorization policy. Assigned ClaimSet is retrieved back in the service using AuthorizationContext, and the group-level permissions assigned to the user are used to create the claims for SamlSecurityToken.

There's more...

In this recipe, the token is returned as an XML string. Realistically, ClaimsProviderService would participate in a federation scenario where it issues the token to a Security Token Service in a different realm using the WS-Trust protocol specification. This is explained further, later in the chapter.

See also

The complete source code for the application is available in the \Chapter 1\Recipe 3\ folder.

 

Implementing federated security using a Security Token Service


In a claims-based identity scenario, tokens are issued by an Identity Provider (IP) and the user can access resources from a Service Provider or Relying Party (RP) using such claims. The following diagram illustrates the process flow:

However, in the world of claims, it is possible that an RP doesn't trust the IP if they are in discrete security domains. This recipe shows how federation can be used to build a Security Token Service for the IP (IP-STS) and the RP (RP-STS) to create a realm of trust across the security boundaries.

Getting ready

Windows Communication Foundation (WCF) exposes the WSFederationHttpBinding class to support federation (WS-Federation). We will use this binding in our recipe solution to create a federated STS. The documentation provided at http://msdn.microsoft.com/en-us/library/aa347982.aspx will help you learn more about this binding configuration.

How to do it...

To create an STS, perform the following steps:

  1. 1. Add reference to the System.ServiceModel.Channels namespace.

  2. 2. Create an ISecurityTokenService service contract and define an operation contract that accepts the Message request ( System.ServiceModel.Channels) and returns a Message response with the claims assigned by the issuer:

    [ServiceContract(Name = "SecurityTokenService", Namespace = "http://RelyingParty/v1")]
    public interface ISecurityTokenService
    {
    [OperationContract]
    Message ProcessRequestSecurityToken(Message message);
    }
    
  3. 3. Specify the WS-Addressing action and the SOAP action for the reply message on the OperationContract attribute:

    [OperationContract(Action = "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue",
    ReplyAction = "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue")]
    

    Note

    The Action and ReplyAction properties must conform to the WS-Trust specification.

  4. 4. Create an implementation of ISecurityTokenService for the IP. In the implemented IdentityProviderSecurityTokenService method, create an instance of RequestSecurityToken using the request message header:

    RequestSecurityToken rst = RequestSecurityToken.CreateFrom(message.GetReaderAtBodyContents());
    

    The RequestSecurityToken class should comply with OASIS web security WS-Trust standard specification. An equivalent XML representation will look like the following code:

    <RequestSecurityToken>
    <RequestType>
    http://schemas.xmlsoap.org/ws/2005/02/trust/Issue
    </RequestType>
    <AppliesTo>
    <EndpointReference>
    <Address> http://localhost:8080/SecurityTokenService/IdentityProvider </Address>
    </EndpointReference>
    </AppliesTo>
    <TokenType>
    http://docs.oasis-open.org/wss/oasis-wss-saml-token- profile-1.1#SAMLV1.1
    </TokenType>
    </RequestSecurityToken>
    
  5. 5. Create a proof token using the RequestSecurityToken key retrieved from the RequestorEntropy property and use the proof token, issuer token, and the claims to create a SamlSecurityToken object with an encrypted proof key to be held by the subject of the SAML security token. Build a RequestSecurityResponse instance using the SamlSecurityToken object:

    BinarySecretSecurityToken proofToken = new BinarySecretSecurityToken(key);
    SamlSecurityToken samlToken = Saml11Helper.CreateSamlSecurityToken(issuer, proofToken, IssuerToken, ProofKeyEncryptionToken, samlConditions, samlAttributes);
    RequestSecurityTokenResponse rstr = GetRequestSecurityTokenResponse(rst, keySize, proofToken, samlToken, senderEntropy, stsEntropy);
    

    Note

    senderEntropy is the RequestorEntropy key and stsEntropy is an alternate random key.

  6. 6. Create a response message using the RequestSecurityResponse instance and message header action set to the WS-Trust reply action URI:

    Message responseMessage = Message.CreateMessage(message.Version, "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue", rstr);
    
  7. 7. Ensure that the response message relates to the request message:

    responseMessage.Headers.RelatesTo = message.Headers.MessageId;
    
  8. 8. Set the service credential certificate validation mode to PeerOrChainTrust:

    serviceHost.Credentials.IssuedTokenAuthentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;
    
  9. 9. In the service model behavior configuration, set the appropriate certificate reference under the serviceCredentials element:

    <serviceCertificate storeLocation ="LocalMachine"
    storeName="My"
    x509FindType="FindBySubjectName"
    findValue="IdentityProviderSTS" />
    

    Note

    The binding element should be wsHttpBinding. Also, make sure that a mex endpoint is exposed for the purpose of metadata discovery.

  10. 10. Repeat steps 4 to 8 to create an implementation of ISecurityTokenService for the RP. In the implemented method—RelyingPartySecurityTokenService, verify that the issuer is the IP STS:

    List<ClaimSet> claimSets = new List<ClaimSet>(OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets);
    ClaimSet issuer = claimSets.Find((Predicate<ClaimSet>)delegate(ClaimSet target)
    {
    X509CertificateClaimSet issuerClaimSet = target.Issuer as X509CertificateClaimSet;
    return issuerClaimSet != null && issuerClaimSet.X509Certificate.Subject == "CN=IdentityProviderSTS";
    });
    

    In a more realistic scenario, the retrieved claim sets will be compared for matched thumbprints; however, for our recipe, we will settle for the certificate subject comparison with the IP. Notice that ClaimSet is retrieved from the service's AuthorizationContext. Also, copy over the identity claims retrieved from the IP realm to create an instance of SamlSecurityToken for the response message.

  11. 11. In the service model behavior configuration, set the appropriate certificate reference under the serviceCredentials element:

    <serviceCertificate storeLocation ="LocalMachine"
    storeName="My"
    x509FindType="FindBySubjectName"
    findValue="RelyingPartySTS" />
    

    Note

    The binding element should be wsFederationHttpBinding. The binding configuration should have message security mode set to Message and the issuer/issuerMetadata address pointing to the endpoint/mex endpoint address of the IP. A mex endpoint should also be exposed in the RP service configuration for the purpose of metadata discovery.

  12. 12. In the client configuration, specify the endpoint identity certificate:

    <client>
    <endpoint name="" address="http://localhost:8080/RelyingParty/Service" binding="wsFederationHttpBinding" bindingConfiguration="FederationBinding" behaviorConfiguration="RelyingPartyServiceBehavior" contract="IResource">
    <identity>
    <certificateReference storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="RelyingPartyService"/>
    </identity>
    </endpoint>
    </client>
    

How it works...

To allow the users of the IP realm to access resources from the RP, a brokered trust is established using an STS on either side of the realm. In our recipe, the trust is established by sharing a common contract between the IP-STS and RP-STS. The RP expects that the user presents it with the claims to access the resources that are issued by the RP-STS. On the other hand, the RP-STS expects the user to present claims issued by the IP-STS. The successful handshake is achieved by verifying the issuer at each step. The following diagram illustrates this scenario:

The RP service can validate the client request using an implementation of ServiceAuthorizationManager and validating the claims in the CheckAccess method:

public class FedAuthorizationManager : ServiceAuthorizationManager
{
public override bool CheckAccess(OperationContext operationContext)
{
}
}

There's more...

A brief overview of the concept of federation is provided in the MSDN documentation at http://msdn.microsoft.com/en-us/library/ms730908.aspx. This recipe references the concepts mentioned in the article. A complete solution of the federation scenario sample can be downloaded from http://msdn.microsoft.com/en-us/library/aa355045.aspx.

Passive federation

Web browsers act as the passive requestors and there is no direct way of controlling the behavior. The WS-Federation Passive Requestor Profile provides a set of guidelines that can be used to make web applications provide identity services. Details of the guidelines can be found in the MSDN article at http://msdn.microsoft.com/en-us/library/bb608217.aspx.

Single realm STS

If the trust boundaries are not discrete, a single realm STS could be used, where both the IP and the RP trust the STS. The following diagram illustrates this scenario:

In a single realm STS, the token service creates a token after authenticating the client credentials against an IP. The RP ensures that the issuer in the token is the STS and verifies the claims before accepting the client request.

 

Implementing Single Sign-On using claims


In a federation scenario, claims-based identity providers complying with the WS-Trust/WS-Federation security specification can act on behalf of the users to authenticate against third-party service providers that have a trust relationship established with the IP via some form of metadata exchange. This reduces the burden on the user to log in multiple times and facilitates a seamless Single Sign-On experience. This recipe shows how claims-based security can be used to create an SSO experience within and across the security boundaries easily.

Note

In the world of federation, web SSO is often described as passive, because the token processing must be performed within the limitations of the HTTP protocol, using GET, POST, and so on.

How to do it...

To create a Single Sign-On experience with the RP web application, perform the following steps:

  1. 1. In the requestor web page, create a form body with the SAML token, and use JavaScript to auto-post the form to the RP SSO URL:

    HTTP/1.1 200 OK ...
    <html xmlns="https://www.w3.org/1999/xhtml"> <head> <title>Working...</title> </head> <body> <form method="post" action="https://RelyingParty/SsoLogin.aspx">
    <p> <input type="hidden" name="wa" value="wsignin1.0" /> <input type="hidden" name="wctx" value="https://Resource.RelyingParty.com"
    />
    <input type="hidden" name="wresult" value="&lt;RequestSecurityTokenResponse&gt;...&lt;/RequestSecurityToken Response&gt;" />
    <button type="submit">POST</button> <!-- included for requestors that do not support javascript --> </p> </form> <script type="text/javascript"> setTimeout('document.forms[0].submit()', 0); </script> </body> </html>
    

    Note

    A POST button is also included for the browsers that do not support JavaScript.

  2. 2. Use the SSO page to retrieve the POST token and pass it to the STS for validation:

    POST https://RelyingParty/SsoLogin.aspx HTTP/1.1 &crarr; … &crarr; &crarr; wa=wsignin1.0 &crarr; wctx= https://Resource.RelyingParty.com wresult=<RequestSecurityTokenResponse>…</RequestSecurityTokenResponse>
    
  3. 3. In the STS, validate the token and return the user context.

  4. 4. In the RP application, generate the encrypted cookie using the context information and the token issuer, and save it.

  5. 5. You will be redirected to the requested page:

    HTTP/1.1 302 ... ~/home
    

How it works...

The wa parameter specifies the action to be performed. For sign-in, it should be set to wsignin1.0 as defined in the WS-Federation Passive Requestor Profile specification. The security token is returned using the wresult parameter. The value must be set to an XML string corresponding to the WS-Trust RequestSecurityTokenResponse element. The following code snippet shows the structure of a sample RequestSecurityTokenResponse XML string:

<trust:RequestSecurityTokenResponse
xmlns:trust="http://schemas.xmlsoap.org/ws/2005/02/trust">
<trust:Lifetime>
<wsu:Created>…</wsu:Created>
<wsu:Expires>…</wsu:Expires>
</trust:Lifetime>
<wsp:AppliesTo>
<EndpointReference>
<Address>
https://RelyingParty/SecurityTokenService
</Address>
</EndpointReference>
</wsp:AppliesTo>
<Trust:RequestedSecurityToken>
<saml:Assertion
MinorVersion="1"
AssertionID="_839f..." Issuer=" https://IdentityProvider/SecurityTokenService ">
<saml:Conditions
NotBefore="2009-10-22T14:40:07.978Z"
NotOnOrAfter="2009-10-22T00:40:07.978Z">
<saml:AudienceRestrictionCondition>
<saml:Audience>
https://RelyingParty/SecurityTokenService
</saml:Audience>
</saml:AudienceRestrictionCondition>
</saml:Conditions>
<saml:AttributeStatement>
<saml:Subject>
<saml:SubjectConfirmation>
<saml:ConfirmationMethod>
urn:oasis:names:tc:SAML:1.0:cm:bearer
</saml:ConfirmationMethod>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Attribute
AttributeName="name"
AttributeNamespace=
"http://.../ws/2005/05/identity/claims">
<saml:AttributeValue>
mary</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
<ds:Signature>
<ds:SignedInfo>
...
</ds:SignedInfo>
<ds:SignatureValue>
.....=
</ds:SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>
...
</X509Certificate>
</X509Data>
</KeyInfo>
</ds:Signature>
</saml:Assertion>
</trust:RequestedSecurityToken>
<trust:TokenType>
http://docs.oasis-open.org/wss/
oasis-wss-saml-token-profile-1.1#SAMLV1.1
</trust:TokenType>
<trust:RequestType>
http://schemas.xmlsoap.org/ws/2005/02/trust/Issue
</trust:RequestType>
<trust:KeyType>
http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey
</trust:KeyType>
</trust:RequestSecurityTokenResponse>

The RP generates an encrypted cookie using the token to prevent the subsequent requests to be redirected for token processing. The encrypted cookie will also store each RP address that participates in the sign-in scenario that is retrieved from the wctx parameter.

There's more...

You can have a look at the WS-Federation Passive Requestor Profile article at http://msdn.microsoft.com/en-us/library/bb608217.aspx for more information on web SSO.

 

Implementing Single Sign-Out in a trust realm


Single Sign-Out in a passive federation scenario could be tricky, as there could be several RPs participating in the trust realm sign-in process. This recipe shows how to sign out from each of the participating RPs with a single click using the WS-Federation commands.

How to do it...

To process a sign-out request, perform the following steps:

  1. 1. After clicking on the sign-out link, clear the federation cookie:

    System.Web.HttpContext.Current.Response.Cookies.Remove(stateKey);
    
  2. 2. Redirect the browser to the simulated issuer with a WS-Federation sign-out parameter as the action:

    https://RelyingParty/SsoLogout.aspx?wa=wsignout1.0&wreply=...
    

    Note

    The WS-Federation command— wa=wsignout1.0 is used to sign out from the issuer.

  3. 3. Retrieve the list of RPs from the cookie and send the sign-out clean-up command to each of them:

    https://RelyingParty1/SsoLogout.aspx?wa=wsignoutcleanup1.0, 
    https://RelyingParty2/SsoLogout.aspx?wa= wsignoutcleanup1.0, 
    https://RelyingParty3/SsoLogout.aspx?wa= wsignoutcleanup1.0
    

This allows all the relying parties to perform the sign-out operation.

How it works...

The wsignout1.0 and wsignoutcleanup1.0 actions defined in the wa GET parameter are well understood by relying parties adhering to the WS-Federation Passive Requestor Profile. These actions allow a sign-out operation from all the RPs in the realm.

There's more...

The Windows Identity Foundation runtime provides an HTTP module named WSFederationAuthenticationModule that provides out of the box support for the WS-Federation Passive Requestor Profile. We will explore this further in Chapter 3, Advanced Programming with Windows Identity Foundation.

 

Configuring certificates for the claims-based applications


Certificates are the crucial elements in the security of claims-based applications. They are used for signing and encrypting tokens that are transmitted across the security boundaries, safeguarding the communication from security threats such as man-in-the-middle attacks and eavesdropping.

This recipe shows the concepts of deploying certificates and retrieving them to create the signing credentials and the proof tokens that will be used throughout the course of this book.

How to do it...

To configure the certificates for claims-based applications, perform the following steps:

  1. 1. Open Visual Studio command prompt in Administrator Mode and run the makecert command:

    makecert -r -pe -n "CN= SamlTokenSigningCertificate" -b 01/01/2010 -e
    01/01/2012 -sky exchange -ss my
    
    

    A self-signed certificate with the SamlTokenSigningCertificate subject is generated and stored in the My store. The private key is marked exportable.

  2. 2. Launch the Management Console window by entering mmc in Windows Run and click on Add/Remove Snap-in under the File menu. Choose the Certificates snap-in and click on Add, as shown in the following screenshot:

  3. 3. Choose My Account from the prompt, and click on Finish. Click on OK to return to the Management Console window.

  4. 4. Expand the Personal folder, and you will find the certificate deployed, as shown in the following screenshot:

    • The Certificates snap-in can be used further to copy certificates to the other locations, to export and set permissions.

    Note

    It is a good idea to save this console configuration along with the local machine certificates snap-in. It will come handy for future operations.

  5. 5. Create an X509CertificateHelper class and add a static method—GetValidCertificateFromStore that accepts the subject name, store location, and the valid time as parameters, and returns the X509 certificate from the store:

    public static X509Certificate2 GetValidCertificateFromStore(StoreLocation location, DateTime timeValid, string subjectDistinguishedName)
    {
    X509Store store = new X509Store(location);
    try
    {
    store.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection validCertificates = store.Certificates.Find(X509FindType.FindByTimeValid, timeValid, false);
    X509Certificate2Collection signingCertificate = validCertificates.Find(X509FindType.FindBySubjectDistinguishedName, subjectDistinguishedName, false);
    if (signingCertificate.Count == 0)
    return null;
    return signingCertificate[0];
    }
    finally
    {
    store.Close();
    }
    }
    

How it works...

A collection of the certificates that are valid for the specified date is retrieved and a lookup is performed using the unique subject. The method shown here makes a very target-specific search. There could be overloaded methods that are more generic in nature. An example would be to look for matching (contains string) subjects. The X509FindType.FindBySubjectName search criteria could be used for such purpose. The retrieved certificate will be used to create a digital signature for the token (discussed in the Designing claims-based tokens using Security Assertion Markup Language recipe earlier in this chapter).

There's more...

You can have a look at the Cryptographic Tasks article at http://msdn.microsoft.com/en-us/library/7yx4d854.aspx to learn more about the cryptographic operations that can be performed using Microsoft CryptoAPI.

Proof token

A proof token is used by the requestor to authenticate, in order to get GenericXmlSecurityToken from the issuer. A good overview of the proof tokens is provided by Vittorio Bertocci from MSFT in his blog at http://blogs.msdn.com/b/vbertocci/archive/2008/01/02/on-prooftokens.aspx.

See also

The complete source code for the application is available under the \Chapter 1\Recipe 7\ folder.

About the Author

  • Sandeep Chanda

    Sandeep Chanda is the Director of Solutions at Neudesic, a Microsoft National Systems Integrator and Gold Certified Partner. He has been working on several Microsoft technologies (including but not limited to .NET, Azure, BizTalk, SharePoint, and Dynamics CRM) for the past ten years, building large-scale enterprise applications spanning multiple industries. He is a technology enthusiast and speaks at various corporate events and public webinars. He has authored several articles on Microsoft Dynamics CRM 4.0 in DevX, and is the author of Microsoft Windows Identity Foundation Cookbook, Packt Publishing and Beginning ASP.NET 4.5 Databases, Apress. Recently, he has been involved in evangelizing aspects of Application Lifecycle Management (ALM) and developer collaboration using Team Foundation Server, and has been the speaker on these subjects at the Great Indian Developer Summit since 2012. He holds an M.S. degree in Software Systems from BITS, Pilani, and his areas of interest include service-oriented computing, cross-platform mobility, pervasive computing, haptic devices, and cloud computing. He is also a blogger for the DevX Issues column at DevX (http://www.devx.com/blog/dev_issues).

    Browse publications by this author