4

I work for a large company with an intranet and Windows AD logins for everyone. We have a number of internal SQL Server databases which allow us to log in using Windows authentication, one of which I'm trying to connect to through an ASP.NET Core application. I can connect to this database through SQL Server Management Studio and query the tables fine.

I've followed the tutorial for an ASP.NET Core app using an existing database as closely as I possibly could, and created a single model class to test with to see if I could read data from the database. When debugging with IIS Express in Visual Studio, I can read data from the database when accessing the auto-generated controller and views.

Everything seems fine when debugging, but when publishing to IIS, I receive the following error:

SqlException: Login failed for user '<DOMAIN>\<COMPUTERNAME>$'.

Where domain is my domain and computername is my computer's name. This is expected, since my computer itself doesn't have access to the database. But it shouldn't be trying to connect using that system account (with the dollar sign), it should be trying to connect with my windows account: <DOMAIN>\<USERNAME>.

What's weirder, the app does seem to recognize my Windows credentials in some capacity - when I access the home page, I get the familiar "Hello, <DOMAIN>\<USERNAME>!" message in the nav bar. So the Windows credentials are definitely getting passed through to the app, but for some reason not getting passed through when trying to connect to the database through DbContext.

Am I missing something obvious here?

My Code

I started with Visual Studio's ASP.NET Core Web Application template.

In launchSettings.json, I have:

  "iisSettings": {
    "windowsAuthentication": true, 
    "anonymousAuthentication": false, 
    "iisExpress": {
      "applicationUrl": "http://localhost:60686",
      "sslPort": 44336
    }
  },

In appsettings.json, I have:

  "ConnectionStrings": {
    "MyDB": "Server=<servername>;Database=<dbname>;Trusted_Connection=True;"
  },

In Startup.cs, I have the following line in ConfigureServices

            services.AddDbContext<MyContext>(options => {
                options.UseSqlServer(Configuration.GetConnectionString("MyDB"));
            });

And from there, I have scaffolded an MVC controller with views using Entity Framework.

IIS has Windows authentication set to Yes and anonymous authentication set to No. My application pool is set to No Managed Code with ApplicationPoolIdentity.

Edit: The problem

To state the actual problem I'm trying to solve, I have a SQL Server database on a remote intranet server which allows access to a subset of the whole company via Windows authentication. If I want to create an ASP.NET application to provide an API to that database, hosted by IIS, what's the best way to do this? Assuming:

  1. I don't want to have to manage permissions myself or have to duplicate them in some way
  2. The people who have access to the database directly should have access to the API, the people who don't should not.
  3. If they're accessing it from within the intranet while logged in to Windows, they shouldn't have to log in again.

I assumed I could just pass their windows credentials from IIS through the app to SQL server but I'm starting to wonder if that's actually the case.

Aias
  • 161
  • 1
  • 8
  • where are you deploying your app to? have you tried connecting to sql server from the machine you are deploying your app to? is SSMS on that machine? – John-Luke Laue Jan 22 '19 at 23:11
  • I would remove the "Trusted_Connection=True" setting, as this is providing the machine's credentials. I have not heard of credentials passing through from IIS->ASP->SQL Server. Seems like you'll need to provide some credentials at some point. – Scott Hoffman Jan 22 '19 at 23:17
  • Currently I'm deploying it to IIS on my local machine. I've tried both file system deployment and webdeploy. – Aias Jan 22 '19 at 23:18
  • You might try using NetworkService instead of ApplicationPoolIdentity. If that doesn't work...setup a database user and provide credentials - just as a sanity check – John-Luke Laue Jan 22 '19 at 23:43
  • “But it shouldn't be trying to connect using that system account (with the dollar sign), it should be trying to connect with my windows account: \.” I don't know from where you get that misunderstanding. https://blog.lextudio.com/web-application-differences-in-visual-studio-and-iis-60fec7e311b3 – Lex Li Jan 22 '19 at 23:49
  • @Lex Li - I guess I'm missing the point then, because the IIS authentication mode is set to Windows, and the web app can see my Windows username, and the app's SQL server connection strings are set to use trusted connection, but for some reason the app can't use that to connect to SQL server? What's the best practice for this situation then, if I want to let intranet users be able to query the database? – Aias Jan 23 '19 at 05:16
  • 1
    My understanding is that your database connection will be made with the application pool identity (which I guess defaults to \$). I believe you need to use "Impersonation" to get it to use your loggged on user https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc730708(v=ws.10) – Nick.Mc Jan 23 '19 at 09:14

4 Answers4

2

After learning more about .NET and what Windows auth actually does on IIS, I'm going to say that what I was trying to do is not recommended. There is a difference between passing windows credentials to a .NET app in order to read from them, vs. actually executing a secondary process as that user. The latter case is what I was trying to do, but instead should set up my app pool in IIS with a user who can log in to the database, and use the windows credentials to verify against the list of users who have access.

Aias
  • 161
  • 1
  • 8
  • Do you have a guide / reference of what you actually did (setting up app pool, etc.)? – krismath Apr 10 '20 at 03:05
  • Hi, @Aias I am kind of struggling with hosting asp.net core web app in IIS with windows APP and I am badly stuck. I have answered the question [here](https://stackoverflow.com/questions/63213584/windows-authentication-does-not-work-on-iis-with-asp-net-core). Looks like you were able to achieve this. Can you please help me in this regard? Please post an answer to this question if you know how to solve this. Feel free to comment if you need any more detail. – Chetan Sep 12 '20 at 14:27
1

You are using Entity-Framework for SqlServer and EF is using ADO.NET SqlClient. Therefore Trusted_Connection=yes; does not work.

Add Integrated Security=true; instead and it should be fixed.

Here some resources to read about it https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/connection-string-syntax

alsami
  • 8,996
  • 3
  • 25
  • 36
  • Unfortunately, switching the connection Integrated Security=true didn't work. Still getting the same error where it's trying to connect using my computer's built-in account rather than my actual windows user. This only happens when hosted in IIS, not during development when debugging with IIS Express. – Aias Jan 23 '19 at 16:34
  • I tried the suggestion of @johnluke.laue above, using a named user and password to log in to SQL Server instead, and it worked. So that at least provided a sanity check. Using NetworkService instead of ApplicationPoolIdentity doesn't help. – Aias Jan 23 '19 at 16:37
0

Not to dig up an old thread, but this is a function that should work as long as Identity Impersonate = True is set. Here's some stuff being worked on.

GitHub Doc

Community
  • 1
  • 1
1SG Nitro
  • 23
  • 1
  • 5
0

I'll add my answer because this is how I fixed this issue.
The reason a "$"-sign is added to the login name/user must have something to do with the IIS that the application is being hosted on.

I'm not an expert on any of this, so I can't really go in-depth, but I've added the IIS user to the Logins and then it works.

USE [master]
GO

CREATE LOGIN [IIS APPPOOL\'name'] FROM WINDOWS WITH DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[us_english]
GO

ALTER SERVER ROLE [sysadmin] ADD MEMBER [IIS APPPOOL\'name']
GO

ALTER SERVER ROLE [securityadmin] ADD MEMBER [IIS APPPOOL\'name']
GO

ALTER SERVER ROLE [serveradmin] ADD MEMBER [IIS APPPOOL\'name']
GO

ALTER SERVER ROLE [setupadmin] ADD MEMBER [IIS APPPOOL\'name']
GO

ALTER SERVER ROLE [processadmin] ADD MEMBER [IIS APPPOOL\'name']
GO

ALTER SERVER ROLE [diskadmin] ADD MEMBER [IIS APPPOOL\'name']
GO

ALTER SERVER ROLE [dbcreator] ADD MEMBER [IIS APPPOOL\'name']
GO

ALTER SERVER ROLE [bulkadmin] ADD MEMBER [IIS APPPOOL\'name']
GO  

You have to change 'name' to your IIS hosted application name. So for example if you app/site's name in ISS is "My-Backend-App" you should do:

CREATE LOGIN [IIS APPPOOL\My-Backend-App] FROM WINDOWS ...  

So all the names should be "My-Backend-App".

When adding this user to the logins, my backend application could access & create the DB, create tables, access data etc...

SIDENOTE: I've used the Windows Event logger to find out this was my issue. My application just crashed, said a "500.30" error but no real information given.

You can access the "Event Viewer" application from Windows Search. Then you can go to "Applications" and there are all application errors/crashes that occured on your machine, and in this case also the reason why. It said it couldn't find user "myUser$" while trying to login to SQL, but the Windows Authentication user was "myUser". So for some reason it added a "$"-sign and couldn't log in. My fix above fixes this issue and you can login etc.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Tempuslight
  • 1,004
  • 2
  • 17
  • 34