asp.net core 3 HTTP.SYS with SSL, Active Directory + Kerberos - struggling with SPN?

558 views Asked by At

I'm trying to run a net core 3 API as a windows service (i.e. not using IIS) with Http.Sys authenticating accounts on an active directory. I would like to have Basic auth enabled (have to support non .NET languages where developers have requested basic auth) but allow windows/kerberos where available.

I am most of the way there, in fact I basically have a service that does everything that I want, except for 1 thing - I only see NTLM being used instead of kerberos. I could potentially go to prod as it is but I'd like to understand why I can't get kerberos working. I believe the final piece is the SPN.

Create:

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        return Host.CreateDefaultBuilder(args)
                   .ConfigureServices((hostContext, services) =>
                   {
                       services.AddAuthentication(HttpSysDefaults.AuthenticationScheme);
                       services.AddHostedService<Worker>();
                   })
                   .ConfigureWebHostDefaults(webBuilder =>
                   {
                       webBuilder.UseHttpSys(options =>
                       {
                           options.Authentication.Schemes = AuthenticationSchemes.Basic | AuthenticationSchemes.Negotiate;
                           options.Authentication.AllowAnonymous = true;
                           options.UrlPrefixes.Add("https://*:20010/");
                       });
                       webBuilder.UseStartup<Startup>();
                   })
                   .UseWindowsService();
    }

Startup class:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers().AddJsonOptions(opts =>
        {
            opts.JsonSerializerOptions.IgnoreNullValues = true;
            opts.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

Controller:

[ApiController]
[Route("test")]
[Authorize]
public class TestController : ControllerBase
{
    [HttpGet("run")]
    public ContentResult Run()
    {
        return new ContentResult
        {
            Content = $"Run Requested: {string.Join(",", this.User?.Identity?.Name, this.User?.Identity?.IsAuthenticated, this.User?.Identity?.AuthenticationType)}",
        };
    }
}

I have paid for a proper certificate which I setup on port 20010 with netsh in a ps1 script:

 $guid = [guid]::NewGuid()
 $certHash = "<CORRECT THUMBNAIL>"
 $ip = "0.0.0.0" # This means all IP addresses
 $port = "20010" # the default HTTPS port
 "http add sslcert ipport=$($ip):$port certhash=$certHash appid={$guid}" | netsh

The Webserver:

  • properly joined to the domain
  • netbios name: mywebserver
  • full name: mywebserver.ad.mydomain.com

The service:

  • .net core 3.1
  • running under domain account 'myserviceaccount'

The service account 'myserviceaccount' currently has admin privs on the web server, I think I can remove that if I grant permissions to the certificate directly to this account. Or perhaps to get this all working I have to run it as a system account? Prefer not to do this though.

The active directory:

  • ad.mydomain.com
  • server netbios name: domainserver
  • server full name: domainserver.ad.mydomain.com

As is, this works fine with all browsers/OS and from all languages that are set to use the service. It challenges correctly, allows domain users through and shows the proper certificate. But as stated above, when I use various auth testers/fiddler etc - it only shows NTLM when accessing from windows clients.

I have tried to set the following SPNs on the web server:

setspn -S HTTP/mywebserver.ad.mydomain.com:20010 MYDOMAIN\mywebserver

setspn -S HTTPS/mywebserver.ad.mydomain.com:20010 MYDOMAIN\mywebserver

setspn -S HTTP/mywebserver.ad.mydomain.com:20010 MYDOMAIN\myserviceaccount

setspn -S HTTPS/mywebserver.ad.mydomain.com:20010 MYDOMAIN\myserviceaccount

I made sure to restart the service each time I tried a new SPN, and fully close down all browsers.

I don't know if these are correct (I'm assuming they're not since it falls back to NTLM!). I am not sure if I should be setting these on mywebserver or domainserver.

I have tried setting the scheme to AuthenticationSchemes.Kerberos only as a test, but when I do this I get no response from the server at all.

Can anyone help me get over the line? Thanks in advance!

0

There are 0 answers