ASP.NET web app can't use multiple impersonation for authenication - asp.net

I have a asp.net app (uses windows authentication for access) which (stipulated by the security team) needs to connect to a remote SQL Server 2005 using integrated security.Because of the fact that it is remote SQL server I needed to impersonate a custom account (impersonating the original caller would not work) via :
<identity impersonate = "true" userName="domainname\user" password="password" />
This workes fine. The rub is my app also connects to an SSRS server for reporting needs using the ReportViewer control. The report server is on a separate server and the security team mandates that all calls to this server must be using the original window's account for auditing purposes. It seems my only option was to to try and separate my app into folders and use a "location" tag in my web.config and use separate identity tags. Such as:
<location path="Reporting">
<system.web>
<identity impersonate = "true"/>
</system.web>
</location>
Note: no username and password specified which means it should impersonate the original caller.
However to make matters even more complicated my app is a Masterpage/content page app. The master page makes calls to SQL to populate menus and such. Bottom line is the dual impersonation track is not working. I am ready to throw my hands up and declare that that this can not be done. If there was a way where I could have the app impersonate the original caller which would satisfy my SSRS auditing needs yet make connections to SQL server as the custom domain account. I cannot use SQL authentication: not allowed although that would solve this issue.

Have you tried the following setup:
Set impersonation to true. This is necessary for authentication into the application and for access to the SSRS to use current user logged in.
Use one connection string to SSRS that has Integrated Security set to true, so that the impersonated user passes straight through.
Use a second connection string, with the custom user name and password hard coded into the connection string. You can encrypt the connection string section of the web.config so that it isn't visible to human eyes, but the framework will automatically decrypt this on the fly when creating a connection.
I have a similar situation (need a specific account to retrieve specific data, but the general impersonation for the rest of the service functionality) and this setup is working.
EDIT: The general syntax for encrypting your web.config from the command prompt is:
aspnet_regiis -pef "connectionStrings" [PhysicalPathToApplication] -prov "DataProtectionConfigurationProvider"
Encryption is done on a machine per machine basis, so the encryption will have to be done on the specific server. You can pull up more documentation on this if needed.

You should be able to switch the impersonation on and off, so you can go back to using the default account running the site. I will have to check, it's been a while since I have done it.
This looks like a start as to how to do it:
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
//Insert your code that runs under the security context of the authenticating user here.
impersonationContext.Undo();
Essentially you just impersonate the appropriate user for the calls you need, and then "undo" the context and turn it off. It goes back to the default user after that.
Here is a link to the windows identity class:
http://msdn.microsoft.com/en-us/library/system.security.principal.windowsidentity.aspx

Related

AD User Authentication

I am attempting to create an ASP.NET (.NET 3.5) website to connect to our Exchange 2010 server through Exchange Web Services, I am able to connect to EWS when I define the username, password and domain to authenticate with but I would like, if possible, to not include login details in my code.
In IIS I have enabled Integrated Windows Authentication for the site, in web.config of the site I have <authentication mode="Windows"/>.
The following code is what I have been woking with:
svc.UseDefaultCredentials = True
svc.Credentials = New WebCredentials()
svc.Url = New Uri(svcURL)
With the above code I am receiving the message:
When making a request as an account that does not have a mailbox, you
must specify the mailbox primary SMTP address for any distinguished
folder Ids.
When I attempt to use svc.Credentials = CredentialCache.DefaultNetworkCredentials (in place of svc.Credentials = New WebCredentials()) I receive the error message:
Unable to cast object of type 'System.Net.SystemNetworkCredential' to
type 'Microsoft.Exchange.WebServices.Data.ExchangeCredentials'.
As mentioned, the only thing that has worked is to define the user credentials to authenticate to by hardcoding user login details, which I would rather not do: svc.Credentials = New WebCredentials("username","password","domain")
Has anyone been able to authenticate to EWS using the credentials of the current logged in user in an ASP.NET website?
By default it is not possible to delegate a user's credentials from one server (the server on which you are hosting your ASP.NET site) to another (your Exchange server). This is known as a "server hop" and Windows will prevent it by default as a security measure.
You have a couple of options to work around this:
Using Kerberos: When Kerberos is enabled it makes it possible to delegate user credentials between servers when using Windows authentication. I do not know the exact details on how to set up Kerberos as I am only a humble developer but maybe your system administrator can assist you. AFAIK, you need to set up your ASP.NET server to allow user delegation.
Setting the user identity of your IIS application pool: If Kerberos is not an option, you may change the identity of the application pool that your ASP.NET site is running under. First define a new application pool in IIS manager. Then go to the Advanced Settings dialog for that application pool and set the identity to a domain user that is allowed to access your Exchange server. More info on the application pool identity here: http://technet.microsoft.com/en-us/library/cc771170(v=WS.10).aspx.
Setting the <identity> element: If you for some reason cannot change the application pool, you may try impersonation of your ASP.NET web site using the <identity> element in your web.config file. ASP.NET gives you the option of storing the credentials in the registry so that you do not have to put them directly in your web.config file. More info here: http://msdn.microsoft.com/en-us/library/72wdk8cc(v=vs.90).aspx
Using the <appSettings> ellement and encryption: The last option I can think of is to simply put the credentials in your web.config file as normal <appSettings> and then encrypt the entire <appSettings> section. You would then simply read the appSettings from your code using the AppSettingsReader class. .NET allows you to encrypt sections of the web.config file out of the box and you can read the settings without event noticing that the section is encrypted. .NET takes care of decrypting for you. More info here: http://msdn.microsoft.com/en-us/library/zhhddkxy.aspx

ASP.NET accessing a SQL Server in a different server

I have installed a new web application that access a SQL Server database in a different server. I'm using Windows Authentication and get the error of:
Login Failed for user XXX
When I try to set identity impersonate="true" in the web.config file, it just throws an error
Login Failed for anonymous user
Also, I'm using forms authentication to validate users from my website and using a different application pool.
Update: connection string Basically like this:
Data Source=myServerAddress;Initial Catalog=myDataBase;Integrated Security=SSPI;
Update:
My Virtual Directory has Anonymous Authentication and Windows Authentication enabled.
Typically ASP.NET runs as an anonomous account. In order to access a remote SQL Server using integrated authentication (SSPI), you'll need to have a bit more "permenant" presence. Easy way would be to shift the app pool to use the NETWORK SERVICE built-in account. Slightly trickier would be to use a named account. On the SQL server side of the equation you will need to give the same account -- either matching user/pass or NETWORK SERVICE -- proper permissions to your database.
Your DBA should be able to help.
It is difficult to provide you with an exact answer because you have not provided your connection string or info on your SQL Server config. Your best bet is to look at the IIS configuration and work out what user is attempting to access the different SQL Server. You then need to give this account access to the database. This is a common problem and most of the changes need to happen in SQL Server unless you can change the account that the web server is running under.

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

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?
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.
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).

what does 'run the ASP.NET worker process with dbo privileges' mean?

I am having issues implementing SqlSiteMapProvider using the Wicked Code article. I am using VB.NET and SQL Server 2008 - and the OnSiteMapChanged event is not firing (the SqlDepdencyCache just seems to simply be not working at all).
The article states "You also need to run the ASP.NET worker process with dbo privileges for SQL Server 2005 cache dependencies to work automatically.)"
I don't understand what this means. I know what the ASPNET user account is and that it runs aspnet_wp.exe which is basically the ASP.NET run time as I understand it. I know what DBO privs are on SQL. But my SQL and web servers are on different machines, and ASPNET is not a domain account. And it seems crazy to make it one to try to simply get the SqlDepdencyCache to work, and I have trouble believing everyone is doing this?
Anyone have any clue what I'm missing here?
Thanks very much
EDIT: I FOUND MY ISSUE!!! SET NOCOUNT ON INSIDE MY STORED PROC WAS CAUSING IT!! BEWARE AS THIS IS NOWHERE IN THE MSDN DOCUMENTATION!!!!
Your worker process identity needs to be changed to either a domain user OR a user with a matching username/password on both the web and database servers. The SQL Server would also need Windows authentication (or Mixed authentication) enabled.
Under IIS 5 (Windows XP/2000), you need to modify the ASP.NET Process Identity in the machine.config file.
Under IIS 6 / 7 (Windows Vista/7/2003/2008/R2) you should just be able to modify the Application Pool identity. If this doesn't work, enable <identity impersonate="true" /> in your web.config.
SqlDependencyCache uses SqlDependency and SqlDependency deploys at runtime a set of services, queues and stored procedures in your database as part of its infrastructure. You can read this article on more details what really happens The Mysterious Notification.
When you create your site map provider, you provide a connection string. This connection string specifies either a SQL login and password, or it specifies that SSPI (or Trusted, or Integrated) Authentication should be used. When a user and password are provided then this user is used to log in into your application database (the ASP database). When SSPI is used then the conenction is made using the ASP thread identity, which is either the app pool identity or the impersonated user identity. Whichever login ends up being used, this login must have the priviledges necessary to deploy the SqlDependency infrastructure (create a queue, create a service, create a stored procedure). The simplest way is to simply make this login's user in the database member of the db_owner role (which is the correct wording for what the article calls 'dbo priviledges').
So depending on yoru connection string, your app pool identity and your impersonation settings, the database user that corresponds to the login used by the map provider must be added to the db_owner role. I can't tell what you need to do, because it all depends on the variable factors enumerated above.

Database connections work fine when application is run from localhost. Login fails from dev server

I have an application which connects to a database, retrieves a username from a user's table and matches it against the username retrieved with System.Security.Principal.WindowsIdentity.GetCurrent.Name
On my localhost, everything works fine. The database exists on the development server but the application lies on my localhost. All of my authorization and authentication techniques are running smoothly.
However, when I publish my application to the development server, I'm faced with the following error.
Cannot open database requested in login 'databaseName'. Login fails.
Login failed for user 'DevelopmentServerName\ASPNET'.
I can't put my finger onto what would cause this. Any help would be greatly appreciated.
Thanks!
Edit: Here is the connection string!
<add name="connectionStringName" connectionString="Initial Catalog=myDatabase;Data Source=DevelopmentServerName;Integrated Security=True"
providerName="System.Data.SqlClient" />
Also, for context. This authentication needs to grab the user's Windows username and match it against the username in the database. Users will have the Computername\Myname username built into the database (if they are authorized to use the required section of the program, that is).
Thanks again :)
It appears that your application is attempting to connect to the database under the ASPNET account, which may have limited permissions on the development server, as opposed to logging in on your own (you local machine may actually be using your windows identity). I can see two potential solutions.
Make sure to add into the system.web section of your web.config file.
Check with the system administrator and the SQL administrator to make sure the ASPNET account has proper authorization to connect to the database, if indeed your environment allows this account to connect.
Adding some additional code to your question, such as your connection string may help things out as well.
EDIT:
Okay, you are indeed using IntegratedSecurity, so typically with this kind of setup (using impersonation), you need to make sure you are getting prompted to add your Username and Password to authenticate against.
We have a similar setup, and to do this, we have to go to the IIS settings for the virtual directory, select the Directory Security tab, and click the Edit button under Anonymous access and authentication control.
Make sure Anonymous access is unchecked, and you may will most likely need to enable the proper authentication for your environment. Unfortunately we're still using Basic authentication (clear text) here, but Integrated Windows authentication may will work for you too. It depends on your environment.
I'm adding this comment to the main post since this seemed to have done the trick...
I just found this post which may help you get the proper configuration setup to handle what you need based on your IIS environment.
The answer may lay with your connection string. My guess would be that you are using integrated authentication to log into the database. This works fine when it's your machine because the application is using your credentials. When you publish to the development server you would be using the aspNet user and wouldn't have the right credentials to login. I would either add this user to your database server or change your connection string to use SQL authentication.
It could be a firewall setting that's preventing your server from seeing your database.
It might also have something to do with your connection string. If you're using anything besides a username/password combo in your web.config file, you will probably require additional configuration to convince the database server to let you connect.
It seems that what you want to do is impersonate the caller of the web page. You need to add a line to your web.config to do this:
<identity impersonate="true" />
See this article for an explanation.

Resources