ASP.NET User Impersonation

3

I have an ASP.NET MVC application that accesses an database to retrieve some data and updates data on another database when the form is submitted. Both databases and IIS are on different servers and the users will be accessing this remotely, but everything is within out intranet. Access to the databases are granted to the users via groups.

This means i need to use the user's credentials (the person browsing to the asp net application) to access both databases and i am having a lot of trouble getting this to work. Here's what i've been trying:

After deploying the application and opening it remotely, it opens but the method that accesses the database returns Login failed for domain/servername.

  1. Enabled impersonation: "An ASP.NET setting has been detected that does not apply in Integrated managed pipeline mode."
  2. validateIntegratedModeConfiguration="false" - > DirectoryServicesCOMException (0x80072020): An operations error occurred.
  3. Disabled impersonation and tried to add code to impersonate only on the section of code i access the DB using:

    ((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
    

    which resulted in Login failed for NT AUTHORITY/ANONYMOUS LOGON

My connection string is

    "Data Source=" + SERVER + ";Initial Catalog=" + DB + ";Integrated Security=True;Connection Timeout=30;Trusted_Connection=true"

Note: he application works perfectly when debugging on visual studio and accessing it locally on the server i deployed it at (with impersonation enabled). Also, we use smartcard login and i cannot ask credentials to the user. I cannot use another ID on behalf of the user due to the security models of our servers.

c#
asp.net
asp.net-mvc
asked on Stack Overflow Apr 30, 2015 by YuriW • edited Apr 30, 2015 by John Saunders

4 Answers

2

I suspect your web app is not authenticating your users, otherwise you wouldn't get that Login failed for NT AUTHORITY/ANONYMOUS LOGON message.

Check your IIS web site settings and ensure anonymous authentication is disabled.

answered on Stack Overflow Apr 30, 2015 by MatteoSp
2

What you are doing/asked to do is typically frowned upon. When you have Integrated Security=True set in your connection string, the SID/user access the connection is defined by the application pool. This allows SQL Connection Pooling to work very efficiently.

When you try to access the SQL server using Integrated Security with Pass-through authentication or impersonation, you basically lose all value from the connection pool (because now each connection has to be created with the user credentials and cannot be shared across requests).

Normally when I come across this situation, I create a user, grant db access and use that user with the application pool. When a user authenticates on the website (windows or basic auth) I use Active Directory Services or LDAP to verify the user has access to the application.

answered on Stack Overflow Apr 30, 2015 by Erik Philips • edited May 1, 2015 by Erik Philips
0

I had a similar problem with impersonation not working in MVC.

I had to code out the impersonation using win32 calls to log in a specific user. Then I found this didn't play well with SQLClient and had to improve it further.

Its not quite what you want but here's the code I'm currently using. compiled from various internet sources

public class Impersonator
{
    public WindowsImpersonationContext Impersonate(string username, string domain, string password)
    {
        WindowsIdentity tempWindowsIdentity;
        const int LOGON32_PROVIDER_DEFAULT = 0;
        //This parameter causes LogonUser to create a primary token. 
        const int LOGON32_LOGON_INTERACTIVE = 2;
        SafeTokenHandle token;
        IntPtr tokenDuplicate = IntPtr.Zero;

        if (NativeMethods.RevertToSelf())
        {
            // Call LogonUser to obtain a handle to an access token. 
            bool returnValue = NativeMethods.LogonUser(
                username,
                domain,
                password,
                LOGON32_LOGON_INTERACTIVE,
                LOGON32_PROVIDER_DEFAULT,
                out token);

            if (returnValue)
            {
                if (NativeMethods.DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                {
                    tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                    NativeMethods.CloseHandle(tokenDuplicate);
                    return tempWindowsIdentity.Impersonate();
                }
                else
                {
                    throw new Exception("unable to login as specifed user - duplicate ");
                }
            }
            else
            {
                throw new Exception("unable to login as specifed user ");
            }
        }
        else
        {
            throw new Exception("could not revert to self ");
        }
        using (WindowsIdentity id = new WindowsIdentity(token.DangerousGetHandle()))
        {
            return id.Impersonate();
        }
    }
}
internal static class NativeMethods
{
    [DllImport("kernel32.dll")]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    [SuppressUnmanagedCodeSecurity]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool CloseHandle(IntPtr handle);

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool LogonUser(
        String lpszUsername, 
        String lpszDomain, 
        String lpszPassword,
        int dwLogonType, 
        int dwLogonProvider, 
        out SafeTokenHandle phToken);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int DuplicateToken(
        SafeTokenHandle hToken,
        int impersonationLevel,
        ref IntPtr hNewToken);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool RevertToSelf();
}

public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    private SafeTokenHandle()
        : base(true)
    {
    }

    protected override bool ReleaseHandle()
    {
        return NativeMethods.CloseHandle(handle);
    }
}
answered on Stack Overflow Apr 30, 2015 by Ewan
0

The reason that is being caused it is the Server tries to access the Database and the Server is not trusted by the Database, so it could not resolve the credentials.

You could use an explicit id at the Application Pool and setting the Impersonate Disabled. The IIS will run on behalf the ID. Make sure the ID have the Database Access. This will be the more secure solution.

answered on Stack Overflow Apr 30, 2015 by Anderson Oki

User contributions licensed under CC BY-SA 3.0