views:

214

answers:

4

I am currently refactoring some code which performs Windows Impersonation for testability and have run into a bit of a roadblock. This is the bit of code that I am having trouble with:

...
if (LogonUserA(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) > 0)
{
    if (DuplicateToken(token, 2, ref tokenDuplicate))
    {
        var tempWindowsIdentity = new System.Security.Principal.WindowsIdentity(tokenDuplicate);
        var impersonationContext = tempWindowsIdentity.Impersonate();
        ...
    }
...
}

How do I mock the behaviour of instantiating a WindowsIdentity object out? I have thought of various alternatives:

  • Pass in a factory class that would create the instance and mock the behaviour of that
  • Pass in a delegate that handles the creation of the instance (i.e. like a C++ function pointer)

None of these alternatives seem particularly good to me because I'm afraid they would blur the intent of the method as the method signature would look something like the following:

public bool Impersonate(string user, string password, string domain, Factory factory)

or

public bool Impersonate(string user, string password, string domain, delegate WinIDCreator)

Because the intent of the method is to impersonate a particular user, it doesn't make sense to me that either a Factory class or Delegate should be provided to it. I do want to isolate and mock this behaviour out however as I am uncomfortable with the thought of a new WindowsIdentity instance being created every time I run a bunch of unit tests.

Any ideas or comments?

A: 

I would create a virtual Impersonate method that you could mock. The Impersonate method would be as follows:


public virtual WindowsImpersonationContext Impersonate(string tokenDuplicate) {
    var tempWindowsIdentity = new System.Security.Principal.WindowsIdentity(tokenDuplicate);  
    var impersonationContext = tempWindowsIdentity.Impersonate();

    return impersonationContext;
}
jamesaharvey
+1  A: 

I'm a Java dev but ...

Why not make the "Factory" an attribute of the the class that contains the Impersonate method?

The "Factory" attribute, perhaps, "windowIdentityFactory", could be set in the constructor or via a setter method (using some type of dependency injection).

The the test, you would supply the class with a mock Factory (as you've suggested). In production, you give it the real deal.

...
if (LogonUserA(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) > 0)
{
    if (DuplicateToken(token, 2, ref tokenDuplicate))
    {
        var tempWindowsIdentity = windowIdentityFactory.newInstance(tokenDuplicate);
        var impersonationContext = tempWindowsIdentity.Impersonate();
        ...
    }
...
}
LES2
+4  A: 

I think you are on the right track with the Factory idea, but I'd inject the Factory in the class constructor not as a method parameter. Your default constructor can create an instance of the default Factory if one is not supplied.

You are also going to have a few problems -- like needing real login ids and passwords in your unit tests -- if you don't factor out the LogonUserA and DuplicateToken methods as well. I'd suggest a thin wrapper around this implementing an interface that you can also inject in the constructor.

Below are some of the highlights to show you how to start structuring it.

public interface ILogonHelpers
{
     bool LogonUser( string user, string domain, string password, ref int token );
     void DuplicateToken(  int token, ref int duplicateToken );
}

public class MyClass
{
    public MyClass( ILogonHelper logonHelper, IIdentityFactory factory )
    {
        this.LogonHelper = logonHelper ?? new DefaultLogonHelper();
        this.IdentityFactory = factory ?? new DefaultIdentityFactory();
    }

    ...

if (this.LogonHelper.Logon(user, domain, password, ref token) > 0)
{
    if (this.LogonHelper.DuplicateToken(token, ref tokenDuplicate))
    {
        var tempWindowsIdentity = this.IdentityFactory.CreateIdentity(tokenDuplicate);
        var impersonationContext = tempWindowsIdentity.Impersonate();
        ...
    }
...
}
tvanfosson
Thanks for that. I should have added that I have encapsulated the logon stuff into a NativeMethods class and am simply mocking those out. The worry that I have with injecting the factory into the class is the same as using it as a method param - it doesn't feel 'natural' to have a class have a dependency on a class factory...
jpoh
i.e. This class performs Impersonation and so it has a dependency on a NativeMethods class (which encapsulates the Win API stuff I need). I'm finding it difficult to convince myself that having it also have a dependency on a Factory class is OK.
jpoh
A: 

I agree with tvanfosson about injecting the factory via the constructor (or possibly through a property if you regard the factory as optional). However, since you're not too happy about that, I suggest you take a look at TypeMock Isolator, which will let you mock instances in a rather unconventional way. It works by injecting IL similar to what profilers do and it allows you to use mocks without changing your object setups.

Brian Rasmussen