Download Example Code Found Here

I used to really hate Basic Http Authentication when used for WCF services. For a long while I thought there had to be a better way of handling this other than storing your credentials in the of your application. And indeed, after I got to look around and feel comfortable with WCF and I created a simple behavior extension that would allow credentials to be stored side-by-side with the WCF configuration. Problem solved.

First, WCF has many extension points, and you can do many things to your advantage by implementing one. Most of these involve getting rid of cross-cutting concerns and extending the communication protocol used for WCF.

In our example our extension is really quite simple. First we create an extension element that we can use via WCF configuration. This extension represents the configuration element and is used to dynamically add your extension at runtime. Below is a sample of our HTTP basic authentication extension.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Configuration;

using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Activation;
using System.ServiceModel.Description;

namespace Azure.ServiceModel
{
    /// <summary>
    /// Provides the ability to define the basic credentials used to communicate
    /// to the investor service.
    /// </summary>
    public class BasicHttpCredentialBehaviorElement : BehaviorExtensionElement
    {
        /// <summary>
        /// Gets or sets the name of the user.
        /// </summary>
        /// <value>The name of the user.</value>
        [ConfigurationProperty("userName", IsRequired = true)]
        public string UserName
        {
            get { return this["userName"] as string; }
            set { this["userName"] = value; }
        }

        /// <summary>
        /// Gets or sets the password.
        /// </summary>
        /// <value>The password.</value>
        [ConfigurationProperty("password", IsRequired = true)]
        public string Password
        {
            get { return this["password"] as string; }
            set { this["password"] = value; }
        }

        /// <summary>
        /// Creates a behavior extension based on the current configuration settings.
        /// </summary>
        /// <returns>The behavior extension.</returns>
        protected override object CreateBehavior()
        {
            return new BasicHttpCredentialEndpointBehavior(UserName, Password);
        }

        /// <summary>
        /// Gets the type of behavior.
        /// </summary>
        /// <value></value>
        /// <returns>A <see cref="T:System.Type"/>.</returns>
        public override Type BehaviorType
        {

            get
            {
                return typeof(BasicHttpCredentialEndpointBehavior);
            }
        }
    }
}

Note that our configuration element defines what class to create under CreateBehavior(). In our case, this class is responsible for adding the username and password whenever we talk to our services. Note how the username and password is passed to our BasicHttpCredentialEndpointBehavior.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Xsl;

using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Activation;
using System.ServiceModel.Description;

namespace Azure.ServiceModel
{
    /// <summary>
    /// Provides the custom behavior on an endpoint to all a client to talk
    /// to a service using basic authentication.
    /// </summary>
    public class BasicHttpCredentialEndpointBehavior : IEndpointBehavior
    {
        static object _lockObject = new object();
        string username;
        string password;

        /// <summary>
        /// Initializes a new instance of the <see cref="BasicHttpCredentialBehavior"/> class.
        /// </summary>
        public BasicHttpCredentialEndpointBehavior()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BasicHttpCredentialBehavior"/> class.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        public BasicHttpCredentialEndpointBehavior(string username, string password)
        {
            this.username = username;
            this.password = password;
        }

        #region IEndpointBehavior Members

        /// <summary>
        /// Implement to pass data at runtime to bindings to support custom behavior.
        /// </summary>
        /// <param name="endpoint">The endpoint to modify.</param>
        /// <param name="bindingParameters">The objects that binding elements require to support the behavior.</param>
        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {

        }

        /// <summary>
        /// Implements a modification or extension of the client across an endpoint.
        /// </summary>
        /// <param name="endpoint">The endpoint that is to be customized.</param>
        /// <param name="clientRuntime">The client runtime to be customized.</param>
        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            lock (_lockObject)
            {
                var cc = endpoint.Behaviors.Find<clientCredentials>();
                cc.UserName.UserName = this.username;
                cc.UserName.Password = this.password;
            }
        }

        /// <summary>
        /// Implements a modification or extension of the service across an endpoint.
        /// </summary>
        /// <param name="endpoint">The endpoint that exposes the contract.</param>
        /// <param name="endpointDispatcher">The endpoint dispatcher to be modified or extended.</param>
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) { }

        /// <summary>
        /// Implement to confirm that the endpoint meets some intended criteria.
        /// </summary>
        /// <param name="endpoint">The endpoint to validate.</param>
        public void Validate(ServiceEndpoint endpoint) { }

        #endregion

    }
}

Now if we want to use our new extension we can add it to our app.config/web.config under system.serviceModel.

<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="basicHttpCredential" type="Azure.ServiceModel.BasicHttpCredentialBehaviorElement, Azure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=72acb2628d02c9fb"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>

What is important to note is that the DLL that has our extension is signed and that the FULL ASSEMBLY NAME is used. WCF will not allow you to include an extension that does not have a FULL ASSEMBLY NAME. You’ll get some wonky exception that it can’t find your behavior extension if you don’t have the full name (or you fat fingered it).

Now after you added your behavior extension you can target your endpoint behaviors to include this new extension and use it whenever your endpoints are created, this is where we can inject our credentials into our service call behind the scenes.

<behaviors>
<endpointBehaviors>
<behavior name="[YOUR_BEHAVIOR_NAME]">
<basicHttpCredential userName="********" password="********"/>
</behavior>
</endpointBehaviors>
</behaviors>

After that is accomplished you can now add to your WCF configuration the behaviorConfiguration you defined above.

<client>
<endpoint address="****.svc"
behaviorConfiguration="[YOUR_BEHAVIOR_NAME]" binding="basicHttpBinding" bindingConfiguration="https"
contract="****" name="****" />
</client>

And there ya have it. Quick and easy username and password stored in your configuration, side-by-side with your WCF configuration. Easy, no?

 

One Response to WCF BasicHttpBinding : Username and Password Behavior

  1. Don’t cry when something is over, smile when something is happened. Don’t give up, you are always the unique one. Just believe yourself.

Leave a Reply

Your email address will not be published. Required fields are marked *

*


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Set your Twitter account name in your settings to use the TwitterBar Section.