Developing an Active STS – A Fun Project

Lately, I have been playing around with WIF to build an Active STS. I didn’t have access to necessary tools to build this on .NET 4.5 and I used .NET 4.0 to start with, this difference is significant because WIF is now part of .NET 4.5 and deeply embedded with .NET libraries, though conversion from this 4.0 to 4.5 shouldn’t be too hard.

Few weeks back I wrote about WIF here, its basics and the difference between .NET 4.0 and 4.5.

This article discussed following

  1. Implement Active STS with WIF & .NET 4.0
  2. Consuming Active STS in a MVC Application

Alright, lets talk about what is Active STS and what we can do with it.

Active STS – MSDN say’s – “A security token service (STS) is the service component that builds, signs, and issues security tokens according to the WS-Trust and WS-Federation protocols.”

The definition is really true, STS based authentication decouple the authentication logic from application, now application is responsible for authorizing the user based on Claims provided by STS and focus on application logic.

Federation where user is authenticated by one STS but they can have access to resources in other application if there is a trust relationship between the STS consumed by other application.

STS is build on top of WS-Trust specification, it describes issuing, renewing and validating of security tokens and broker the trust relationship between the participant in a secure message communication. Based on WS-Trust specification, Message is sent in the form of “Request for Security Token” and response is return in the form of “Request for Security Token Response”. For RST & RSTR, please refer the details here.

Building an Active STS

An Active-STS is consist of following

  1. A custom class derived from SecurityTokenService
  2. A WCF Service to host the SecurityTokenService
  3. Few Helper classes
  4. A MVC Client which will use the STS for authentication

SecurityTokenService

For Active-STS, most of the functionality is centered around the inherited class SecurityTokenService, it has two abstract method which needs to implemented in order to implement the functionality.

  1. GetScope
  2. This method checks if the requester is recognized by the STS and set Signin credential for RSTR.

  3. GetOutputClaimsIdentity
  4. This method gets called from Claims issuance pipeline when a client (implementation of IWSTrustChannelContract) request the token through Issue method (See the code – LoginService in StsClient). This method takes an incoming claims principal and return a new ClaimsIdentity with added claims.

These two method can be extended to plug-in multiple relying party client.

WCF Host and Configure

In order to host this service with WCF, an extension of WSTrustServiceHostFactory is required, which will create the service host to service the request. This is normal practices as like any other WCF Service host except, you are inheriting from WSTrustServiceHostFactory than ServiceHostFactory.

Couple of standard configuration required in WCF Service web.config file to make it working

  1. microsoft.identityModel section configuration in configSections and section configuration
  2. serviceBehaviour and bindings configuration in serviceModel.
  3. service certificate configuration, for this sample I am using localhost default certificate both for client and server.

I ran into issues while using the user name and password to validate the requesting client and seems only workaround to pass that is to create a derived implementation of UserNameSecurityTokenHandler, also before adding this configuration default TokenHandler – WindowsUserNameSecurityTokenHandler needs to removed.

  <securityTokenHandlers>
        <remove type="Microsoft.IdentityModel.Tokens.WindowsUserNameSecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add type="CPrakash.Security.ActiveSTS.RealmSTS.CustomUserNameSecurityTokenHandler, CPrakash.Security.ActiveSTS.RealmSTS" />
      </securityTokenHandlers>

RP Client

In my example, I have taken MVC as a client application but it can be any application eg. WebForms. In the example application, I removed the Membership method calls and added a LoginService which has custom code to call the STS from code with the supplied credential.

SessionSecurityToken sessionToken;
if (new StsClient.Services.LoginService().ValidateUser(model.UserName, model.Password, out sessionToken))
{
  ... // code after validation

If you look at the LoginService code, ValidateUser method takes supplied user name and password and pass it as credential to WSTrustChannelFactory.

SessionSecurityToken sessionToken;
var factory = new WSTrustChannelFactory(
                new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
                new EndpointAddress("https://localhost/ActiveSTS/SecurityTokenService.svc"));

factory.Credentials.SupportInteractive = false;
factory.Credentials.UserName.UserName = userId;
factory.Credentials.UserName.Password = password;

It builds the RST (request for secured token) and calls the issue method to request the secured token from service.

 var rst = new RequestSecurityToken
 {
     RequestType = RequestTypes.Issue,
     AppliesTo = new EndpointAddress("https://localhost/stsclient/"),
     KeyType = KeyTypes.Bearer,
     TokenType = Microsoft.IdentityModel.Tokens.SecurityTokenTypes.Saml11TokenProfile
 };

 var channel = factory.CreateChannel();
 var genericToken = channel.Issue(rst) as System.IdentityModel.Tokens.GenericXmlSecurityToken;

Once we have the token retrieved from service, we can create the session token out of it and it will be used to validate the user in subsequent request.

// parse token
var handlers = FederatedAuthentication.ServiceConfiguration.SecurityTokenHandlers;
var token = handlers.ReadToken(new XmlTextReader(new StringReader(genericToken.TokenXml.OuterXml)));
var identity = handlers.ValidateToken(token).First();

// create session token
sessionToken = new SessionSecurityToken(ClaimsPrincipal.CreateFromIdentity(identity));

Last piece to write the session token to client machine using cookie through WIF’s SessionAuthenticationModule‘s WriteSessionTokenToCookie method.

FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
Thread.CurrentPrincipal = sessionToken.ClaimsPrincipal;

Source code for this project is available at GitHub

Advertisements

About cprakash

A developer, passionate about .Net, Architecture and Security.
This entry was posted in WIF and tagged , , , . Bookmark the permalink.

2 Responses to Developing an Active STS – A Fun Project

  1. Pingback: Policy Based Authorization in Windows Identity Foundation (WIF) – Part I | cprakash

  2. Ali Salamin says:

    This is an amazing collection of knowledge and research. Thanks for this. One thing I had to get past was that the thumbprint (located in one of the web.configs) for the localhost x509 cert needs to be unique to your dev machine, as its obviously localhost (used this to find https://www.sslshopper.com/move-or-copy-an-ssl-certificate-from-a-windows-server-to-another-windows-server.html). It took me a good while to make sense of the errors I was seeing, hopefully this helps anyone else having the same issue.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s