Geeks With Blogs
Jan Schepens Software Developer
OK so this is my first blogpost (EVER) so I hope it'll be of value to some people.

This post is about passing through some information at the client to the server, and how to automate this using the WCF configuration.

Case study:
I was with a client, developing WCF services which are hosted on IIS. Since they already have a wide range of security settings stored in databases, it would be a shame to let go of those configurations and force a whole new security model on them instead of trying to integrate their configs into the services.
We have several end users surfing to an intranet site (which is our WCF client), while the site communicates with several servers running WCF services on IIS. The site runs under a simple network service so the Windows Authentication is guaranteed server-side.
But to ensure security for several users (not everyone is allowed to view the same information) we want to pass the current username to the WCF service, and perform a security check with the client configurations, before returning any results.

How do we do this? Well there are probably tons of solutions available, but the way that worked the easiest for me (and my client) is working with custom behaviors on the endpoints, where the username will be passed in a WCF header.

So we need two classes: one to add the header client-side, and one to process the username server-side. In my example, I call them RequestAuth and ProcessAuth. Let's start out with RequestAuth.

Since I want to add something to the message at the endpoint level, I'll need to implement the IClientMessageInspector interface, which is found in the System.ServiceModel.Dispatcher namespace, and the IEndpointBehavior interface, in the System.ServiceModel.Description namespace. BUT, since we are going to add this to a behavior, we need to inherit from the BehaviorExtensionElement class, in the System.ServiceModel.Configuration namespace.


Now before we start implementing, bare in mind that it might come in handy to override the BehaviorType property of BehaviorExtensionElement, as well as the CreateBehavior() method. This is done easily by doing:
    public override Type BehaviorType
    {
            get { return typeof(RequestAuth); }
    }

    protected override object CreateBehavior()
    {
            return new RequestAuth();
    }

Also, to store the current user to send to the server, I'll hold a property UserName:
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private string userName;

    public string UserName
    {
            get { return userName; }
            set { userName = value; }
    }

Note: by using the System.Diagnostics.DebuggerBrowsable attribute and setting it to never, no client will ever get to see the private fields in your code. Not only is this safer, but it also gives a better debugger view when debugging.
Now, while it is not necessary anymore in .NET 3.5 to link a property to a private field, this example was written in .NET 2.0, so if you are redoing this in 3.5 you won't need the username field.

On to the implementations then! At first, I have to implement the IClientMessageInspector members.
Keeping in mind that I am SENDING something to the server, I only need to implement the BeforeSendRequest method.

So we need to make a MessageHeader object of string to send the username. After that, I try to retrieve the current logged on user.
In here I needed to make a difference between web applications and desktop applications. But if you are certain that you will ALWAYS
run in one environment (web or desktop) you can drop the check and keep the right username
Now, before I did the actual implementation, I keep a name and a namespace for my header in two private fields, so I can easily find
them back server side.
    [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
        private string hName = "SomeName"; //use your own name for the header in here
        [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
        private string hNameSpace = "http://SomeNameSpace"; //use own namespace here

        public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
        {
            MessageHeader<string> header = new MessageHeader<string>();
            header.Actor = "Anyone";
           
            //Keep the difference between web environments and desktop environments
            if (System.Web.Hosting.HostingEnvironment.IsHosted)
            {
                if (OperationContext.Current != null)
                    UserName = OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name;
                else
                {
                    if(System.Web.HttpContext.Current != null)
                        UserName = System.Web.HttpContext.Current.User.Identity.Name;
                }
            }
            else
                UserName = System.Threading.Thread.CurrentPrincipal.Identity.Name;

            //Add the username to the header
            header.Content = UserName;

            //Creating an untyped header to add to the WCF context
            System.ServiceModel.Channels.MessageHeader unTypedHeader = header.GetUntypedHeader(hName, hNameSpace);

            //Add the header to the current request
            request.Headers.Add(unTypedHeader);

            return null;
        }

So the previous code snippet will add a string containing the username to the WCF request. But to do this for every request, we still
need to add the MessageInspector we just implemented to the behavior. So on to the implementation of the IEndpointBehavior interface!
Well there's nothing much to it in this part, but to use the current clientbehavior and add the inspector:
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(this);
        }
NOTE: I use <this> as parameter, because the class we are working in IS a message inspector, thanks to the IClientMessageInspector interface
we implemented.

THAT'S IT FOR THE CLIENT SIDE!!! If you build this in an assembly and sign it, you will be able to add this in your WCF config file.
HOW? Simple: Open your WCF config file with the WCF Config Editor tool (SvcConfig.exe). Under the "Advanced" node, within "Extensions", you have
a node "behavior element extensions". That's where you click New, give your extension a name, and browse to your newly created assembly, and select
the correct behavior element to add (if you have multiple in one assembly). In this case, you need to select the RequestAuth item.
Once this is done, you can navigate to your Endpoint Behaviors, and in your behavior, if you click Add, you will see the new extension in the
list of available extensions. From now on, every service that uses this endpoint behavior will add the new username header to every outgoing request
it makes. Posted on Monday, March 17, 2008 4:25 PM | Back to top


Comments on this post: Automate passing valuable information in WCF headers

# re: Automate passing valuable information in WCF headers
Requesting Gravatar...
Thanks for the post. Always nice to search google/live and to end up at a blog of one of your colleagues :d

Best regards,
Sam
Left by Sam Vanhoutte on Dec 05, 2008 4:43 PM

# re: Automate passing valuable information in WCF headers
Requesting Gravatar...
Thanks for this post. This was exactly what I needed and saved me a ton of time!

-- Dan
Left by Dan on Dec 09, 2008 2:04 AM

# re: Automate passing valuable information in WCF headers
Requesting Gravatar...
Great example. Can you send the client and server code? Thanks
Left by Jim Meehan on Mar 09, 2009 7:44 PM

# re: Automate passing valuable information in WCF headers
Requesting Gravatar...
This is a good exercise for passing around header data, but as far as username is concerned, I believe WCF provides an implicit property where you can obtain it: OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name

Nonetheless, thanks for laying the grounds for passing data, I'll be using it to pass machine name and other info.
Left by Hadi on May 19, 2009 5:40 PM

# re: Automate passing valuable information in WCF headers
Requesting Gravatar...
Please could you send me the client and server code. I want to follow all the steps. This is exactly the solution I need for my project. Thank you.
Left by Daniel on Jul 13, 2009 10:59 AM

# re: Automate passing valuable information in WCF headers
Requesting Gravatar...
Great stuff...
Can you please upload the sample code, then all the reader can easily get into this.
Left by Ramesh R on Sep 09, 2009 5:02 AM

# re: Automate passing valuable information in WCF headers
Requesting Gravatar...
Is it secure to pass user name and password in request headers, can some one grab the headers and use it
Left by Kumar on Nov 17, 2011 2:42 PM

Your comment:
 (will show your gravatar)


Copyright © Jan Schepens | Powered by: GeeksWithBlogs.net