Zulfiqar's weblog

Architecture, security & random .Net

Archive for January, 2010

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 »

Using Request Headers for Metadata Address

Posted by zamd on January 14, 2010

WCF by default adds the listen address of the endpoints in the WSDL so in a scenario where the private address of the server is different from the public address you get incorrect endpoint address in WSDL.

For example if a service is listening on http://localhost:7721/ and you access its metadata using a virtual IP http://102.212.0.117/?wsdl, you get following:

 

Now this behavior might not work in certain scenarios and you want the metadata generation to dynamically pick the address from the request headers, similar to ASMX web services.

UseRequestHeadersForMetadataAddressBehavior enables exactly this. This opt-in behavior sets the address of endpoints dynamically, based on the request header.  

Like all other WCF behaviors, this behavior can be enabled either in the code or config.

sh.Description.Behaviors.Add(new UseRequestHeadersForMetadataAddressBehavior());

<system.serviceModel>

  <behaviors>

    <serviceBehaviors>

      <behavior>

        <useRequestHeadersForMetadataAddress/>

      </behavior>

    </serviceBehaviors>

  </behaviors>

</system.serviceModel>

As part of this behavior, you can also specify default ports for different schemes (http,https etc..). These default ports come into action in following scenarios:

  • When metadata is accessed over http, all http based URIs are substitued with the Hostname and host port from the Host header
  • All https based URIs picks the default port registered against https scheme
  • Similarly when metadata is accessed over https, all https URIs pick up the host and port from the host header and http based URIs used the default port registered against http scheme

This behavior is added in .NET 4.0 and there is a QFE available for 3.5 SP1: http://support.microsoft.com/kb/971842

Posted in WCF | 4 Comments »

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 »

 
Follow

Get every new post delivered to your Inbox.