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
- Implement a custom STS class
- Implement a custom STS configuration class
- 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).
- Create an ASP.NET web page to handle the WS-Federation passive protocol sign-in requests and add the FederatedPassiveTokenService control.
- Set the Service attribute of the control to the type name of your STS configuration class.
- 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>
[...] who has been working with Zermatt for a couple of weeks already, is posting a useful “straight to the point†how to implement active and passive STS’s using [...]
Introducing Zermatt…
Nice article by Sebastian Iacomuzzi : Intro to ZZermatt . Zermatt is a set of .NET Framework classes….