In Enhance Your Workflows with the New Activity Packs, I introduced the ADO.NET and State Machine activity packs, which extend the built-in library of WF activities to fill some much needed gaps. Shortly after that article was written, Microsoft released a new set of activities to address the issues of security and identity within WF workflows. The WF Security Pack CTP 1—available on CodePlex at wf.codeplex.com—enables you to leverage the WCF Identity Model within your workflows with a simplicity that makes designing secure WCF services with workflows a very compelling option. In this article, I'll provide an overview of all the activities included in the pack, which tier you should use them in, and how they are designed to help you.
To get started using the activities from WF Security Pack CTP, download the MSI installer from CodePlex (wf.codeplex.com). Prior to installation, be sure you have Windows Identity Foundation installed. Once you run the installation, your Visual Studio 2010 toolbox (when viewed with a workflow open in the designer) will contain a new Security group with seven new activities, as Figure 1 shows.
You can build workflows that are clients of other WCF services (e.g., they use Send activities), and workflows can be built that define backend services themselves (e.g., leveraging Receive activities). In addition, workflows can implement services that also call other services, which are effectively both services and clients (e.g., they contain a mixture of Send and Receive activities). For simplicity, we refer to these as Client workflows, Middle Tier Service workflows, and Backend Service workflows, as Figure 2 shows.
In the following sections, I'll introduce the purpose of each of the activities in terms of the tier that they apply.
Backend Service Workflows
Let's start with the most obvious case first, the Backend Service (which is most likely what you think of when building a service). This service does not make any outgoing calls to other services. In this scenario, you are likely interested in authenticating the caller's identity and performing in-workflow authorization of the caller’s ability to perform some action. You might also need to impersonate the caller's Windows Identity to perform some action against a resource under that user (such as accessing the file system or a database). The three activities that are useful in this scenario, as Figure 2 shows, are the PrincipalPermissionScope, OperationContextScope, and ImpersonatingReceiveScope.
PrincipalPermissionScope. If you are accustomed to performing authorization of your callers using Windows or username and password credentials, then the functionality of PrincipalPermissionScope should already be familiar to you. When a message comes in to a Receive activity contained within its body (see Figure 3), it examines the authenticated identity and compares if the principal’s name matches the PrincipalPermissionName property (shown as Name on the design surface) or belongs to the group/role (shown as Role on the design surface) described by the PrincipalPermissionRole property. This check functions identically to how the PrincipalPermission attribute performs authorization for code-based WCF services. In Figure 3, we show that only members of the Super Users role may call the GetData method. Callers not in this role will receive an access denied exception. Beyond examining for a specific user or membership in a role, if you leave both the PrincipalPermissionName and PrincipalPermissionRole properties null, anonymous callers will be denied.
Services that utilize the PrincipalPermissionScope activity can authorize against Windows username and groups or authorize against ASP.NET membership users and Role Provider roles.
OperationContextScope. The OperationContextScope makes the OperationContext of the operation available, defined by the current Receive. Just as for code-based WCF services, this provides you with access to message headers, properties, and claims (e.g., name, role, or some other useful attribute such as e-mail) provided by the caller. If your workflow service needs to define specific logic based on the claims provided, you can use the current OperationContext to access the ClaimSets provided and then examine the specific claims within each. Figure 4 shows how to use the OperationContextScope to provide activities contained within the Body of the OperationContextScope access to the current OperationContext. In the figure, the If condition ensures that we have claims, and we use nested ForEach activities—one that loops over each ClaimSet and another that loops over each Claim. We would put whatever claim-specific logic we require within the body of the latter ForEach.
ImpersonatingReceiveScope. In the case that the identity provided maps to a Windows Identity, our Backend Service may want to impersonate this identity to access a resource such as the local file system or a SQL database secured with Window Integrated Security. All activities within the body of an ImpersonatingReceiveScope will execute under the impersonation context of this client-provided identity. Figure 5 shows how the GetData operation uses the identity of the caller to read a file from the file system using the identity of the caller. Any I/O performed within the Read in File activity will happen using the Windows Identity of the caller.
Whereas workflows for a Backend Service were concerned with acting on the identity of the caller, workflows in the Client are concerned with how to attach an identity to calls made out to other services via Send activities present within the Client workflow (recall Figure 2). The easiest identity to attach is the Windows Identity of the thread running the client workflows. Just as for WCF code services, if the binding (e.g., wsHttpBinding) supports these credentials, then the service invoked will automatically receive the Windows Identity of the client. Previously, it was much more difficult to attach a username and password token or a SAML token. Now with the use of TokenFlowScope, GetUserNameSecurityToken, and GetSamlSecurityToken, the process becomes very simple.
TokenFlowScope. The TokenFlowScope manages security tokens and passes them down through the Send activities via the outgoing OperationContext to the WCF channel layer, where they are added to the message by the WorkflowClientCredentials custom ClientCredentials behavior provided with the WF Security Activity Pack. The use of the TokenFlowScope becomes apparent in the context of either the GetUserNameSecurityToken or the GetSamlSecurityToken.
GetUserNameSecurityToken. If the service being called expects a username and password, you will want to use the GetUserNameSecurityToken to create the token that encapsulates those credentials. It’s as easy as adding a GetUserNameSecurityToken activity and specifying the values for the username and password. In order for that token to be sent with the outgoing call, both the GetUserNameSecurityToken and the Send activity must be added to the Body of the same TokenFlowScope activity. Figure 6 shows how we attach the user with name “Foo” and password “Bar” to the outgoing call to Ping (which is an activity generated by Add Service Reference that calls the Ping operation on the PingService). Note that while the example uses hardcoded strings, you can and should use workflow variables to pass these values.
GetSamlSecurityToken. If the service expects a SAML token, the client first needs to call out to a Security Token Service (STS) to acquire the token to present to the service, it can then call the service with the token attached. To acquire the SAML token, you use the GetSamlSecurityToken and configure it to use an endpoint you have defined in your client’s configuration. The implementation is very similar to the username and password case, as Figure 7 shows. The main difference is that GetSamlSecurityToken makes a service call first to the STS presenting the Client’s credentials to acquire the token. The token acquired by the GetSamlSecurityToken is then attached to the outgoing request (defined by the Ping activity) via the TokenFlowScope and related WorkflowClientCredentials behavior.
Middle-Tier Service Workflows
Services that sit in the middle tier have needs that are similar to the Client and the Backend Service. They need to authorize callers just as Backend Service workflows do, and as a result they will make use of PrincipalPermissionScope and OperationContextScope to do this. They may also need to access local resources under the caller’s identity, so they may use the ImpersonatingReceiveScope as well.
Middle-tier service workflows also make calls out to other services, and in doing so some form of identity on the outgoing calls may need to be included, using GetUserNameSecurityToken, GetSamlSecurityToken, and TokenFlowScope in the same way as Client workflows.
Due to their unique position in the middle between clients and other services, they may also need to delegate the identity presented by the client and use it in a call to another service. In the case of Windows Identity tokens that support the delegation level of impersonation, this can be accomplished simply by defining the middle-tier service operation within an ImpersonatingReceiveScope, where the call to the other service happens within the body of the ImpersonatingReceiveScope. However, if there is a need to delegate using SAML tokens, you need to make use of the GetBootStrapToken activity.
The GetBootStrapToken activity obtains the primary identity from the current OperationContext, which is made available from an OperationContextScope. This token can then be attached to the outgoing request of a Send activity by a TokenFlowScope. Figure 8 shows how these pieces fit together to forward the caller’s SAML token to the Ping operation of a remote service.
Try the Security Pack Today
The WF Security Pack CTP 1 provides a great deal of functionality for a community tech preview. This functionality was possible before, but implementing it was both laborious and technically challenging. With the WF Security Pack you are able to manage identity across your client, middle-tier, and backend workflow services. You can define authorization logic in-workflow, and work with tokens created from username and passwords as well as acquired from an STS. You also get the ability to easily impersonate and delegate the identity of a caller. Beyond security, the OperationContextScope activity gives you easy access for working with headers within your workflow definition. Go download the activity pack today and improve your workflow’s vocabulary!