WCF Extensibility – Interactive Channel Initializer

This post is part of a series about WCF extensibility points. For a list of all previous posts and planned future ones, go to the index page .

Since this is a slow week (many people are on vacations for the Christmas / New Year holidays, at least in the western countries), I’ll take a break on the deep subseries about transport channels, and start covering some of the lesser used extensibility points in WCF. This week I’ll cover probably the least used of them all (on my quite unscientific method of the interface with the least number of results in both Bing and Google queries), the IInteractiveChannelInitializer interface.

According to the official description in MSDN, this interface enables the client to “display an user interface that enables the user of the application to create or select the credentials prior to opening a channel”. It’s essentially an asynchronous callback which is called while the channel is being opened so that the user can be prompted for credentials, although the interface is passed an instance of the client channel, so nothing prevents its implementations from doing something else with the channel it’s passed to. Frankly, I don’t really know why we have this special interface for requesting the user credentials – the applications could as well simply ask the user for credentials, and after having that information in hand, create the channel and set the username / password directly on the client channel prior to opening it. Maybe that’s one reason why this interface isn’t used that much…

Applications who want to use this interface need to decide whether to call it explicitly or implicitly. In the former case, the client would, prior to opening the client (or calling any operations, which causes an implicit open call), call either ClientBase<TChannel>.DisplayInitializationUI or IClientChannel.DisplayInitializationUI (or one of its asynchronous versions). That will trigger the IInteractiveChannelInterface implementation to be called, and when it’s done, you can then open the client (again, either calling Open directly or calling one of its operations). In the implicit case, you’d simply call an operation, and the interactive channel initializers will be called for that channel. If the application uses the implicit approach, if the user doesn’t respond with the credentials within the open timeout, an exception will be thrown when the user interface returns.

Public implementations in WCF

None – even non-public ones (Reflector doesn’t show any derived types from that interface in the WCF assemblies). I think this interface is used by the Windows CardSpace product, though.

Interface definition

  1. public interface IInteractiveChannelInitializer
  2. {
  3.     IAsyncResult BeginDisplayInitializationUI(IClientChannel channel, AsyncCallback callback, object state);
  4.     void EndDisplayInitializationUI(IAsyncResult result);
  5. }

The interactive channel initializer interface is a UI-focused interface, so its methods are asynchronous. When BeginDisplayInitializationUI is called, applications would typically display a credentials UI, and return an IAsyncResult implementation which can be waited upon if the caller wishes. When the user finishes entering their credentials, then the code should invoke the callback passed to it, and the caller would then call the EndDisplayInitializationUI, and it’s up to the channel initializer to populate the user credentials in the channel.

The way the interactive channel initializer adds the credentials to the channel is quite convoluted: when it has the appropriate credentials, it should request a ChannelParameterCollection from the channel, using the IChannel.GetProperty<T> method. Then it should add an instance of a NetworkCredential object to the parameter collection, with the credentials obtained from the user interface.

There is, however, one extra step which is not properly documented (and thankfully Allan Nielsen was able to find out in his great post about this interface). The network credentials added to the channel parameter collection out of the box isn’t used by the runtime. The ClientCredentials behavior (which is added to the client for a binding which requires authentication) does not fetch the credentials from the channel parameter collection. So we need to have a custom behavior (derived from ClientCredentials), which uses a custom SecurityTokenManager implementation, which would in turn return a custom SecurityTokenProvider, which would finally return a SecurityToken with the credentials entered by the user (an UserNameSecurityToken). Again, just prompting the user beforehand would simplify this a lot… The example later in this post will show all this together.

How to add an interactive channel initializer

If you want to just add the initializer, a simple endpoint behavior does the trick. The list of interactive channel initializers can be accessed via the ClientRuntime object passed to ApplyClientBehavior (a contract behavior could be used as well), and adding one there will cause it to be called once the channel is opened (or if you call DisplayInitializationUI explicitly).

  1. class MyBehavior : IEndpointBehavior
  2. {
  3.     public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
  4.     {
  5.         clientRuntime.InteractiveChannelInitializers.Add(
  6.             new MyInteractiveChannelInitializer());
  7.     }
  8. }

However, if you want the initializer to be used to gather user credentials, you’ll need something more than that – namely, instead of having a simple class which implements IEndpointBehavior, you’ll likely have it deriving from ClientCredentials (which implements IEndpointBehavior itself).

Real world scenario: prompting user for credentials

This is a simple UI-based client/server system which uses the interactive channel initializer to gather the user credentials. As I’ve mentioned before, I really can’t tell exactly why we have this extensibility point, so this is quite an artificial example, but it should illustrate the usage of the interface.

And before starting with anything, the usual disclaimer – and this time I’ll make it stronger. This is a sample for illustrating the topic of this post, this is not production-ready code. There is hardly any error checking (if there’s any error from the server, the application will simply crash). More importantly, DO NOT ever, ever use basic authentication over insecure transports as is done in this sample (I did so to keep it small and focused on the interface itself) – this is essentially sending the user password in plain text over the network. I tested it for a few contracts and it worked, but I cannot guarantee that it will work for all scenarios (please let me know if you find a bug or something missing).

Ok, now that the warning is out of the way, let’s get to it. First, we need a service which requires credentials. To make the sample small (and F5-able), I’ll make the server self-hosted and using a simple username / password authentication mechanism using HTTP Basic (and just in case it wasn’t clear before, DO NOT use it in production). The service will be the calculator one which I’ve used a few times. In the server implementation, we’ll just update the server UI to show which user called which operation. Notice that, since this server will be hosted in an UI application (a Windows Form app), the implementation is decorated with the [ServiceBehavior] attribute with the UseSynchronizationContext property set to false to prevent a deadlock between the UI thread and the incoming messages.

  1. [ServiceContract]
  2. public interface ICalculator
  3. {
  4.     [OperationContract]
  5.     int Add(int x, int y);
  6.     [OperationContract]
  7.     int Subtract(int x, int y);
  8.     [OperationContract]
  9.     int Multiply(int x, int y);
  10.     [OperationContract]
  11.     int Divide(int x, int y);
  12. }
  14. [ServiceBehavior(UseSynchronizationContext = false)]
  15. public class Service : ICalculator
  16. {
  17.     public int Add(int x, int y)
  18.     {
  19.         this.UpdateServerFormUi("Add");
  20.         return x + y;
  21.     }
  23.     public int Subtract(int x, int y)
  24.     {
  25.         this.UpdateServerFormUi("Subtract");
  26.         return x - y;
  27.     }
  29.     public int Multiply(int x, int y)
  30.     {
  31.         this.UpdateServerFormUi("Multiply");
  32.         return x * y;
  33.     }
  35.     public int Divide(int x, int y)
  36.     {
  37.         this.UpdateServerFormUi("Divide");
  38.         return x / y;
  39.     }
  41.     private void UpdateServerFormUi(string operationName)
  42.     {
  43.         ServerForm.UserCalled(Thread.CurrentPrincipal.Identity.Name, operationName);
  44.     }
  45. }

Now for the hosting part. We’ll use a simple BasicHttpBinding with BasicHttpSecurityMode.TransportCredentialOnly and HttpClientCredentialType.Basic. Next, we need to hook up an authorization policy which will set the thread principal for the identity passed by the request. Finally, we need to hook up a custom password validator to validate the user and password passed to the system.

  1. private static BasicHttpBinding GetBinding()
  2. {
  3.     BasicHttpBinding result = new BasicHttpBinding();
  4.     result.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
  5.     result.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
  6.     return result;
  7. }
  9. private void CreateAndOpenHost()
  10. {
  11.     host = new ServiceHost(typeof(Service));
  12.     host.AddServiceEndpoint(typeof(ICalculator), GetBinding(), BaseAddress);
  13.     List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>();
  14.     policies.Add(new CustomAuthorizationPolicy());
  15.     host.Authorization.ExternalAuthorizationPolicies = policies.AsReadOnly();
  16.     host.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
  18.     host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
  19.     host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new MyPasswordValidator();
  21.     host.Open();
  22. }

To keep the sample simple, the username / password validator just does some basic check. A real one would probably get some data from a database (which preferably does not store the password, but some salted hash, but that’s another story).

  1. class MyPasswordValidator : UserNamePasswordValidator
  2. {
  3.     public override void Validate(string userName, string password)
  4.     {
  5.         // Very secure password scheme
  6.         if (userName != password)
  7.         {
  8.             throw new SecurityTokenException("Unauthorized");
  9.         }
  10.     }
  11. }

The custom authorization policy I borrowed from the “How To: Create a Custom Principal Identity” document from MSDN. It gets the identities from the evaluation context, and creates a custom principal from the first one there.

  1. class CustomAuthorizationPolicy : IAuthorizationPolicy
  2. {
  3.     string id = Guid.NewGuid().ToString();
  5.     public string Id
  6.     {
  7.         get { return this.id; }
  8.     }
  10.     public ClaimSet Issuer
  11.     {
  12.         get { return ClaimSet.System; }
  13.     }
  15.     public bool Evaluate(EvaluationContext context, ref object state)
  16.     {
  17.         object obj;
  18.         if (!context.Properties.TryGetValue("Identities", out obj))
  19.             return false;
  21.         IList<IIdentity> identities = obj as IList<IIdentity>;
  22.         if (obj == null || identities.Count <= 0)
  23.             return false;
  25.         context.Properties["Principal"] = new CustomPrincipal(identities[0]);
  26.         return true;
  27.     }
  28. }

At this point the service is ready, so we can run it and add a service reference from the client project. One thing that I noticed is that the generated configuration doesn’t get the client credential type correctly specified, so I’ll fix that in the client side code. Notice the code commented out is what I’d normally do (getting the username / password from some dialog or some other source). But since we’re trying to use the interactive client initializer, let’s go with it. As I mentioned before, we’ll be replacing the ClientCredentials behavior with another type which knows how to deal with the output of the initializer.

  1. private void InitializeClient()
  2. {
  3.     if (this.client == null)
  4.     {
  5.         this.client = new ServiceReference1.CalculatorClient();
  6.         BasicHttpBinding binding = this.client.Endpoint.Binding as BasicHttpBinding;
  7.         binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
  8.         binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
  10.         //client.ClientCredentials.UserName.UserName = "John Doe";
  11.         //client.ClientCredentials.UserName.Password = "John Doe";
  13.         this.client.Endpoint.Behaviors.Remove<ClientCredentials>();
  14.         this.client.Endpoint.Behaviors.Add(new ClientCredentialsEx(this));
  15.     }
  16. }

The ClientCredentialsEx class will do two things: first, it will add our interactive channel initializer to the client runtime. Then, as mentioned before, it will replace the security token manager with one which can interpret the result of the initializer.

  1. class ClientCredentialsEx : ClientCredentials
  2. {
  3.     ClientForm clientForm;
  5.     public ClientCredentialsEx(ClientForm clientForm)
  6.         : base()
  7.     {
  8.         this.clientForm = clientForm;
  9.     }
  11.     public ClientCredentialsEx(ClientCredentialsEx other, ClientForm clientForm)
  12.         : base(other)
  13.     {
  14.         this.clientForm = clientForm;
  15.     }
  17.     protected override ClientCredentials CloneCore()
  18.     {
  19.         return new ClientCredentialsEx(this, this.clientForm);
  20.     }
  22.     public override void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime clientRuntime)
  23.     {
  24.         clientRuntime.InteractiveChannelInitializers.Add(new ShowCredentialsUI(this.clientForm));
  25.         base.ApplyClientBehavior(serviceEndpoint, clientRuntime);
  26.     }
  28.     public override SecurityTokenManager CreateSecurityTokenManager()
  29.     {
  30.         return new MyClientCredentialsSecurityTokenManager(this);
  31.     }
  32. }

Now for the initializer itself. In all the (two) examples I’ve seen (and even in the documentation in MSDN), they have essentially a synchronous call to a UI which is invoked on the BeginDisplayInitializationUI method (the MSDN documentation states that in that method the code should get the user credentials and add them to the channel). That goes completely against the asynchronous pattern suggested by the interface (if it were the case, we wouldn’t need an asynchronous Begin/End method pairs, making the interface a lot simpler). In this example I’m implementing it as I believe the creators of the interface intended. The Begin call simply starts the credential UI. When that is done, the callback passed to the method is invoked, and only when the End operation is called that the client should expect to have the credentials added to the channel. In order to do that, I’ll use the same AsyncResult class which I used in the posts about transport channels (itself borrowed from the UDP Transport sample) which provides the infrastructure for dealing with asynchronous requests. As was the case in the asynchronous code in the transport channels example, the implementation of the actual Begin / End methods is quite simple, as shown below.

  1. class ShowCredentialsUI : IInteractiveChannelInitializer
  2. {
  3.     ClientForm clientForm;
  4.     public ShowCredentialsUI(ClientForm clientForm)
  5.     {
  6.         this.clientForm = clientForm;
  7.     }
  9.     public IAsyncResult BeginDisplayInitializationUI(IClientChannel channel, AsyncCallback callback, object state)
  10.     {
  11.         return new ClientPasswordAsyncResult(this.clientForm, channel, callback, state);
  12.     }
  14.     public void EndDisplayInitializationUI(IAsyncResult result)
  15.     {
  16.         string userName, password;
  17.         IClientChannel clientChannel;
  18.         ClientPasswordAsyncResult.End(result, out userName, out password, out clientChannel);
  19.         ChannelParameterCollection coll = clientChannel.GetProperty<ChannelParameterCollection>();
  20.         coll.Add(new NetworkCredential(userName, password));
  21.     }
  22. }

The ClientPasswordAsyncResult class is shown below. The ClientForm instance which was passed around from the client, to the behavior, to the interactive channel initializer and finally to this class is finally used. Here we’re dispatching a call to its UI thread in the constructor to show the password form as a modal (dialog) window. That’s a synchronous operation (there was already a lot of asynchronous code, and at this point we’re at the UI layer, so I cut a little corner here), and when it’s done (i.e., when the password form is closed), we complete the AsyncResult class (which causes the client callback to be invoked).

  1. class ClientPasswordAsyncResult : AsyncResult
  2. {
  3.     private delegate void ShowPasswordDialogDelegate();
  4.     ClientForm clientForm;
  5.     ClientPasswordDialog passwordForm;
  6.     IClientChannel clientChannel;
  8.     public ClientPasswordAsyncResult(ClientForm clientForm, IClientChannel clientChannel, AsyncCallback callback, object state)
  9.         : base(callback, state)
  10.     {
  11.         this.clientForm = clientForm;
  12.         this.clientChannel = clientChannel;
  13.         this.passwordForm = new ClientPasswordDialog();
  14.         this.clientForm.BeginInvoke(new ShowPasswordDialogDelegate(delegate
  15.         {
  16.             this.passwordForm.ShowDialog();
  17.             this.Complete(false);
  18.         }));
  19.     }
  21.     public static void End(IAsyncResult asyncResult, out string userName, out string password, out IClientChannel channel)
  22.     {
  23.         ClientPasswordAsyncResult thisPtr = AsyncResult.End<ClientPasswordAsyncResult>(asyncResult);
  24.         userName = thisPtr.passwordForm.UserName;
  25.         password = thisPtr.passwordForm.Password;
  26.         channel = thisPtr.clientChannel;
  27.     }
  28. }

Now for the last part of the client: the custom security token manager. This code is borrowed practically verbatim from Allan Nielsen’s post mentioned above (I tried to post a comment to thank him for that, but the comment page didn’t work, so if you know him, please thank him for me). When CreateSecurityTokenProvider is called for the appropriate usage and token type, we return our own token provider.

  1. class MyClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager
  2. {
  3.     public MyClientCredentialsSecurityTokenManager(ClientCredentials parent) : base(parent) { }
  4.     public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
  5.     {
  6.         if (tokenRequirement.KeyUsage == SecurityKeyUsage.Signature)
  7.         {
  8.             NetworkCredential token = null;
  9.             ChannelParameterCollection obj;
  10.             obj = (ChannelParameterCollection)tokenRequirement.Properties[
  11.                 ServiceModelSecurityTokenRequirement.ChannelParametersCollectionProperty];
  12.             token = obj[0] as NetworkCredential;
  13.             if (tokenRequirement.TokenType == SecurityTokenTypes.UserName)
  14.             {
  15.                 return new MyUserNameSecurityTokenProvider(token);
  16.             }
  17.         }
  19.         return base.CreateSecurityTokenProvider(tokenRequirement);
  20.     }
  21. }

Finally, the security token provider simply returns a UserNameSecurityToken based on the network credentials which were created by the interactive channel initializer.

  1. class MyUserNameSecurityTokenProvider : SecurityTokenProvider
  2. {
  3.     private NetworkCredential credentials;
  5.     public MyUserNameSecurityTokenProvider(NetworkCredential credentials)
  6.     {
  7.         this.credentials = credentials;
  8.     }
  10.     protected override SecurityToken GetTokenCore(TimeSpan timeout)
  11.     {
  12.         return new UserNameSecurityToken(this.credentials.UserName, this.credentials.Password);
  13.     }
  14. }

And that’s it. Try downloading the sample and running it. Once you call an operation for the first time, you should the credentials dialog showing up. If you enter the same value for the username and password, you should see in the server UI a notification saying that the user you entered called that operation.

[Code in this post]

[Back to the index]