Problem with Impersonation and Trusted Connections
dmcollie
Posts: 7
Hi
I have an app written in ASP.NET 2. It uses trusted database connections and impersonates the current user for database access rather than use the NETWORK SERVICE account. This works fine for all of my database related code.
However I have problems when calling the comparison library in SQL Toolkit. Instead of using the logged in user account it instead uses the NETWORK SERVICE account. It therefore fails because the NETWORK SERVICE account does not have any database rights.
The problem is occurring when I call the Register method of the Database class, having passed in a ConnectionProperty object that was created using the (server, database) constructor.
Any ideas if this is a bug or am I doing something wrong?
Thanks
Dave
I have an app written in ASP.NET 2. It uses trusted database connections and impersonates the current user for database access rather than use the NETWORK SERVICE account. This works fine for all of my database related code.
However I have problems when calling the comparison library in SQL Toolkit. Instead of using the logged in user account it instead uses the NETWORK SERVICE account. It therefore fails because the NETWORK SERVICE account does not have any database rights.
The problem is occurring when I call the Register method of the Database class, having passed in a ConnectionProperty object that was created using the (server, database) constructor.
Any ideas if this is a bug or am I doing something wrong?
Thanks
Dave
Comments
The support for Windows authentication is provided transparently by the Windows operating system, so the Toolkit wouldn't be interfering with it in any way.
In ASP .NET, I believe that the web application's web.config file needs to be altered to turn on impersonation, otherwise any code for passing credentials on will not work. Somewhere in the system.web node, you should add an identity impersonate: You may also want to check your security event logs -- someone may have revoked NETWORK SERVICE's Impersonate a client after authentication user right. If this doesn't cure the problem, let me know...
I still think that setting identity impersonate in the web.config may be a useful troubleshooting step for you though. If that causes the web application to authenticate as the logged-in user, then you know it's probably something wrong with your ASP .NET code.
I am using <identity impersonate="true"/> in my web.config - that's how I have impersonation enabled.
This works fine for my own code when I connect to MSSQL using System.Data.SqlClient.SqlConnection with a SQL connection like "Data Source=localhost;Initial Catalog=some_db;Trusted_Connection=yes". Instead of connecting to the DB as the NETWORK SERVICE account under which ASP.NET is running it connects as the user that I am logged in as. I know this because I have traced the statements in the SQL Server Profiler and I do not get any security problems being raised by MSSQL.
However when I call RedGate.SQLCompare.Engine.Database.Register with a ConnectionProperties object created with two parameters (the server and databasename taken from the above connection string), MSSQL complains because the Register method is not impersonating the current logged in user but instead using the NETWORK SERVICE account. This implies that the Red Gate code is somehow ignoring the fact that it should be doing impersonation.
Any clues as to how to proceed to tract down what's wrong?
Thanks
Dave
I don't know. Could it be a threading issue? Maybe any threads spawned by your web application are not inheriting the credentials from the main thread?
and here's the exception raised when the Register method is called:
I believe that this code example clearly illustrates the problem: calling SqlConnection.Open() impersonates the logged in user fine whereas the call to Database.Register does not. TBH it looks like a bug in the SQL Toolkit libraries.
Cheers,
Dave
Seriously, there is nothing in the libraries that would change the security context. Windows is not passing the credentials down to the thread that's registering the database.
I've got a reproduction of the problem now, so I'll have a closer look tomorrow. I'm pretty sure this is specific to IIS.
I'm glad you can reproduce it (although I am sure you are not ;-) ). Let me know if there's anything more I can do to help.
Cheers
Dave
I think my original suspicion has been proved correct. SQLCompare Engine starts its' own thread, and IIS only passes the impersonation to threads that it controls. The solution is to apply a token to the thread. Here is some code that does the trick. Note that there is a class called 'DBRegistrar' that wraps up the SQL Compare functionality -- this was done because of Toolkit licensing implications that require the Red Gate components be be in a pre-compiled assembly outside of the web application code. For reference, this is the code used to create the wrapper dll around SQL Compare Engine: I hope that this works for you!
On second thought, this doesn't seem to work either. The SQL Toolkit uses an AsyncDelegate to register the database and the impersonation is not inherited from the application pool. The only way around this I can see is to specifically change the SQL Compare Engine so that the AsyncDelegate supports IIS impersonation.
All I can think to do is call the command-line version of SQL Compare (sqlcompare.exe) to create a snapshot file and then do all of the comparisons in your ASP .NET code from snapshot. If you use an external process you can call it using your impersonated credentials using Process.Start.
What're the chances of getting the SQL Compare libraries to actually exhibit the 'expected' behaviour under ASP.NET?
Thanks
Dave
Basically, in aspnet.config (which can be found under <Windows Folder>\Microsoft.NET\Framework\vx.x.xxxx directory) you would need to set these two values:
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
As an alternative, you can set this setting per application pool as described in https://weblogs.asp.net/owscott/setting-an-aspnet-config-file-per-application-pool