Impersonating ASP.NET Users

I have an ASP.NET MVC application that accesses a database to get some data and update data in another database when a form is submitted. Both the databases and IIS are on different servers and users will access this remotely, but everything is inside the network. Database access is provided to users through groups.

This means I need to use the credentials of the user (the person viewing the asp net application) to access both databases and I am having trouble getting it working. Here's what I tried:

After deploying the application and opening it remotely, it opens, but the method that accesses the database returns a Login Error for the domain / server name.

  • Impersonation enabled: "An ASP.NET setting has been detected that does not apply in Integrated Managed Pipeline mode."
  • validateIntegratedModeConfiguration = "false" → DirectoryServicesCOMException (0x80072020): An operational error has occurred.
  • Disabled impersonation and tried to add the impersonation code only in the code section I am accessing the db with:

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

    which resulted in a login error for NT AUTHORITY / ANONYMOUS LOGON

My connection string

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

      

Note. The app works fine when debugging in visual studio and accessing it locally on the server I deployed it to (with impersonation enabled). Also, we are using a smart card account and I cannot prompt for credentials for the user. I cannot use a different user ID due to the security models of our servers.

+3


source to share


4 answers


What you are doing / asked to do is usually frowned upon. When there is a connection string Integrated Security=True

, the SID / user gets access to the connection, determined by the application pool. This allows working with a pool of SQL connections.

When you try to access the SQL server using Integrated Security with authentication or impersonation through a proxy you basically lose all value from the connection pool (because now every connection has to be created with user credentials and cannot be used shared for inquiries).



Usually when I run into this situation, I create a user, provide db access and use it with the application pool. When a user authenticates to a website (windows or basic auth), I use Active Directory or LDAP services to verify that the user has access to the application.

+2


source


I suspect that your web application is not authenticating your users, otherwise you will not receive the message Login failed for NT AUTHORITY/ANONYMOUS LOGON

.



Check your IIS website settings and make sure Anonymous Authentication is disabled.

+2


source


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

I had to code impersonation using win32 calls to login to a specific user. Then I found it didn't work very well with SQLClient and had to improve it further.

This is not exactly what you want, but here is the code I am using now. 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);
    }
}

      

0


source


The reason it is called is because the server is trying to access the database, and the server does not trust the database, so it cannot resolve the credentials.

You can use an explicit identifier in the application pool and the Impersonate Disabled setting. IIS will run on behalf of the ID. Make sure the identifier has access to the database. This will be a safer solution.

0


source







All Articles