Thinktecture.IdentityModel: WIF Support for WCF REST Services and OData

The latest drop of Thinktecture.IdentityModel includes plumbing and support for WIF, claims and tokens for WCF REST services and Data Services (aka OData).

Cibrax has an alternative implementation that uses the WCF Rest Starter Kit. His recent post reminded me that I should finally “document” that part of our library.

Features include:

  • generic plumbing for all WebServiceHost derived WCF services
  • support for SAML and SWT tokens
  • support for ClaimsAuthenticationManager and ClaimsAuthorizationManager
  • based solely on native WCF extensibility points (and WIF)

This post walks you through the setup of an OData / WCF DataServices endpoint with token authentication and claims support. This sample is also included in the codeplex download along a similar sample for plain WCF REST services.

Setting up the Data Service
To prove the point I have created a simple WCF Data Service that renders the claims of the current client as an OData set.

public class ClaimsData
{
    public IQueryable<ViewClaim> Claims
    {
        get { return GetClaims().AsQueryable(); }
    }
 
    private List<ViewClaim> GetClaims()
    {
        var claims = new List<ViewClaim>();
        var identity = Thread.CurrentPrincipal.Identity as IClaimsIdentity;
 
        int id = 0;
        identity.Claims.ToList().ForEach(claim =>
            {
                claims.Add(new ViewClaim
                {
                   Id = ++id,
                   ClaimType = claim.ClaimType,
                   Value = claim.Value,
                   Issuer = claim.Issuer
                });
            });
 
        return claims;
    }
}

…and hooked that up with a read only data service:

public class ClaimsDataService : DataService<ClaimsData>
{
    public static void InitializeService(IDataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule(“*”, EntitySetRights.AllRead);
    }
}

Enabling WIF
Before you enable WIF, you should generate your client proxies. Afterwards the service will only accept requests with an access token – and svcutil does not support that.

All the WIF magic is done in a special service authorization manager called the FederatedWebServiceAuthorizationManager. This code checks incoming calls to see if the Authorization HTTP header (or X-Authorization for environments where you are not allowed to set the authorization header) contains a token. This header must either start with SAML access_token= or WRAP access_token= (for SAML or SWT tokens respectively).

For SAML validation, the plumbing uses the normal WIF configuration. For SWT you can either pass in a SimpleWebTokenRequirement or the SwtIssuer, SwtAudience and SwtSigningKey app settings are checked.If the token can be successfully validated, ClaimsAuthenticationManager and ClaimsAuthorizationManager are invoked and the IClaimsPrincipal gets established.

The service authorization manager gets wired up by the FederatedWebServiceHostFactory:

public class FederatedWebServiceHostFactory : WebServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(
      Type serviceType, Uri[] baseAddresses)
    {
        var host = base.CreateServiceHost(serviceType, baseAddresses);
 
        host.Authorization.ServiceAuthorizationManager =
          new FederatedWebServiceAuthorizationManager();
        host.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
 
        return host;
    }
}

The last step is to set up the .svc file to use the service host factory (see the sample download).

Calling the Service
To call the service you need to somehow get a token. This is up to you. You can either use WSTrustChannelFactory (for the full CLR), WSTrustClient (Silverlight) or some other way to obtain a token. The sample also includes code to generate SWT tokens for testing – but the whole WRAP/SWT support will be subject of a separate post.

I created some extensions methods for the most common web clients (WebClient, HttpWebRequest, DataServiceContext) that allow easy setting of the token, e.g.:

public static void SetAccessToken(this DataServiceContext context,
  string token, string type, string headerName)
{
    context.SendingRequest += (s, e) =>
    {
        e.RequestHeaders[headerName] = GetHeader(token, type);
    };
}

Making a query against the Data Service could look like this:

static void CallService(string token, string type)
{
    var data = new ClaimsData(new Uri(https://server/odata.svc/&#8221;));
    data.SetAccessToken(token, type);
 
    data.Claims.ToList().ForEach(c =>
        Console.WriteLine(“{0}n {1}n ({2})n”, c.ClaimType, c.Value, c.Issuer));
}

HTH

This entry was posted in IdentityModel. Bookmark the permalink.

4 Responses to Thinktecture.IdentityModel: WIF Support for WCF REST Services and OData

  1. Alexey says:

    The FederatedWebServiceAuthorizationManager is not anymore found in Thinktecture.IdentityModel for .net 4.5. Is there an alternative?

    • Edgar says:

      I can not find FederatedWebServiceAuthorizationManager in Thinktecture.IdentityModel.
      Is it still available for developers? If not – are there alternatives in Thinktecture.IdentityModel to support WIF in WCF Data service?

      • I am not sure I still have that source code – maybe look for a Nuget called Thinktecture.IdentityModel.Web – and check the source code. sorry.

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 )

Facebook photo

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

Connecting to %s