AspNetWindowsAuthProvider available in dotnetcore?

Hi. I’m working on a new dotnetcore 2.1 product using ServiceStack, and the client ultimately insists on using NTLM auth on their intranet. All code / projects are written in NETCORE for APIs/Tests and Standard for libraries, with no .NET Framework being used thus far. For development purposes we are using kestrel but the product will ultimately be deployed behind IIS.

So my question is, is the AspNetWindowsAuthProvider available when running a dotnetcore project, in particular for SS v5+?

That provider is not included in the list of unsupported features, (http://docs.servicestack.net/netcore#servicestack-features-that-wont-be-supported-in-net-core) but whenever I try to include that provider in my solution, i see only a nuget package v4.5.4 as an option in the nuget package search, and viewing the source code on Github, I see that the provider seems to be explicitly excluded in STANDARD (https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack/Auth/AspNetWindowsAuthProvider.cs)

I have read the following, but am not sure whether it directly relates to my issue? (.Net Core Service Stack API reference a CredentialsAuthProvider from a .Net Framework 4.5 API project)

I hoping I can avoid .NET Framework and keep everything in NETCORE but it looks like I might have to mix-n-match the two, or even revert to .NET Framework?

I have done a bit more digging, and it seems that Kestrel doesnt support NTLM but I can try Http.Sys (which I have never seen before) for our local development at least… but the article I am referencing (https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-2.1) is probably more about webapi, so has anyone ever tried NTLM with SS in NETCORE? I have no idea what I might do to get these SS + NLTM to play nicely , so would very much appreciate any suggestions.

No, anything that uses classic ASP.NET System.Web Types can’t be used in .NET Core. If needing to use NTLM the easiest solution would be to use ASP.NET Framework. Creating a separate Auth Server as mentioned in JWT docs to issue JWT tokens may be an option if you wanted to keep everything else .NET Core.

1 Like

@daleholborow, I agree that separating the auth server and using JWT is probably the cleanest .Net Core way to do this.

That said, I did try to implement the provider in .NET core here, but that’s a very buggy impl (for various reasons, biggest of which is that it depends on having the IHttpContext accessor, which you shouldn’t enable for performance reasons). I only link to it in case a separate server isn’t an option and you want to stay on .NET core (and can fix the issues with my code).

2 Likes

@jrodrigu: thanks, I’ll check it out! Unfortunately ntlm is a strict requirement, one of the few concrete requirements of the system that I have :stuck_out_tongue: so no jwt for me

You mention that this is buggy - I’ll try it out today, but what bugs in particular did you encounter?

I’d get occasional timeouts on requests. Sometimes the request wouldn’t auth at all. I didn’t dig too deep though, because everyone seems to be moving away from traditional auth like this, and tabled the issue until I had time to properly build a JWT auth server.

I also don’t claim to have a full grasp of the .NET Core Auth schemes, so it’s quite possible I did something wrong. I’m including the other relevant bits you might need:

Here’s my ConfigureServices in my Startup class:

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(IISDefaults.AuthenticationScheme);
            services.Configure<IISOptions>(options => { options.AutomaticAuthentication = true; });
            services.AddHttpContextAccessor(); // Performance penalty
        }

(and here’s the auth section of my Configure (note that I have a custom populate roles section that uses the Active Directory groups included as part of the WindowsIdentity to populate roles)

 Plugins.Add(new AuthFeature(() => new AuthUserSession(),
                    new IAuthProvider[]
                    {
                        new AspNetCoreWindowsAuthProvider(this)
                        {
                           AllowAllWindowsAuthUsers = true,
                           PopulateUserRoles = (request, user, session) =>
                           {
                               var userId = user.Identity as WindowsIdentity;
                               var roles = new List<string>();
                               if (userId != null)
                                   foreach (var group in userId.Groups)
                                   {
                                       // Remove the domain name from the group,
                                       var groupName =
                                           new SecurityIdentifier(group.Value)
                                               .Translate(typeof(NTAccount))
                                               .ToString();
                                       if (groupName.Contains("\\"))
                                           groupName = groupName.Split('\\')[1];
                                       roles.Add(groupName);
                                   }

                               session.Roles = roles;
                           }
                        }
                    }){HtmlRedirect = null});

@jrodrigu Hey mate, champion effort for this. I actually just used your Authenticator plugin class code (copy and paste) , add this line to the Startup.ConfigureServices,

public void ConfigureServices(IServiceCollection services) {
// Comes with non-trivial performance effects, but we need this for NTLM auth
// See: https://github.com/aspnet/Hosting/issues/793?WT.mc_id=-blog-scottha
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}

, turned on Http.Sys as the webserver instead of Kestrel (because I run using IIS instead of IISExpress because IISExpress seems to crash a lot of me, and Kestrel doesnt support NTML), and it … seems to… just work?! :smiley:

To outline my steps, I patched Program.BuildWebHost to be:

	/// <summary>
/// Following instructions here: https://stackify.com/how-to-deploy-asp-net-core-to-iis/
/// To run under IIS, make sure you:
///   -- Install .NET Core Windows Server Hosting Bundle (https://go.microsoft.com/fwlink/?linkid=844461)
///   -- If you get errors about "500.19 module, your webconfig is invalid", you might need to install
/// the HttpPlatformHandler is a new component that connects IIS with your ASP.NET Core application. Go:
/// http://go.microsoft.com/fwlink/?LinkID=690721
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public static IWebHost BuildWebHost(string[] args)
{
	return new WebHostBuilder()

		// 28.08.2018 D.Holborow notes: Originally for development purposes we used either IISExpress OR Kestrel.
		// However, Kestrel does not support NTLM Auth, so investigations revealed that to enable NTLM in .NETCORE,
		// one should instead use the HttpSys webserver, as per the documentation link.

		// 28.08.2018 D.Holborow : *commented out the use of Kestrel*
		// Next line registers the IServer interface for Kestrel as the server that will be used to host your application.
		// In the future, there could be other options, including WebListener which will be Windows only.
		//      .UseKestrel()

		//// 28.08.2018 D.Holborow : Http.Sys is the rebranded name of WebListener, I believe. Use this webserver instead
		//// so that we can access NTLM authentication.
		//// See https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-2.1#enable-windows-authentication-with-httpsys
		.UseHttpSys(options =>
		{
			options.Authentication.Schemes = AuthenticationSchemes.NTLM | AuthenticationSchemes.Negotiate;
			options.Authentication.AllowAnonymous = false;
		})
                    .etc .... 

I haven’t thrashed it extensively yet, so I cannot confirm that its 100% rock solid, but its definitely looking promising.

If i switch to IISExpress, that DOES seem to support NTLM out of the box as well, so the Kestrel->HttpSys change is not required (note: IISExpress seems to crash when HttpSys is used, so the choice is IISExpress+Kestrel OR IIS+HttpSys).

I’ll edit your authenticator class, because as you note, your network-based roles etc are irrelevant for me, but still -> this saved my bacon!

@mythz its worth noting that .NETCORE does seem to have the capability to support NTLM now (for all us devs stuck with Luddite customers :wink: ), so I might try to write up a blog post or something at some point, or you can drop it into your support notes somewhere.

Great, I’m glad this helped. Maybe my issues were IIS Express issues after all (I think I really only tested on my dev box), I might give this another shot as a transition step prior to moving into the modern auth world :smile:

For those reading this thread and wanting this to be formally supported, I do have a UserVoice for this. I think most people who need this would be willing to accept the performance hit with HttpContextAccessor, or perhaps someone can think of a way to use this without that dependency.

Regarding the perf hit, it’s not a concern in my tiny low traffic project so I did no benchmarks, but I actually read on one of the dotnet Dev forums that it’s not actually even that bad, it’s more “why would you bother taking the hit unless you need it”, so maybe it’s not something to be too stressed about.

Maybe :smiley: