4

I want to access a database with the credentials of the client user.

my code:

Task.Run(() => 
{
        // Connect to DB.
}

I have the identity tag with impersonation attribute in the system.web node:

<identity impersonate="true" />

I have the validation tag in the system.webServer node:

<validation validateIntegratedModeConfiguration="false" />

I have the authentication set to windows:

<authentication mode="Windows" />

I have impersonation and windows set on my app in iis:

iis settings

I have the app set to use passthrough:

enter image description here

I have restarted iis.

I am at a loss at how this works or I totally misunderstand it.

Chris Hayes
  • 3,876
  • 7
  • 42
  • 72
  • https://msdn.microsoft.com/en-us/library/xh507fc5.aspx – Daniel A. White Sep 18 '15 at 18:21
  • Sample connection string could clarify what you are actually trying to connect too... I suspect you have more specific question than "How does asp.net impersonation work" (because it would be way too broad), but not yet clear what the question is. – Alexei Levenkov Sep 18 '15 at 18:25
  • thank you Daniel but this doesn't explain how to execute code as the impersonated user – Chris Hayes Sep 18 '15 at 18:25
  • i must totally misunderstand 'impersonate'. I believe it means to pretend to be someone. I want my code to pretend it's executing as the client caller via windows auth – Chris Hayes Sep 18 '15 at 18:26
  • this generally works. i also give full permissions to iis_iusrs for the root folder and everything inside. – blogbydev Sep 18 '15 at 18:28
  • and voila, my code isn't impersonating diddly: System.Security.Principal.WindowsIdentity.GetCurrent().Name "IIS APPPOOL\\DataCopyTool" – Chris Hayes Sep 18 '15 at 18:29
  • I figured it out. the code was in a task and that task didn't transport the credentials – Chris Hayes Sep 18 '15 at 18:30
  • thip is the app pool identity.. you can give your username/pass to the app pool directly.. and that will work – blogbydev Sep 18 '15 at 18:30
  • 1
    Is your database on a different server than IIS? If so, you need to do some work to setup trusted authentication between the two servers. – Arian Motamedi Sep 18 '15 at 18:31
  • 1
    @ChrisHayes please either close the question or self-answer (you may still want to update question to at least have better title). – Alexei Levenkov Sep 18 '15 at 18:40

2 Answers2

5

Based on your comment, it seems like you are running System.Security.Principal.WindowsIdentity.GetCurrent().Name in a Task, and getting App Pool's identity instead of impersonated user's. This is a common issue (take a look at this question I asked a while back).

There is however, a workaround. If you still want your Task to run as the impersonated user, you'll have to save current user's token before the Task runs and try to "re-impersonate" the Task's context like this:

IntPtr currentUser = WindowsIdentity.GetCurrent().Token; // This token points to the impersonated user

Task.Run(() => 
{
    using (WindowsIdentity.Impersonate(token))
    {
        // Connect to DB.
    }
}

This ensures anything in the Using block runs under impersonated user's identity.

Community
  • 1
  • 1
Arian Motamedi
  • 7,123
  • 10
  • 42
  • 82
1

Had this lying around:

Windows Interop...

public static class Win32LogonInterop
{
    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
    public static WindowsIdentity LogOn(string domain, string userName, string password)
    {
        IntPtr token = IntPtr.Zero;

        if (NativeMethods.LogonUser(userName, domain, password, ConnectionKind.NewCredentials, Provider.Default, out token))
        {
            return new WindowsIdentity(token);
        }
        else
        {
            RaiseError();
            return null;
        }
    }

    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
    public static void LogOff(WindowsIdentity identity)
    {
        if (identity != null)
        {
            if (!NativeMethods.CloseHandle(identity.Token))
                RaiseError();
        }
    }

    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
    private static void RaiseError()
    {
        int errorCode = Marshal.GetLastWin32Error();
        throw new Win32Exception(errorCode);
    }
}

internal static class NativeMethods
{
    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool LogonUser(
            string userName,
            string domain,
            string password,
            ConnectionKind connectionKind,
            Provider provider,
        out IntPtr token);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool CloseHandle(IntPtr handle);
}

public enum Provider
{
    Default = 0,
    WindowsNT35 = 1,
    WindowsNT40 = 2,
    WindowsNT50 = 3
}

public enum SecurityLevel
{
    Anonymous = 0,
    Identification = 1,
    Impersonation = 2,
    Delegation = 3
}

public enum ConnectionKind
{
    Unknown = 0,
    Interactive = 2,
    Network = 3,
    Batch = 4,
    Service = 5,
    Unlock = 7,
    NetworkClearText = 8,
    NewCredentials = 9
}

Impersonation method...

private void MyMethod(string domain, string userName, string password)
{
    WindowsIdentity _identity = Win32LogonInterop.LogOn(domain, userName, password);
    WindowsImpersonationContext impersonation = null;
    try
    {
        impersonation = _identity.Impersonate();

        // Stuff that needs impersonation
    }
    finally
    {
        if (impersonation != null)
        {
            impersonation.Undo();
            impersonation.Dispose();
        }
        if (_identity != null)
        {
            Win32LogonInterop.LogOff(_identity);
        }
    }
}
Adam Milecki
  • 1,738
  • 10
  • 15