Archive for the 'Identity' Category

How to make an Active/Passive STS using “Zermatt” Framework

Definition

“A Security Token Service (STS) is the plumbing that builds, signs, and issues security tokens using the interoperable protocols…”

“The “Zermatt” Framework makes it easy to build your own STS. It’s up to you to figure out how to implement the logic, or rules that drive it (often referred to as security policy).”

Active vs Passive

  Active STS Passive STS
Implementation WS-Trust protocol WS-Federation passive protocol
Built as WCF service ASP.NET web application
Hosting Self-hosted / IIS IIS

Steps to create our STS

  1. Implement a custom STS class
  2. Implement a custom STS configuration class
  3. Integrate the STS implementation with the hosting environment. (Here’s the differences between an active and passive STS implementation)

#1 - Implement a custom STS class

SecurityTokenService class handles the task of serializing and de-serializing the protocols. We can implement a custom STS by inheriting from this class and providing the following functionality:

  • Decide what claims to issue.
  • Decide what STS signing credentials the STS should use to sign the issued token.
  • Decide what relying party encrypting credentials the STS should use to encrypt the token before sending it (typically, the RP’s certificate information is shared out of band).
  • Decide what URL the response message goes to.

We need to override two methods from SecurityTokenService class:

GetScope

/// <summary>
/// This methods returns the configuration for the token issuance request. The configuration
/// is represented by the Scope class.
/// </summary>
/// <param name=”principal”>The caller’s principal</param>
/// <param name=”request”>The incoming request</param>
/// <returns></returns>
protected override Scope GetScope(IClaimsPrincipal principal, RequestSecurityToken request)
{
            // Validate the request’s AppliesTo
            ValidateAppliesTo(request.AppliesTo);

            // Create the scope using the request and the STS signing credentials.
            // The request.appliesTo is automatically copied to the scope instance.
            Scope scope = new Scope(request, _signingCreds);

            // Setting the encrypting credentials
            scope.EncryptingCredentials = _encryptingCreds;

            // Set the ReplyTo address for the WS-Federation passive protocol
            // (THIS IS NOT USED IN THE WS-TRUST ACTIVE CASE)
            scope.ReplyToAddress = scope.AppliesToAddress + “/Default.aspx”;

            return scope;
}

GetOutputSubjects

/// <summary>
/// This methods returns the claims to be included in the issued token.
/// </summary>
/// <param name=”scope”>The scope that was previously returned by GetScope method</param>
/// <param name=”principal”>The caller’s principal</param>
/// <param name=”request”>The incoming request</param>
/// <returns>The claims to be included in the issued token.</returns>
public override ClaimsIdentityCollection GetOutputSubjects(Scope scope, IClaimsPrincipal principal, RequestSecurityToken request)
{
            IClaimsIdentity callerIdentity = (IClaimsIdentity)principal.Identity;
            ClaimsIdentity outputIdentity = new ClaimsIdentity();
            ClaimsIdentityCollection returnValue = new ClaimsIdentityCollection();

            // Name claim
            outputIdentity.Claims.Add(new Claim(System.IdentityModel.Claims.ClaimTypes.Name, callerIdentity.Name));

            // Age Claim (custom claim)
            outputIdentity.Claims.Add(new Claim(“http://ZermattSamples/2008/05/AgeClaim”, “25″, ClaimValueTypes.Integer));

            returnValue.Add(outputIdentity);
            return returnValue;
}

#2 - Implement a custom STS configuration class

We can implement a custom STS configuration class by inheriting from SecurityTokenServiceConfiguration class and configuring the following properties:

  • The STS IssuerName. Configure this by passing the value to the base class constructor.
  • The STS implementation class type. Configure this to point to your custom STS implementation class.
public class MySecurityTokenServiceConfiguration : SecurityTokenServiceConfiguration
{
        public MySecurityTokenServiceConfiguration()
            : base(“HelloWorldSTS”)
        {
            SecurityTokenService = typeof(MySecurityTokenService);
        }
}

#3 - Integrate the STS implementation with the hosting environment

The integration step varies between active and passive STSes.

Active STS

Hosted in a console application
SecurityTokenServiceConfiguration config = new MySecurityTokenServiceConfiguration();

// Add the STS endoint information
config.TrustEndpoints.Add(new ServiceHostEndpointConfiguration(“http://localhost:6000/HelloWorldSTS”, new WSHttpBinding(), typeof(IWSTrustFeb2005SyncContract)));

// Create the WS-Trust service host with our STS configuration
using (WSTrustServiceHost host = new WSTrustServiceHost(
            config,
            new Uri(“http://localhost:6000/HelloWorldSTS”)))
{
                host.Open();
                Console.WriteLine(“Active STS started, press ENTER to stop …”);
                Console.ReadLine();
                host.Close();
}

Hosted in a IIS Web-Based Service

We need to host it in IIS and set up a .svc file in the web site. In this case, the .svc file needs to contain a “Factory” parameter that points to WSTrustServiceHostFactory class or a class inherited from it (if programmatic configuration of the WCF service host is needed), and a “Service” parameter that points to a custom STS configuration class.

> .svc file:

<%@ServiceHost language=C#
                Factory=”MyTypes.ActiveSTSFactory”
                Service=”MyTypes.MySecurityTokenServiceConfiguration”%>

> Custom STS factory:

// Creating a WSTrustServiceHostFactory instance that is capable of handling WSTrust protocol
public class ActiveSTSFactory : WSTrustServiceHostFactory
{
        public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
        {
            // Set the required parameters and return the serviceHost instance
            ServiceHostBase serviceHost = base.CreateServiceHost(constructorString, baseAddresses);

            //
            // Perform any necessary imperative configuration of the serviceHost instance here
            //

            // return the configured ServiceHost instance to WCF activation
            return serviceHost;
        }
}

Passive STS

Add the custom classes to the web application’s code behind file

To expose the STS functionality that you have implemented by using the WS-Federation passive protocol, we can use the “Zermatt” Framework FederatedPassiveTokenService control. (Note: make sure that you install the “Zermatt” Framework controls into the Visual Studio toolbox).

  1. Create an ASP.NET web page to handle the WS-Federation passive protocol sign-in requests and add the FederatedPassiveTokenService control.
  2. Set the Service attribute of the control to the type name of your STS configuration class.
  3. When deployed, make sure that the intended authentication is enabled for the passive STS Web application. The FederatedPassiveTokenService control requires that the caller be authenticated before the page is rendered. If the caller of the page is not authenticated, the control will not do anything.
<idfx:FederatedPassiveTokenService
            ID=”TokenService1″
            runat=”server”
            Service=”PassiveSTS.MySecurityTokenServiceConfiguration”>
</idfx:FederatedPassiveTokenService>

Introducing Microsoft code name Zermatt

Zermatt is a set of .NET Framework classes. It is a framework for implementing claims-based identity in your applications.

When you build claims-aware applications, the user presents an identity to your application as a set of claims. One claim could be the user’s name, another might be an e-mail address. The idea here is that an external identity system is configured to give your application everything it needs to know about the user with each request she makes, along with cryptographic assurance that the identity data you receive comes from a trusted source.

Object Model

Microsoft.IdentityModel namespace (included in Zermatt) extends the classical .NET model, based on the IPrincipal and IIdentity interfaces, by creating two specialized interfaces: IClaimsPrincipal and IClaimsIdentity:

image

IClaimsPrincipal

In the claims model multiple users or claims-based identities can be party to a single action. The IClaimsPrincipal interface defines the data and behavior of the identities associated with an execution context.

IClaimsPrincipal exposes a collection of identities, each of which implements IClaimsIdentity. In a common case, there will be a single issuer and a single token and the identities collection will only have one element. However, it’s possible in advanced scenarios for a relying party to ask (via policy) for more than one security token, potentially from different issuers.

IClaimsIdentity

This interface defines the basic functionality of a ClaimsIdentity object. It is recommended that this interface be used to access the methods and properties of ClaimsIdentity instead of using ClaimsIdentity directly.

All ClaimsIdentity objects implement the IClaimsIdentity interface.

IClaimsIdentity extends IIdentity and when you look at a user’s identity, you can get her name the same way you always have. In addition, you can look at IClaimsIdentity.Claims to get more information pertaining of the user’s identity, like her email address.

Claim

A Claim describes a property of a subject as observed by or attested to by an issuer. Examples include group or role membership, or age and geographic references. A claim can be evaluated to determine access rights to data and other secured resources during the process of authorization.

Claim.ClaimType is a string (typically a URI) that tells you what the value of the claim means. For example, a claim with a ClaimType of “http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname” represents a user’s first name.

Once you know the type of the claim, you can read its value from Claim.Value and with Claim.ValueType you can deserialize the value of the claim getting the format of the value.

ClaimsPrincipal

ClaimsPrincipal has the static Current property that is the IClaimsPrincipal associated with the current context.

Helpful links

· Microsoft Code Name Zermatt Setup Package

· Microsoft Code Name “Zermatt” white paper for developers by Keith Brown

· Vittorio Bertocci’s blog

· Kim Cameron’s Identity Blog

· Pedro Felix’s blog

 

In the following posts, I’ll try to show some samples about how to implement Zermatt in our applications and services.