Windows authentication in WCF & IIS to access a database - asp.net

I have a WCF service I want to use to access a SQL db (via Linq2SQL at the moment), but the trusted security in a live IIS environment doesn't seem to use the right credentials - I've tried to follow the related posts here, but can't seem to quite get it. I'd be really grateful if someone could spot my mistake ...
in the Endpoint config, I've set it up to use BasicHttpBinding, with the following configuration
<basicHttpBinding>
<binding name="authHttpBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
I've set the system.web settings to:
<authentication mode="Windows" />
<identity impersonate="true" />
on the IIS server, I've added a new AppPool, set the Identity to ApplicationPoolIdentity and ManagedPipeLine to Integrated. On the actual web application, set to my new AppPool, I've set Windows Authentication to "Enabled", and tried ASP.Net Impersonation on both enabled and disabled
When I try calling the WCF service, it runs, but when it makes an actual call to a stored proc via Linq2SQL (to a database on a remote server using Trusted Security), I get the following error:
Login failed for user 'domain\ machinename$' - the machine name with a dollar sign at the end
which looks to me a lot like I've failed to delegate the correct identity (I can access the actual database fine through Management Studio.

Accessing your db shouldn't have anything to do with your WCF security settings. I would remove security settings from your binding config and also the impersonation setting in the system.web. You shouldn't need either of these.
Check your connection string settings in your config and make sure that if you are using Windows integrated security to access your db that you have the correct permissions on your database. IIS will attempt to connect to your database using the identity configured in the apppool so you need to make sure that account has access. If you have a named user, then make sure your credentials are set correctly. ConnectionStrings.com has various examples of how to set this correctly.
HTH.
Steve

Yes it is possible. In this case, you need to make sure your security setting is set to Windows (which is the default) and make sure your services are primed for impersonation. You can do this programmatically or declaratively.
You need to instruct WCF to allow impersonation for the service/method you want by setting the appropriate ImpersonationOption attribute to either required or allowed.
[OperationBehavior(Impersonation=ImpersonationOption.Allowed)]
Because you are accessing resources across the network, you need top make sure the impersonation level is set to delegate, not impersonate, unless the resources you're accessing are local. This is set at the client endpoint behaviour level.
<clientCredentials>
<windows allowedImpersonationLevel="[Impersonation or Delegate]"/>
</clientCredentials>

Related

Hosting WCF Apps IIS Authentication

I have written a WCF Service and need to host it, I can either host in IIS or Self-Host and I would like to use Windows Authentication by setting the bindings in the web.config file below:
<bindings>
<netHttpBinding>
<binding>
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</netHttpBinding>
</bindings>
I am trying to understand what IIS is doing in terms of authentication and passing it on to the web application, specifically:
If I host in IIS, do I need to enable Windows Authentication for the
service site in IIS administration settings?
If so, why can the service not perform Windows Authentication simply
from the config file just like self host - why does IIS need to get involved? Self host
doesn't need anything other than the web.config file.
Is there a way in IIS for the application (ASP MVC, WCF etc) to
handle authentication types (Forms, Windows Authentication, Basic)
without enabling them (reason being if the site is not configured
correctly it could be a security risk, if the code handles
authentication then the security intent becomes explicit)?
If I host in IIS, do I need to enable Windows Authentication for the service site in IIS administration settings?
Yes.
If so, why can the service not perform Windows Authentication simply from the config file just like self host - why does IIS need to get involved? Self host doesn't need anything other than the web.config file.
Because Windows Authentication is a feature. When it is installed, you can enable or disable this feature for particular site or service. Note, that Windows Authentication is not supported Home or Starter editions of Windows Vista® and Windows® 7.
IIS WCF host implementation is completely different from SelfHost implementation. And Windows Authentication feature is required to get things like setting security context identity (ServiceSecurityContext.Current.WindowsIdentity) or impersonating the caller (http://msdn.microsoft.com/en-us/library/ms788971(v=vs.110).aspx) to work on IIS WCF host.
Is there a way in IIS for the application (ASP MVC, WCF etc) to handle authentication types (Forms, Windows Authentication, Basic) without enabling them (reason being if the site is not configured correctly it could be a security risk, if the code handles authentication then the security intent becomes explicit)?
You must install feature before using it. There is no security risk because it just wouldn't work. For instance, if you configure your site or a service to use windows authentication, anonymous users won't get access to this site or service.
Check out this.
This gives all the details, follow this and i am sure you will get what you want.

WCF, IPC Named Pipes, ASP.NET, and <identity impersonate="true" />

We have a .NET 4.0 Windows Service that is hosting an endpoint over a Named Pipe (using IPC). This service is running under the context of User A.
We have an ASP.NET-hosted client that is requesting the operation that is exposed by the aforementioned service. This client runs under the context of User B (via Anonymous Access ,via <identity impersonate="true" />).
The problem:
If we use <identity impersonate="true" /> in our web.config (this cannot be changed), we get "Failed to connect to an IPC Port: Access is denied." exceptions when the client tries to call the hosted operation. If <identity impersonate... /> does not exist (perhaps by virtue of not using ASP.NET, say a client Console Application), we have no issue.
Does anyone out there know how to get this configuration working so we stop receiving Access Denied errors? It has something to do with authentication but we just can't work it out.
Recalling from 70-503: net.pipes only works with Windows security. It's obvious because the whole process (WCF) is on the current (Windows) machine only. ASP.NET runs under the credentials of a dedicated ASP.NET-user by default who's rights are strictly limited. I don't aspect the ASP.NET user having access to the current machine, accessing local files, net.pipes etc. It only has access to the folder your website runs from. So, by impersonating that very user is like ensuring having only the rights to run a website.
What you can do is impersonate to a specific Windows account who has the appropriate rights. This can be done using programmatic impersonation. Or use delegation. Read about it here to use the solution who fits best.
Not possible due to NetWorkService being restricted from seeing or accessing the pipe.
Answer here

How can I use Windows Authentication to allow group members access to my web application

I under stand how to configure .NET Authorization under Windows Authentication to limit access to a website to specific users and groups.
However, for a web application, how do I set the database connection to impersonate the logged in user? The SQl database is on another server.
If this strictly IIS configuration? Code? Both? For an individual, I can add the credentials via the <identity> element, but what about impersonating AD group members?
The SQL Server is set up to to only allow connections from a specific group. The DBA set this up, I do not know the details.
Setting
<identity impersonate="true" />
and Integrated Security=true results in the following error:
HTTP Error 500.24 - Internal Server Error
An ASP.NET setting has been detected that does not apply in
Integrated managed pipeline mode.
Using <identity impersonate="true" />
in your web.config along with Integrated Security=true; in your connection string should do this for you.
It will be up to the database to discover if the Active Directory User supplied is in the appropriate AD Group.

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

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

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

Resources