How To Secure a Workflow Service in .NET 4

Edit: 7/5/11 - This sample has been updated and posted on MSDN Code Gallery - Windows Workflow Foundation (WF4) - Role Based Security for Workflow Services

The other day somebody asked me how they could secure a Workflow Service.  Specifically what they wanted to do was to allow one or two Windows Accounts to be able to access the service on the Intranet.  The other requirement was to simply list the allowed identities in the configuration file.  So I decided to tackle this project and put it on endpoint.tv

After investigating this here is the solution I came up with.  It starts with a WCF Workflow Service project.  (Note: This code would work with any WCF service, not just Workflow Services)

I then added an appKey value to the web.config with the list of allowed identities.

 <configuration>
  <appSettings>
    <add key="ServiceAllow" value="REDMOND\rojacobs,ROJACOBS-PC\Administrators"/>
  </appSettings>

Next I added a class that is derived from ServiceAuthorizationManager and implemented a role check for the identity to see if I had a match with my list.

 public class ServiceAuthz : ServiceAuthorizationManager
{
    private String[] serviceAllows;

    public ServiceAuthz()
    {
        String allowString = System.Configuration.ConfigurationManager.AppSettings["ServiceAllow"];
        serviceAllows = allowString.Split(',');
    }

    protected override bool CheckAccessCore(OperationContext operationContext)
    {
        var authCtx = operationContext.ServiceSecurityContext.AuthorizationContext;
        var identities = (List<System.Security.Principal.IIdentity>)(authCtx.Properties["Identities"]);

        foreach (var ident in identities)
        {
            var windowsIdent = ident as System.Security.Principal.WindowsIdentity;
            if (windowsIdent != null)
            {
                var windowsPrincipal = new System.Security.Principal.WindowsPrincipal(windowsIdent);
                foreach (String allow in serviceAllows)
                {
                    Boolean fInRole = windowsPrincipal.IsInRole(allow);
                    if (fInRole)
                        return true;
                }
            }
        }
        return false;
    }
}

By default, the Workflow Service doesn’t include any configuration so it will use basicHttpBinding which will not pass credentials.  So I simply added a protocol mapping section to web.config <system.serviceModel> section to cause it to use wsHttpBinding instead which will pass the Windows credentials by default.

 <protocolMapping>
  <add scheme ="http" binding="wsHttpBinding"/>
</protocolMapping>

And then we have to add the <serviceAuthorization> behavior.  Since I am using “tagless” services, I added this behavior to the rest of the behaviors which will apply to all “tagless” services in the solution.

 

 <serviceDebug includeExceptionDetailInFaults="false"/>
<serviceAuthorization serviceAuthorizationManagerType=
"WorkflowServiceWindowsAuthZ.ServiceAuthz, WorkflowServiceWindowsAuthZ" />

Now we’re all set to go.  You can test the service by using the RUNAS command to run the WCFTestClient from various user accounts to see the security take effect.

 

If you want to see this in action, be sure to check it out on endpoint.tv or just download the code and give it a go…