-
Notifications
You must be signed in to change notification settings - Fork 25.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WinAuth] Clarify app configuration and deployment #12144
Comments
Thanks for the report @bdlane ... I think we need to clarify something in the topic for sure (at least for the time being): "development-side configuration" doesn't address running the project on the development machine with IIS Express. It only addresses setting up the project for WinAuth while it's on the development machine so that when it's deployed to an IIS production environment it has the web.config with the correct settings for WinAuth. The next section, Publish and deploy your project to the IIS site folder probably adds to the confusion because although it speaks to deployment (to an IIS site folder) it immediately says to "launch the app." It could be clarified a bit further: It really means deploy the app to the IIS production environment ... then run it. Anyway ... Yes! ... you probably do need to modify applicationHost.config on the local machine for it to work with IIS Express. Those sections are locked by default. But again, the topic isn't trying to explain how to run the app locally that way ... perhaps it should ... but it doesn't today. @Tratcher What direction would you like to take:
|
If I may add a couple points. Setting up in the web.config file also does not make the current session user ie: WindowsIdentity.GetCurrent().Name equal the Context.User.Identity.Name. The WindowsIdentity.GetCurrent() is equal to the computer / account used to run the website in IIS. The forced way for my SQL queries to run under the Context.User is to do a WindowsIdentity.RunImpersonated on the User accesstoken. I would prefer to avoid that and just have the imperonated setting set to true in the web.config |
@Nitro66215 Engineering approved what's in the topic. They'll respond here when they see your post. Right now, this is the approved guidance for that ... https://docs.microsoft.com/aspnet/core/security/authentication/windowsauth#impersonation ... i.e., so far, they're saying don't do it app-wide ...
|
Running impersonated as the user has many side effects and should be avoided where not absolutely necessary for outbound IO. It's also not practical until .NET Core supports proper async impersonation. https://github.com/dotnet/corefx/issues/24977 |
Understand. This is not application wide. Only on the calls to SQL. However, this is also in a separate class that the calls to SQL are being done. HttpContext is passed in. However, I'm still running into the User.Identity being looked at as the host computer and not the windows user on the published application. Running locally under debug it operates as it should. |
HttpContext.User.Identity is the host computer account? That's not something ASP.NET would do. User.Identity is either anonymous or the client identity. Is this a second tier request being made from another server endpoint? In that case it was the machine account that made the request. Debugging locally IIS Express runs as the current user. |
I misspoke. That was something else I must have done before. Currently the WindowsIdentity.GetCurrent().Name is coming up as NT AUTHORITY\NETWORK SERVICE. When it hits the class module with the referenced httpContext, the RunImpersonated section gets NT AUTHORITY\ANONYMOUS LOGON from httpContext.User.Identity. On the page itself, Context.User.Identity.Name is correctly showing the currently logged in windows user. |
Can you show how you did the impersonation? It's also possible you don't have permissions to impersonate (though I'd expect that to cause an error). What does ImpersonationLevel for the HttpContext identity say? |
Without giving too much code... the basics... class module is a static reference in the HomeController. when the call is made to hit SQL with the required params... var user = (WindowsIdentity)_classModule._httpContext.User.Identity; The impersonationlevel shows "None" |
impersonationlevel was checked on None doesn't make sense, you should always get at least Identification for an authenticated user. |
There has to be something misconfigured somewhere. Running the website from the computer that hosts the IIS website, the SQL Run impersonated seams to act correctly. When I run the website from a different computer connecting to it over the network, It has IIS APPPOOL\Website- None and Domain\User (me). However, the run impersonate code fails with Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'. So it hits SQL with the wrong login. |
What is Context.User.Identity's ImpersonationLevel? |
it shows "None" as well on the _Layout.... @(((WindowsIdentity)Context.User.Identity).ImpersonationLevel.ToString()) |
I tried that with "identity impersonate="true"" in web.config as well as it removed from web.config (ASP.NET Imperonation = Disabled in IIS) |
Ok, something is very wrong with this setup if ImpersonationLevel consistently reports None for Context.User.Identity. At this point I can only suggest creating a minimal application with nothing but default "Empty" template content and trying to get that working in your server. |
[EDIT by @guardrex to format code blocks] OK. Basic WebApplication1 with WindowsAuthentication. Added to _Layout... <a class="label label-info">@WindowsIdentity.GetCurrent().Name.ToString() - @WindowsIdentity.GetCurrent().ImpersonationLevel.ToString()</a> and <a class="label label-info">@Context.User.Identity.Name.ToString() - @(((WindowsIdentity)Context.User.Identity).ImpersonationLevel.ToString())</a> Both show None for Impersonation Level. Created web.config in the application... <?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<security>
<authentication>
<windowsAuthentication enabled="true" authPersistNonNTLM="true"></windowsAuthentication>
</authentication>
</security>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" hostingModel="InProcess">
<environmentVariables>
<environmentVariable name="ASPNETCORE_HTTPS_PORT" value="44316" />
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</location>
<system.web>
<authorization>
<deny users="?" />
</authorization>
<identity impersonate="true" />
</system.web>
</configuration> Startup.cs using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Server.IISIntegration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace WebApplication1
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
} |
Outside of "RunImpersonated"... the Impersonation Level is always None. Within RunImpersonated - The ImpersonationLevel is showing Impersonated. var identity = WindowsIdentity.GetCurrent();
HttpContext.Session.SetString("CurUser", identity.Name);
HttpContext.Session.SetString("CurImpLevel", identity.ImpersonationLevel.ToString());
var user = (WindowsIdentity)HttpContext.User.Identity;
WindowsIdentity.RunImpersonated(user.AccessToken, () =>
{
HttpContext.Session.SetString("ImpUser", WindowsIdentity.GetCurrent().Name);
HttpContext.Session.SetString("ImpLevel", WindowsIdentity.GetCurrent().ImpersonationLevel.ToString());
}); _Layout change.... <a class="label label-info">@Context.Session.GetString("CurUser").ToString() -@Context.Session.GetString("CurImpLevel").ToString()</a>
<a class="label label-info">@Context.Session.GetString("ImpUser").ToString() -@Context.Session.GetString("ImpLevel").ToString()</a> |
@Nitro66215 ... Edit the post that I updated to see how to format your code blocks. |
Better? |
Now if this isn't messed up..... I added a helper class to get HttpContext.Current. namespace System.Web
{
public static class HttpContext
{
private static Microsoft.AspNetCore.Http.IHttpContextAccessor m_httpContextAccessor;
public static void Configure(Microsoft.AspNetCore.Http.IHttpContextAccessor httpContextAccessor)
{
m_httpContextAccessor = httpContextAccessor;
}
public static Microsoft.AspNetCore.Http.HttpContext Current
{
get
{
return m_httpContextAccessor.HttpContext;
}
}
}
} added to Startup.cs System.Web.HttpContext.Configure(app.ApplicationServices.
GetRequiredService<IHttpContextAccessor>()
); within my SQL class module.. wrapped around the call to SQL as well as the error trapping.... var user = (WindowsIdentity)System.Web.HttpContext.Current.User.Identity;
WindowsIdentity.RunImpersonated(user.AccessToken, () =>
{
try
{
System.Web.HttpContext.Current.Session.SetString("ImpUser", WindowsIdentity.GetCurrent().Name);
System.Web.HttpContext.Current.Session.SetString("ImpLevel", WindowsIdentity.GetCurrent().ImpersonationLevel.ToString());
...... in _Layout ... <a class="label label-info">
@{ if (@System.Web.HttpContext.Current.Session.GetString("ImpUser") != null)
{@System.Web.HttpContext.Current.Session.GetString("ImpUser").ToString()} } -
@{ if (@System.Web.HttpContext.Current.Session.GetString("ImpLevel") != null)
{@System.Web.HttpContext.Current.Session.GetString("ImpLevel").ToString()} }
</a> The ImpUser is the Domain\User that is logged in. And ImpLevel is showing Impersonation. |
@Tratcher I'm up to this one now. I'm planning to clarify that the topic is only seeking to get the app configured for WinAuth on the server ... not run it under IIS Express (e.g., unlock config via applicationHost.config for example). Also, I wasn't planning on making significant changes to how impersonation is described today. Is that what we're going with (at least for now)? Alternatively, do you want to expand into IIS Express coverage? ... what about updates for impersonation? If you wish more work on either (or both) of those, I'm going to schedule for June. I'm 🏃😅 at the moment. Minutes for this today is OK ... hours ... not OK. 😄 |
Yeah, don't ever touch VS's applicationHost.config, use the VS UI to enable windows auth. The impersonation doc seems OK for now. The remainder seems to be a SQL issue. You could ask someone from EF about that. |
@Nitro66215 Since that's (for now anyway) an issue outside of our doc set, I'll refer you to the EF Core GH repo issues to open an issue there. If you (and/or they) find some Core-to-EF interaction that we need to cover here, please do let us know about it. For now on this issue, I'm going to work on our development-side language (VS UI for WinAuth and what the topic says about development-side configuration with web.config). I'll also fix a content layout problem described on #12102. The EF Core repo issues for the SQL/EF issue that you described 👉 https://github.com/aspnet/EntityFrameworkCore/issues [EDIT] Indeed ... I think I see where things are a bit dicey. The key content is here, but it's a bit misleading: The VS property page (or a new app from the template) only affects the launch settings. The dev must configure IIS (on the server) or supply the web.config for published output with the proper settings. The topic has all of this content, but it looks like some minor clarifications are in order. [EDIT 2] I'm going to assume that VSC behaves the same way as VS when it uses the launchSettings.json configuration for debugger runs. |
@guardrex Thanks. I did add the Auth startup.cs code. What I've learned is that it seams to be a "double" (for lack of brainpower at the moment) authentication issue. IIS is seeing the user as the impersonated user when "RunImpersonated" is used. However, SQL within that RunImpersonated does not see them. Another forum / website mentioned using Negotiate:Kerberos. When setting that as the Top Level provider in IIS, IE and Edge work when SQL is called within the RunImpersonated code. However, Chrome does not like it. |
There was also an article about having AD permissions set for the Computer Account. The Computer Account must have Delegation allowed. |
@Tratcher This is the first feedback that I recall seeing in this vein. I defer to you on when/how/what to cover, if anything. I'll definitely keep an 👂 out for more feedback that matches @Nitro66215's experience and scenario. |
Ah, yes, Kerberos Delegation is a thing, but it's well outside the scope of these docs. That needs to be configured on your domain controller and isn't the sort of thing the average web dev has access to. |
This comment has been minimized.
This comment has been minimized.
Is there not something in the RunImpersonate code that needs to be done in order to allow that second "hop" to SQL? Or is that an inherent IIS issue? |
Without delegation permissions granted on the domain controller, there's nothing your app can do (See ImpersonationLevel). This is a Windows thing, not an IIS thing. (Note for future reference: we're adding Linux Kerberos support in 3.0 but delegation and impersonation are Windows specific concepts.) Aside from that, we need to confirm with the EF folks if any extra steps are required. @divega |
Got it. And Chrome not working? Is that just something that is disabled, or windows specific? |
@Tratcher can you please point me to specific comments I can read to get some context on what the question is about? Thanks! |
@divega sorry, nevermind. I re-read #12144 (comment) and they got it working without any EF changes. |
No worries @Tratcher! |
Adding the web.config with the authentication elements causes a configuration error at runtime.
Starting from the 'Web Application' template in the new project dialog in Visual Studio 2019, with Windows Authentication enabled, I can run and debug the project fine.
Then, following the steps outlined in the 'Development side configuration with a local web.confg' section (i.e. adding a web.config file with the <system.webServer><security><authentication> tags), running the project returns a HTTP 500.19, with the following config error:
You can fix the problem by modifying the applicationHost.config file in the solution's .vs directory to unlock the relevant sections. However,
Is this the expected behaviour?
Document Details
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
The text was updated successfully, but these errors were encountered: