I have the following architecture outlined:
An API gateway (Web API) which is only available over the intranet, therefore the site is configured to use Windows authentication. This API allows users to interact with a Dll (C++ unmanaged) and because the functions provided by the Dll aren't ready for multi-user interaction and also because states while using the Dll must be maintained, there is a windows service which is responsible for calling the Dll. So in essence, a user makes a request to the gateway, which then invokes a method in the windows service using WCF (named pipes). When handling the first request for a given user, the WCF creates an AppDomain from where to run the Dll code. Now, the application users are mapped to SQL Server database users (...) which have read/write permissions set against, so, when creating the AppDomain to run the Dll it must be done in the context of the user who initiated the request. So far this is what I came up with which unfortunately isn't working.
I have got the following code in my gateway:
[Route("sessions/{sessionId}")]
[HttpPut]
public HttpResponseMessage CreateBalanceSession (Guid sessionId)
{
return Request.CreateResponse(GatewayBalanceProvider.Proxy.CreateSession(sessionId, WindowsIdentity.GetCurrent().Token)
? HttpStatusCode.OK
: HttpStatusCode.NotAcceptable, "Balance session could not be created");
}
and on the windows service end I've got this:
public bool CreateSession(Guid sessionId, IntPtr windowsUserToken)
{
var windowsPrincipal = new WindowsPrincipal(new WindowsIdentity(windowsUserToken));
}
And this is the exception I get when the code in the service runs:
An exception of type 'System.ArgumentException' occurred in mscorlib.dll but was not handled in user code
Additional information: Invalid token for impersonation - it cannot be duplicated.
Obviously I'm missing something here but I can't find what it is. It is my understanding that the token is created in the context of the IIS process, and since everything at this point is sync, shouldn't the token be valid still?
Any help is welcome.
Thanks
UPDATE 1
Based on the comments I started looking into how to duplicate the token which I got done, just a simple Api32 call, and got it all working in the same process:
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.ServiceModel;
namespace ConsoleApplication1
{
class Program
{
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
[DllImport("advapi32.dll", SetLastError = true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, out IntPtr DuplicateTokenHandle);
public enum SecurityImpersonationLevel : int
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
static void Main(string[] args)
{
IntPtr token;
IntPtr tokenDuplicate;
if (LogonUser("xxxxx", "xxxxx", "xxxxx", 2, 0, out token))
{
if (DuplicateToken(token, (int)SecurityImpersonationLevel.SecurityImpersonation, out tokenDuplicate))
{
//var channel = new ChannelFactory<IBalanceProvider>(new NetNamedPipeBinding(),
// new EndpointAddress("net.pipe://localhost/balance")).CreateChannel();
//Test it we can use the duplicated token
var windowsIdentity = new WindowsIdentity(tokenDuplicate);
//channel.CreateSession(Guid.Parse("88fb01c7-41b5-4460-9ce5-fc72f9b0aa33"), tokenDuplicate);
}
}
}
}
}
I can create a new instance of WindowsIdentity using the duplicated token, the problem is that when I send this token over the wire using WCF to the other process I still get the duplicated exception which is driving me mad. Is there anything else I need to do to make sure that the replicated token can be used outside of the scope in which it was created?
Thanks