Zulfiqar's weblog

Architecture, security & random .Net

Archive for the ‘WF4’ Category

WF Security Pack Update

Posted by zamd on March 13, 2013

Quite a few folks have asked me about updating WF Security Pack to .NET 4.5 as WIF is now integrated into .NET 4.5.

Today I manage to spare sometime to upgrade the WFSP to .NET 4.5/WIF 4.5.  I have also pushed the updated source code to github which you can pull down from https://github.com/zamd/wfsp/

Please note github version of the codebase is different from codeplex, which was refactored by a WF team member. The github version of the source code came straight from laptop. I intend to create a Nuget package and potentially a Visual Studio Extension as well. Stay tuned…

Posted in WF4.5, WFSP | Leave a Comment »

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.

Posted in WF4, WFSP | 5 Comments »

Integrating WIF, WF 4.0 & AppFabric: Claims-Based-Delegation

Posted by zamd on June 3, 2010

Extending upon my last post, where I have talked about basic integration, this post will go into the details of claims-based-delegation in WF 4.0 & AppFabric.

Again I’ll be using activities from the Workflow Security Pack. Let’s start with a diagram which captures the main components of solution and their interactions:

image 

  1. Unauthenticated user browse to web application protected by WIF modules.
  2. WIF redirects user to Passive STS for authentication
  3. User authenticates @ passive STS and is redirected back to the ASP.net app along with the Issued Token. WIF modules processes this token and upon successful validation of the token, user is logged into the application. I have configured SaveBootstrapTokens on this app, so the raw incoming token is preserved as part of IClaimsIdentity.
  4. Users click the “Call Service” link to invoke following client workflow. GetBootstrapToken activity reads the bootstrap token and enlist it with the SecurityTokenHandle (specified on the InitializeActAsToken activity) as an ActAs token.image
  5. InitializeSamlSecurityToken activity issues a request (RST) to acquire a SAML token from the STS using the ActAs token enlisted in step 4. InitializeSamlSecurityToken is able to see the ActAs token (enlisted by InitializeActAsToken activity)  because both of these activities share the same SecurityTokenHandle. At this stage, Web App is authenticated by STS using windows authentication while ActAs token is a Saml token (acquired using forms authentication in step 3). The final Saml token will contain claims for both immediate (web app) and original caller (authenticated user).
  6. TokenFlowScope activity along with the workflowCredentials behaviour (configured on the endpoint used by the Echo activity) enhances the WCF security pipeline to attach the Saml token (acquired in step 5) with the outgoing message. As part of it’s execution, TokenFlowScope will detect that Echo activity requires a Saml token, it will then check it’s enlisted tokens to see if it can satisfy the token requirements of the Echo activity. In this example, there is already a Saml token enlisted with the handle so TokenFlowScope simply attaches that token with the outgoing message.

I have attached complete solution with this post. I tried to keep the solution self-contained by using file-based certificates and other shortcuts so hopefully you should be able to get it working by just hitting Ctrl-F5 :)

Feel free to download and experiment and let me know your thoughts…

Posted in WF4, WFSP, WIF | 10 Comments »

Integrating WIF with WF 4.0 and AppFabric

Posted by zamd on May 18, 2010

WIF is framework to claim-enable ASP.net applications and WCF services. WF 4.0 introduced a new paradigm for developing services (known as Workflow Services), whose implementation is based on workflow. Windows Server AppFabric provides the hosting, management & monitoring capabilities for services with a primary focus on workflow services.

WIF integration with Workflow services can be seen at couple of different scopes.

1. Claims-Enabled Workflow Service

As workflow services are standard WCF services, WIF can easily be enabled at the WCF layer using the standard configuration based approach documented in MSDN. This would claims-enable your workflow services and you can use various WIF’s extensions (code-based) for claims-transformation (ClaimsAuthenticationManager) and claims-based authorization (ClaimsAuthorizationManager).

2. Workflow Services calling other Claims-Enabled Services

WF 4.0 provides messaging activities to call other services from workflows. In most cases, Claims-Enabled services require a token from an STS. In a non-WF world, you can either use wsFederationHttpBinding or the new fine grained WIF API (WSTrustChannelFactory) to do this (you can use IssuedSecurityTokenProvider directly). The wsFederationHttpBinding approach kind of works (transparently) in Workflow services world as well but could be quite expensive in terms of performance. See my post on messaging activities for additional details. The wsFederationHttpBinding approach is also not suitable for scenarios, where you need fine-grained control of issued tokens or you want to use issued token in long-running scenarios without re-acquiring them.

3. WIF in middle-tier Workflow Services

WIF enables claims-based-delegation using then ActAs/OnBehalfOf element of WS-Trust protocol. In code-based services, you can access the incoming token in the middle-tier service and then use this when acquiring a SAML token to call a backend service. With this model, the backend service can see all the identities involved in the call chain. Claims-based delegation is not easily possible in workflow services when using wsFederationHttpBinding.

1 & 2 be greatly enhanced by introducing custom activities which can decouple token acquisition from its use; much like activity counterpart of WIF’s WSTrustChannelFactory API.

saml

In above diagram InitializeSamlSecurityToken custom activity encapsulate the functionality of acquiring a token from a STS using the WS-Trust protocol. Internally it uses the standard correlated Request-Reply pair configured for WS-Trust contract. I’ll talk more about TokenFlowScope in a future post but here it enables the Ping activity to use the acquired token when calling a service which requires Saml token. I have attached complete solution with post (STS, Test Service & a Test Client)which also includes alpha drop of WFSP binaries as well. Feel free to download and experiment and let me know your thoughts.

Posted in WF4, WFSP, WIF | 9 Comments »

Messaging activities intricacies

Posted by zamd on April 26, 2010

WF 4 introduced messaging activities which provides a visual way of creating web services and their clients.  In VS 2010 when you do “Add Service Reference” (in a workflow project), the wizard automatically generates activities and config in contrast to imperative code and config (the legacy way J). This looks cool as you can simply drag & drop these activities on a workflow surface and use them to consume your web services.  But how does these activities lay themselves on top of WCF ChannelFactory/Channel API?

Send activity is a wrapper around WCF ChannelFactory/Channel API and there is a cache layer built into Send activity’s infrastructure as well. By default, this caching layer is only used in a safe caching mode, where Endpoint information is specified using the properties of Send activity and you are using one of the stock Bindings without any modifications. As soon as you load Binding information from the config (regardless if you have changed the binding or not) safe caching will be disabled.

Without caching, default WSHttpBinding is not suitable for workflow scenarios as it will negotiate credentials (which is a 2 legs handshake) & then establish a secure conversation session (another leg). But then this would be only be used for a single message and needs to be done for every message generated by the Send activity. In my simple example, I have following service which is using default wsHttpBinding and I used VS “Add Service Reference” to generate a client.

clip_image002

The wizard has generated following two activities and along with some default config (default wsHttpBinding)

clip_image004

I then used these activities to craft a basic client which looks like this:

clip_image006

With this simple arrangement my message flow looks this: For Operation1 calls, following 4 infrastructure messages are generated. Note these are request-reply message so each of them has reply message too.

http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue

http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue

 

http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT

 

http://tempuri.org/IService/Operation1

http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Cancel

By default, wsHttpBinding  is optimized for security and performance – so it establishes a secure conversation which has an upfront cost but applying security for subsequent messages is much cheaper. But unfortunately, in workflow world we only transmit one message as part of secure session, as the second call would use a brand new factory, and all of this will be done again.

Now you can argue here that your binding is still the same default wsHttpBinding binding, why messaging activities didn’t use channel factory caching in this case.  As binding information is now coming from the configuration file, messaging activities can’t safely determine that you are using the default binding hence caching is disabled.  If you know for sure that you binding is still secure for sharing (as in this case, it was the same default wsHttpBinding) you can enable UnsafeCaching which will then reuse the ChannelFactory for sending messages to the same endpoint. Caching API is exposed via SendMessageChannelCache class, which can be added as an extension into your Workflow Host.

class Program

{

    static void Main(string[] args)

    {

        var invoker = new WorkflowInvoker(new Workflow1());

 

        var cache = new SendMessageChannelCache { AllowUnsafeCaching = true, };

        invoker.Extensions.Add(

            delegate

            {

                return cache;

            }

            );

        invoker.Invoke();

        cache.Dispose();

    }

}

 

In above example, cache is added as an Instance level cache (notice I’m using Func<> delegate). Cache can be shared at different scopes; Host & AppDomain are the other two options.  With above modification you would get the expected behaviour:

Secure conversation session is established at the start and would be used to secure all subsequent messages to the same endpoint.

Remember, you are now getting sessions on the server side and you would have to explicit close those sessions otherwise they will stay hanging and will ultimately saturate your session throttles.

You can close the active sessions by disposing the cache. This will send the Cancel message to the sessions.

 

http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Cancel

Please note, this is just one example of optimizing the messaging when using workflow services activities.

Posted in WF4 | Tagged: | 1 Comment »

Introducing Workflow Security Pack

Posted by zamd on February 23, 2010

Have you already started serious development with WF 4 and found security limitations?

Have you struggled to implement authenticated messaging, claims-based security, role-based security and other security features in workflow solutions?

WF 4 is a highly extensible framework so most of these features can be built using the WF extensibility model, but wouldn’t it be nice to have all of these security features available in an easy to use activity library?

 

Here comes the Workflow Security Pack (WFSP) project… WFSP is a collection of activities and associated plumbing to enable key security scenarios in WF 4.  WFSP activities blend with the rest of the WF to bring end-to-end integrated security into workflow solutions. The following diagram shows the initial set of activities which are part of WFSP.

cid:image001.jpg@01CAB458.185E10A0 

Following are some of the scenarios enabled by WFSP:

1.      Authenticated messaging

a.      Enables the use of various credentials with Send activity

b.      Follows exactly the same model when using a Username token or a Saml token issued by an STS

2.      Role-based security

a.      Enables principal permission based authorization on the Receive activity

b.      Supports standard RoleProvider extensibility model

3.      Claims-based security

a.      Ability to acquire a SAML token using the WS-Trust protocol

b.      Ability to pass this token to a SAML secured service using WS-Security

4.      End-to-end Claim-based delegation

a.      Ability to use any token as an ActAs token

5.      Transparent handling of tokens in a long-running environment

a.      Enlisted tokens are preserved during persist and reload cycles

6.      Impersonation and Delegation support

a.      Ability to impersonate incoming Identity on Receive side

b.      Ability to impersonate a User identity on the Send side

c.      Ability to call a backend service from the Impersonated scope (Kerberos delegation)

7.      WCF OperationContext access in a thread-agnostic way

 

In future posts, I’ll take an in-depth look into each of activities above and various scenarios enabled by these activities. Stay tuned.

 

 

Posted in WF4, WFSP | 10 Comments »

Authenticated messaging in WF 4

Posted by zamd on January 19, 2010

Authenticated messaging is one limitation in WF 4 as currently there is no API for setting up credentials to be used with a Send activity. Having said that, ChannelFactory used by Send activity still picks up the behaviour configuration from the config file.

So you can potentially write a custom behaviour to supply additional credentials to the Send activity. Let’s see a simple clientCredentialsAdapter behaviour which will enable you to setup userName/Password in config file. It’s almost always a bad idea to keep unencrypted password in config files so it is recommended that you should use config encryption to encrypt the behaviour section.

<behavior name=credentialAdapter>

  <clientCredentials> 

    <serviceCertificate>

      <authentication certificateValidationMode=None/>

      <defaultCertificate findValue=f7ad5a9dcc35f21ffc691925515f48eb44f5e07a x509FindType=FindByThumbprint storeLocation=CurrentUser storeName=My/>

    </serviceCertificate>

  </clientCredentials>

 

  <clientCredentialsAdapter>

    <userName userName=configUser password=p@ssw0rd!/>

  </clientCredentialsAdapter>

</behavior>

At this point, you can configure this behaviour on an endpoint used by a Send activity. This change will enable Send activity to use this userName/Password for securing outgoing messages.

public class ClientCredentialsAdapterBehavior : IEndpointBehavior

{

    ClientCredentialsAdapterBehaviorElement configElement;

 

    public ClientCredentialsAdapterBehavior(ClientCredentialsAdapterBehaviorElement configElement)

    {

        this.configElement = configElement;

    }

 

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters){}

 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)

    {

        var clientCredentials = endpoint.Behaviors.Find<ClientCredentials>();

        Adapt(clientCredentials);

    }

 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }

 

    public void Validate(ServiceEndpoint endpoint){}

 

    void Adapt(ClientCredentials orignalCredentials)

    {

        orignalCredentials.UserName.UserName = configElement.UserName.UserName;

        orignalCredentials.UserName.Password = configElement.UserName.Password;

    }

}

So that was simpleJ What about a scenario where you have userName/Password as part of workflow state and you want to use that instead?

Well, in that case there is more work involved which I’ll discuss in next post.

Posted in WF4 | Leave a Comment »

PrincipalPermission Authorization in WF 4

Posted by zamd on January 12, 2010

In last post, I have shown you how to get hold of OperationContext when using messaging activities. Once you got hold of OperationContext, you can use it to perform many useful tasks and one of them is Authorization. Let’s start by defining a Scope activity to hook our IReceiveMessageCallback implementation. 

 

    [Designer(typeof(PrincipalPermissionScopeDesigner))]

    public class PrincipalPermissionScope : NativeActivity

    {

        public InArgument<string> PrincipalPermissionName { get; set; }

        public InArgument<string> PrincipalPermissionRole { get; set; }

 

        public Activity Body { get; set; }

 

        protected override void Execute(NativeActivityContext context)

        {

            var name = this.PrincipalPermissionName.Get(context);

            var role = this.PrincipalPermissionRole.Get(context);

 

            var principalPermission = new PrincipalPermission(name, role);

            context.Properties.Add(“AuthorizationManager”,

                new AuthorizationManager(principalPermission));

 

            context.ScheduleActivity(this.Body);

        }

            }

As part of Scope activity execution, I have added my ReceiveMessageCallback in execution properties collection. This enables our callback to be called for every message received by any activity inside the Scope. Once we have access to OperationContext (which is the only as the only parameter of the callback) we can use it to perform authorization.

 

        [DataContract]

        class AuthorizationManager : IReceiveMessageCallback

        {

            [DataMember]

            PrincipalPermission principalPermission;

 

            public AuthorizationManager(PrincipalPermission principalPermission)

            {

                this.principalPermission = principalPermission;

            }

 

            public void OnReceiveMessage(

                System.ServiceModel.OperationContext operationContext,

                ExecutionProperties activityExecutionProperties)

            {

                var currentPrincipal = Thread.CurrentPrincipal;

                var isPrincipalSet = false;

                var targetPrincipal = GetPrincipal(operationContext);

                try

                {

                    if (targetPrincipal != null)

                    {

                        Thread.CurrentPrincipal = targetPrincipal;

                        isPrincipalSet = true;

 

                        principalPermission.Demand();

                    }

 

                }

                catch (SecurityException)

                {

                    throw SecurityUtility.CreateAccessDeniedFaultException();

                }

                finally

                {

                    if (isPrincipalSet)

                        Thread.CurrentPrincipal = currentPrincipal;

 

                }

 

            }

And with a customer designer, this is how it look like

Posted in WF4 | 2 Comments »

Managing OperationContext in WF 4

Posted by zamd on December 13, 2009

Managing OperationContext in WF 4 using the ISendMessageCallback & IReceiveMessageCallback

WF 4 raised the level of abstraction for writing workflow services and their clients by defining Send & Receive messaging activities. These activities hides lot of WCF plumbing from you and as result, some useful components like OperationContext are also not available in the usual WCF way. For example,

Ø  When using Send activity, you never see the ChannelFactory/Channel so you can’t scope an OperationContext around them.

Ø  When using Receive activity, activities following the Receive might execute on a different thread (than the WCF dispatcher thread) in which case you again wouldn’t get OperationContext.

If you done any WCF programming, you would agree that OperationContext can be very useful on both Send/Receive side:

Ø  On the send side, you can use OperationContext for sending additional message headers as part of the outgoing message or you can use OperationContext to add additional message properties to the outgoing message.

Ø  On the receive side, you can use OperationContext to retrieve very useful information including but not limited to security information related to the incoming message.

So in short, access to OperationContext on Send/Receive side can be very useful and luckily WF 4 has enabled this using a callback mechanism based on IReceiveMessageCallback & ISendMessageCallback.

 

IReceiveMessageCallback(s) are invoked just after the message is received by a Receive activity. Similarly, ISendMessageCallback(s) are invoked just before the message is sent on wire.

To attach these callback(s) to Send & Receive activities, they must be available as execution properties when Send/Receive executes. Execution properties are WF mechanism to enable Thread Local Storage (TLS) in a thread agnostic way. A common method of adding execution properties to and activity is to create a parent scope activity and set the execution properties as part of parent execution. Here is an example.

public class OperationContextScope : NativeActivity

{

    public Activity Body { get; set; }

    protected override void CacheMetadata(NativeActivityMetadata metadata)

    {

        metadata.AddChild(this.Body);

    }

    protected override void Execute(NativeActivityContext context)

    {

        context.Properties.Add("MessageInspector", new SendMessageInspector());

        context.ScheduleActivity(this.Body);

    }

 

    [DataContract]

    class SendMessageInspector : ISendMessageCallback

    {

        public void OnSendMessage(OperationContext operationContext)

        {

            var h1 = MessageHeader.CreateHeader("yourName", "urn:personal", "zuahmed");

            operationContext.OutgoingMessageHeaders.Add(h1);

        }

    }

}

Once you defined a scope activity like above you can just wrap your actual Send/Receive inside this scope to activate your inspector.

WorkflowInvoker.Invoke(

    new OperationContextScope

    {

        Body =

        new Send { OperationName = "Ping", ServiceContractName = "IPingService", EndpointConfigurationName = "PingEpr" }

    }

    );

IReceiveMessageCallback and Receive activity is exactly the same and I leaving that as an exercise for the readers J

In this post, I have shown you a general purpose mechanism to interact with an OperationContext while using WF 4 messaging activities. In next few posts, I’ll use this mechanism to add some very useful security features to WF 4. Stay tuned…

Posted in WF4 | 1 Comment »

Durable Duplex Messaging in .Net 4 Beta2

Posted by zamd on October 28, 2009

Here I talked about couple of approaches to enable durable duplex messaging in .Net 3.5.

.NET 4 has added first class support for durable duplex messaging by extending Context Exchange Protocol to include a CallbackContext. So in addition to instanceId, a client application can send a callback context as part of the call.

Service, upon receiving the message, will start the long running work and when it needs to callback to client, it can simply use the address from the callback context.

From API perspective – a new property “ClientCallbackAddress” is added to ContextBindingElement. This property is also exposed on some higher level bindings like wsHttpContextBinding.

A new CallbackContextMessageProperty is also added to manipulate callback context from the application code.

  <bindings> 

    <wsHttpContextBinding>

      <binding name=noSec clientCallbackAddress=http://localhost:7080>

        <security mode=None/>

      </binding>

    </wsHttpContextBinding>

  </bindings>

Any messages sent using above binding will have a callback context attached to it. Please note callback context is only supported with SOAP based context exchange and that’s why clientCallbackAddress property is NOT exposed on basicHttpContextBinding as it uses HTTP cookies for context exchange.

var cf = new ChannelFactory<IRequestChannel>(new WSHttpContextBinding(“noSec”),

                                             new EndpointAddress(http://localhost:8975/&#8221;));

var ccmp = new CallbackContextMessageProperty(new Dictionary<string,string>());

 

var msg = Message.CreateMessage(MessageVersion.Default, “urn:foo”, “”);

msg.Properties.Add(CallbackContextMessageProperty.Name, ccmp);

cf.CreateChannel().Request(msg);

This will produce following SOAP envelop and you can see CallbackContext header is added in outgoing message.

<s:Envelope xmlns:s=http://www.w3.org/2003/05/soap-envelope xmlns:a=http://www.w3.org/2005/08/addressing>

  <s:Header>

    <a:Action s:mustUnderstand=1>urn:foo</a:Action>

    <a:MessageID>urn:uuid:c7c03178-fa84-400e-8673-ad1ed28f0f79</a:MessageID>

    <a:ReplyTo>

      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>

    </a:ReplyTo>

    <CallbackContext xmlns=http://schemas.microsoft.com/ws/2008/02/context>

      <CallbackEndpointReference>

        <a:Address>http://localhost:7080/</a:Address>

        <a:ReferenceParameters>

          <Context xmlns=http://schemas.microsoft.com/ws/2006/05/context/>

        </a:ReferenceParameters>

      </CallbackEndpointReference>

    </CallbackContext>

    <a:To s:mustUnderstand=1>http://localhost:8975/</a:To>

  </s:Header>

  <s:Body>

    <string xmlns=http://schemas.microsoft.com/2003/10/Serialization//>

  </s:Body>

</s:Envelope>

On the server side, you can pick up the CallBackContext from the Message Properties and use it for call-backs. So far I have shown kind of a manual way of dealing with callback context. Workflow services in .Net 4 along with correlation feature has really simplified all this and you never need to muck with CallbackContextMessageProperty etc.

In your client workflow, simply make sure you have an active correlation handle on your send activity and then use a binding capable of transporting callback context (e.g. wsHttpContextBinding mentioned earlier)

 

In your server side workflow, simply make sure that Receive and Send (used for callback) activities are correlated either using implicitly or explicit correlation and that’s it.

You don’t need to specify Endpoint Address on your Send activity and it will automatically pick it from CallbackContext.

Posted in WF4 | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.