How to Impersonate a Windows Client on a WCF Service

The previous example showed how to configure message based security with Windows authentication. So we know who the user is calling our service operations. But what can the user do on our system? On windows systems we can use user impersonation for authorization. We simply service the operation call as the calling user, instead of the logged in user account. In the following example the authenticated Windows user call the operation WriteToLogFile of the EchoService. We impersonate the current logged in account on the service side with the calling user. We dos this by setting the OperationBehaviour Impersonation property to ImpersonationOption Required If the user has no write rights to the file a FaultException is thrown.

[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public void WriteToLogFile(string logText)
{
    const string fileName = @"C:\logdir\logfile.txt";
    StreamWriter streamWriter = null;

    try
    {
        streamWriter = File.Exists(fileName)
                            ? File.AppendText(fileName)
                            : new StreamWriter(fileName);

        streamWriter.WriteLine("{2} - {0}: {1}",
            Thread.CurrentPrincipal.Identity.Name,
            logText,
            DateTime.Now.ToLongTimeString());
    }
    catch (Exception)
    {
        throw new FaultException("Log Access Denied");
    }
    finally
    {
        if (streamWriter != null)
            streamWriter.Close();
    }
}

On the client side, don’t forget to set the AllowedImpersonationLevel to TokenImpersonationLevel “Impersonation” or else the impersonation won’t fly. This level gives the service the right to impersonate the client locally, but not on a remote system.

using System;
using System.Net;
using System.Security.Principal;
using EchoClientConsole.EchoServiceReference;

namespace EchoClientConsole
{
    internal class Program
    {
        private static void Main()
        {
            var channel = new EchoServiceClient(
                "NetTcpBinding_IEchoService"
                );

            channel.ClientCredentials.Windows.AllowedImpersonationLevel =
                TokenImpersonationLevel.Impersonation;

            var networkCredential =
                new NetworkCredential
                    {
                        UserName = @"l040\WcfTester",
                        Password = "WcfTestPassword"
                    };

            channel.ClientCredentials.Windows
                .ClientCredential = networkCredential;

            try
            {
                channel.WriteToLogFile("Can I Log this?");
                Console.ReadLine();
                channel.Close();
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
                Console.ReadLine();
                channel.Abort();
            }
        }
    }
}

Now we can provide access to the logfile by administration of the windows ACL for a specific user.

Setting Permissions for logdir

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>