ASP.Net web application trying to use Impersonation and Delegation to connect to SQL Server
Asked Answered
L

2

16

I'm trying to use Impersonation and Delegation in an intranet ASP.Net web-app in order to pass authenticated users' credentials onto a SQL Server.

The web server and SQL server are two separate machines, but in the same domain, so Delegation is required.

I've done the following:

  • set <authentication mode="Windows"/> and <identity impersonate="true"/> in my web-app's web.config.
  • enabled Constrained Delegation from the web server to the MSSQLSvc service on the SQL Server, in Active Directory.
  • enabled only Windows Authentication in the website, through IIS.

Apparently this should all work, but it doesn't (the SQL Server is denying access to the anonymous user - "Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'").

In IIS7, the Application Pool is set to use Integrated Pipleline Mode and is running with the NetworkService Identity. The website only has Windows Authentication enabled, Extended Protection is Off, Kernel-mode authentication is enabled, and NTLM is the provider.

All the web pages I've read seem to indicate that my setup should work. What am I missing?

Landholder answered 20/1, 2010 at 11:52 Comment(2)
"the SQL Server is denying access to the anonymous user", do your anonymous user have database access?Sherri
The anonymous user does not have access to the database. I don't want the anonymous user accessing the database, I want the current user of the website. Delegation should mean that the current user is the one accessing the database, rather than the anonymous user.Landholder
L
16

I've discovered the answer:

The Windows Authentication provider in IIS7 must be set to Negotiate:Kerberos, not NTLM. This means that the Kernel-mode authentication setting must be disabled. This seems to be fine. I think I'm right in saying that Kernel-mode authentication is required when using a custom identity, i.e. one specific identity. Delegation can use an arbitrary number of identities. So all is well.

I've written a blog post about this too, which goes into a bit more detail.

Landholder answered 20/1, 2010 at 14:13 Comment(2)
Did you have any issues with users not getting their credentials forwarded to the SQL server when using a browser other than Internet Explorer? I've found that the once they have an established session in IE then the website can delegate their credentials if they switch to a different browser.Stephanus
@Peter - I know this is older post but what you describe is the problem I am trying to solve. How can I get Chrome to delegate credentials without opening the app in IE first? I posted a question about it earlier this week: #56136170Magallanes
U
-2

No - it is not accurate to say you need Kerberos, an SPN, to trust the server for delegation, and that this is the ONLY way to do it. Yes, this is one way to do it (and you do need all of it to make it happen via Kerberos), but it is not the ONLY way, or even technically the most secure way or easiest way. Do you really want to have to do extra configurations and create a login for every web user to your DB in SQL? What if any one of those accounts is compromised? More accounts, more vulnerabilities.

No, create a Domain service account, instead, and let that access SQL. If your security guys lock down things, give that user these rights: Logon as a service, Logon as a batch job, and Allow logon locally. Or, if this is just to develop and test the theory or you don't care or can't find the settings or are still getting errors later on, and this might not get a large following, but give it local Admin (sometimes you gotta do what you gotta do - some security pros lock down things tighter than I would care to write about - can always troubleshoot security later to lock it back down). Then set that account as the custom account on the app pool and give that account a login in SQL. Give it dbo on just THAT ONE database.

On the website in IIS, set the authentication type as Windows. I've seen them say "Basic" in other blogs so Kerberos will work, but NTLM uses Windows authentication. In IIS 7, you may also want to enable ASP .NET impersonation. Personally, I've only tried this on IIS 6, but the principal is the same.

In the web.config, add this under <configuration>, which is a "peer" to <system.web>:

<connectionStrings>
  <add 
     name="NorthwindConnectionString" 
     connectionString="Data Source=serverName;Initial 
     Catalog=Northwind;Integrated Security=SSPI;User 
     ID=userName;Password=password"
     providerName="System.Data.SqlClient"
  />
</connectionStrings>

And in <system.web>:

<authentication mode="Windows"/> 
<identity impersonate="true"
      userName="domain\user" 
      password="password" />

Then read the string into your app like this:

using System.Configuration;

string connString = String.Empty;
if (ConfigurationManager.ConnectionStrings.ConnectionStrings.Count > 0)
{
    connString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString; 
    if (connString != null) // do DB connection stuff here
        Console.WriteLine("Northwind connection string = \"{0}\"",
        connString.ConnectionString);
    else
        Console.WriteLine("No Northwind connection string");
}

See http://msdn.microsoft.com/en-us/library/ms178411.aspx.

If it will not connect with the service account after filling in that account in the web.config for the impersonate tag and the SQL connection, you can then use impersonation methods using WindowsImpersonationContext (http://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext.aspx). Specifically, you want wic.Impersonate() and wic.Undo() after getting their token. You can read in the service account domain, name, and password from the web.config, in the form of AppKeys.

In short, there are ways around the issues. You can even encrypt the password in the web.config - both in the ConnectionString, and if you want to store it in an AppKey instead of directly in the "impersonate" tag, if you don't want plain text passwords in there (which I'd recommend against), and so you can have it for the creation of a Logon token, if you need to use the Impersonation methods (as I did).

Unchancy answered 27/8, 2013 at 4:14 Comment(7)
This doesn't actually answer his questionFabricant
@FireLizzard, uh, I gave all the steps required to "use Impersonation and Delegation in an intranet ASP.Net web-app in order to pass authenticated users' credentials onto a SQL Server". This requires 1) a svc account, 2) rights in the Local Security Policy (described above) 3) rights in SQL (dbo - described above), 3) add account to App Pool identity, 4) set Web Site in IIS to Windows authentication, 5) set conn string in web.config, 6) set authentication tag and identity in web.config, 7) add connection string into code, 8) use impersonation code at MSDN link if it doesn't work.Unchancy
Different environments are going to have different rights, as far as accounts go, and he may or may not have privileges to give the account the rights it needs. Without knowing his environment, it is hard to give the specifics of exactly what will work. He will need to try giving the svc acct the rights I specified, and set up the web site and web.config. Maybe it will work without the MSDN impersonation code, maybe not. For my implementation I had just completed when I posted these steps, I needed it. For one I've done recently using Kerberos, SPNs, and a svc acct, I did not.Unchancy
How is this passing the user's credentials to SQL? Your web.config snippet has the app impersonating the service account, not the user.Fabricant
That's because, as I wrote, I identified that you don't want to send the user's credentials to the DB, but use a service account with the access. Ideally, you would take that person's user name and have a log-in routine for that site to begin with, or they shouldn't be on it. Or simply rely on Windows authentication if you don't care about restricting to individual users, but want to allow all authenticated.Unchancy
So, since your solution isn't using the user's credentials to authenticate the SQL session, you're not answering the question. You're telling Graham what you think he should do instead of telling him how to do what he wants to do.Fabricant
Ok, granted. But I believe in using best practices, and his way would mean having to allow everyone in the organization SQL access, and having to create accounts in SQL for each person - or at a minimum, create a security group and add them all into it. This could be hundreds, if not thousands, of people in some organizations. I believe if there's a better way to do something, we ought to share that, instead.Unchancy

© 2022 - 2024 — McMap. All rights reserved.