Phil Sandler
Phil Sandler

Reputation: 28016

Testing WCF Service that Uses Impersonation

I am converting some existing integration tests of a legacy WCF service to be automated via NUnit. The current tests call a deployed version of the WCF service; what I would like to do is have the tests hit the service class (MyService.svc.cs) directly/internally.

The problem I am having is that the service uses impersonation:

    //this is a method in MyService.svc.cs
    public SomeObject GetSomeObject()
    {
      using (GetWindowsIdentity().Impersonate())
      {
        //do some stuff
      }

      return null;
    }

    private WindowsIdentity GetWindowsIdentity()
      {
        var callerWinIdentity = ServiceSecurityContext.Current.WindowsIdentity;

        var cf = new ChannelFactory<IMyService>();
        cf.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;

        return callerWinIdentity;
    }

The problem is that ServiceSecurityContext.Current is always null when I call it from a unit test.

The impersonation is important in downstream operations, so I can't just bypass this code and just call what is within the using block. It might be possible to wrap my test code in WindowsIdentity.GetCurrent().Impersonate() and then call what is within the using block (bypassing MyService.svc.cs code), but this would be less than ideal, as it would not be a complete end-to-end test.

I do not need to fake different users to impersonate--I just need the runner's user context to be available in ServiceSecurityContext.Current.

Is this possible?

Upvotes: 2

Views: 594

Answers (1)

Phil Sandler
Phil Sandler

Reputation: 28016

I'd still be interested in a better and less invasive way of doing this, but this seems to work for now.

I created a second constructor for MyService to allow the use of WindowsIdentity.GetCurrent().

    private readonly bool _useLocalIdentity;

    public MyService(bool useLocalIdentity) :this()
    {
        _useLocalIdentity = useLocalIdentity;
    }


    private WindowsIdentity GetWindowsIdentity()
      {
        if (_useLocalIdentity)
        {
            return WindowsIdentity.GetCurrent();
        }

        var callerWinIdentity = ServiceSecurityContext.Current.WindowsIdentity;
        if (callerWinIdentity == null)
        {
            throw new InvalidOperationException("Caller not authenticated");
        }

        var cf = new ChannelFactory<IMyService>();
        cf.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;

        return callerWinIdentity;
    }

Upvotes: 1

Related Questions