Zulfiqar's weblog

Architecture, security & random .Net

Using WIF with Workflow Services

Posted by zamd on July 4, 2010


Windows Identity Foundation integrates with WCF at the host level (ServiceHost) and then various WIF extensibility points are invoked at different stages of WCF message processing pipeline. In this post, I will show how WIF can be integrated with Workflow Services to enable common security scenarios. Additional rich security scenarios can also be enabled by using activities which are currently part of WF Security Pack project.

Basic Walkthrough

Create a new WCF Workflow Service Application by choosing File -> New Project:

clip_image002[4]

You would notice generated web.config is using simplified WCF 4.0 configuration. There are no explicit endpoint definitions rather service would get default endpoints at runtime.

  <system.serviceModel>

    <behaviors>

      <serviceBehaviors>

        <behavior>

          <!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>

          <serviceMetadata httpGetEnabled="true"/>

          <!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>

          <serviceDebug includeExceptionDetailInFaults="false"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

  </system.serviceModel>

A workflow service is a standard WCF service whose implementation is a workflow, so we should be able to integrate WIF using exactly the same techniques we know for code based WCF services.

Externalize the authentication to an STS

Inside Solution Explorer, right click on your workflow service project and select “Add STS Reference” option to launch FedUtil.exe.

On the Welcome Page, specify the Application URI and click next. On Security Token Service Page, select “Use an existing STS” option and specify the URL of the WS-Federation metadata document. For this example, I’m using AD FS 2.0 as the existing STS.

clip_image002[6]

Leave the default value “Disable certificate chain validation” on next page as I’m using self-signed certificates.

On the “Security token encryption”, choose “Enable encryption” option and specify the private key certificate of your service.

clip_image002[8]

Finish the wizard by choosing default values for the next two pages.

Wizard would generate all the configuration required to enable WIF on this Workflow Service. Lets briefly examine the generated configuration:

A new WIF related section is registered…

  <configSections>

    <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

  </configSections>

 

<microsoft.IdentityModel> configuration section is generated to externalize the authentication responsibility for this service to AD FS 2.0.

 

  <microsoft.identityModel>

    <service>

      <audienceUris>

        <add value="http://localhost:2534/Service1.xamlx" />

      </audienceUris>

      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

        <trustedIssuers>

          <add thumbprint="A1D6790E1CD8EAF2A23768E5789805E1AE58C9D6" name="http://ids.bccoss.com/adfs/services/trust" />

        </trustedIssuers>

      </issuerNameRegistry>

      <certificateValidation certificateValidationMode="None" />

    </service>

  </microsoft.identityModel>

 

A new Service Behaviour is added to the default behaviour collection, which configures WIF on this Workflow Service at the host level (WorkflowServiceHost in this case)

      <serviceBehaviors>

        <behavior>

          <federatedServiceHostConfiguration />

          <!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>

          <serviceMetadata httpGetEnabled="true" />

          <!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>

          <serviceDebug includeExceptionDetailInFaults="false" />

          <serviceCredentials>

            <!–Certificate added by FedUtil.  Subject=’CN=SampleService’, Issuer=’CN=Root Agency’.–>

            <serviceCertificate findValue="F042616A35AD30BE5069B468A67FF1233824F5F1" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" />

          </serviceCredentials>

        </behavior>

      </serviceBehaviors>

 

Default binding for the http scheme is changed to a wizard generated wsFederationHttpBinding. This enables all http based default endpoints to be configured to use this wsFederationHttpBinding.

    <protocolMapping>

      <add scheme="http" binding="ws2007FederationHttpBinding" />

    </protocolMapping>

A new default configuration of ws2007FederationHttpBinding is also generated by the wizard based on the selection made in Wizard. This generated binding has an issuerMetadata element specifying the metadata URL of AD FS 2.0 which would be used by the clients to fetch all the endpoints supported by AD FS 2.0

 

    <bindings>

      <ws2007FederationHttpBinding>

        <binding>

          <security mode="Message">

            <message>

              <issuerMetadata address="https://ids.bccoss.com/adfs/services/trust/mex" />

              <claimTypeRequirements>

                <!–Following are the claims offered by STS ‘http://ids.bccoss.com/adfs/services/trust&#8217;. Add or uncomment claims that you require by your application and then update the federation metadata of this application.–>

                <add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="true" />

                <add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" isOptional="true" />

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/claims/CommonName&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/claims/EmailAddress&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/claims/Group&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/claims/UPN&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/denyonlysid&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarysid&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarygroupsid&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid&quot; isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname&quot; isOptional="true" />–>

              </claimTypeRequirements>

            </message>

          </security>

        </binding>

      </ws2007FederationHttpBinding>

    </bindings>

 

That’s it. Your claim-aware Workflow Service is ready now.

At this stage, clients can generate the required configuration by simply using “Add Service Reference” wizard which would generate config  (endpoint addresses & bindings) for all the different endpoints supported by AD FS 2.0.

The main service endpoint would automatically be configured to acquire a token from AD FS 2.0 before calling the Workflow Service. 

As AD FS 2.0 supports multiple endpoints, generated wsFederationHttpBinding simply picks the first endpoint returned by the AD FS 2.0. This first endpoint choice might not be appropriate in all scenarios and you can easily change it in the client config file.

 

 

        <client>

            <endpoint address="http://localhost:2534/Service1.xamlx" binding="customBinding"

                bindingConfiguration="WS2007FederationHttpBinding_IService"

                contract="ServiceReference1.IService" name="WS2007FederationHttpBinding_IService">

                <identity>

                    <certificate encodedValue="AwAAAAEAAAAUAAAAhxjyEc1MCXsA5XXteMRn0iyQBuwgAAAAAQAAALgBAAAwggG0MIIBYqADAgE==" />

                </identity>

            </endpoint>

        </client>

 

 

Claims Transformation

ClaimsAuthenticationManager can be used to perform claims-transformation exactly in the same way as in code based service.

 

    public class SimpleClaimsAuthenticationManager:ClaimsAuthenticationManager

    {

        public override IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal)

        {

            // Claims transformation…

            return base.Authenticate(resourceName, incomingPrincipal);

        }

    }

 

This class can then be configured on the workflow service using following configuration. All other config except the highlighted line was automatically generated by FedUtil.exe.

 

 

    <service>

      <audienceUris>

        <add value="http://localhost:2534/Service1.xamlx" />

      </audienceUris>

      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

        <trustedIssuers>

          <add thumbprint="A1D6790E1CD8EAF2A23768E5789805E1AE58C9D6" name="http://ids.bccoss.com/adfs/services/trust" />

        </trustedIssuers>

      </issuerNameRegistry>

      <certificateValidation certificateValidationMode="None" />

      <claimsAuthenticationManager type="DeclarativeServiceLibrary1.SimpleClaimsAuthenticationManager"/>

    </service>

 

Claims based Authorization

 

Similarly Claim-Based-Authorization can be enforced at the host level using a ClaimsAuthorizationManager.

 

    public class SimpleClaimsAuthorizationManager:ClaimsAuthorizationManager

    {

        public override bool CheckAccess(AuthorizationContext context)

        {

            if (((IClaimsIdentity)context.Principal.Identity).Claims.Where(c=>

                c.ClaimType== ClaimTypes.Upn &&

                c.Value == "zam1d@bccoss.com").Count() ==0)

                return false;

 

            return true;

        }

    }

 

      <claimsAuthorizationManager type="DeclarativeServiceLibrary1.SimpleClaimsAuthorizationManager"/>

 

With above authorization manager plugged in, you can verify client is failing with “Access is denied” error.

 

clip_image002

 

Summary

Most of the WIF integration simply works with Workflow Services without any issues and is exactly the same as code based services. If you need to access claims inside your workflows or you want to implement more advance security scenarios such as

  • Fine grained control over token issuance and it’s usage
  • Claims-based delegation to other services

You can use WF Security Pack which provides additional activities and accompanying framework code to accomplish above mentioned security scenarios.

About these ads

5 Responses to “Using WIF with Workflow Services”

  1. Hi Zamd,

    How does this work with workflow persistence? I am finding that the credentials in Thread.CurrentPrincipal are wiped out before the workflow even starts when I add sqlWorkflowInstanceStore into the web.config. I can only guess that the workflow is re-hydrated from persistence before the first activity in the service workflow is even called. Any idea how I can get the authenticated credentials back into the workflow?

    I have a forum entry open at http://social.msdn.microsoft.com/Forums/en/wfprerelease/thread/7ff447ff-5a7b-40e3-ad9e-db8c9847bfbb.

    Cheers

  2. Hi Zulfiqar,

    That’s the ticket!

    I have added another entry to the forum with some explanation. Thanks for your help.

  3. […] The busiest day of the year was July 7th with 287 views. The most popular post that day was Using WIF with Workflow Services. […]

  4. Question. You don’t show setting up anything on your ADFS2.0 server, which has my a little confused, thought you needed to setup an RP in ADFS2. Second, doing exactly what you did, I get an error stating: The client certificate is not provided. Specify a client certificate in ClientCredentials.

    Can’t seem to get past it.

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

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: