title: asp.net core 3 HTTP.SYS with SSL, Active Directory + Kerberos - struggling with SPN?
body: <p>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.</p>
  <p>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.</p>
  <p>Create:</p>
  <pre><code>    public static IHostBuilder CreateHostBuilder(string[] args)
      {
          return Host.CreateDefaultBuilder(args)
                     .ConfigureServices((hostContext, services) =&gt;
                     {
                         services.AddAuthentication(HttpSysDefaults.AuthenticationScheme);
                         services.AddHostedService&lt;Worker&gt;();
                     })
                     .ConfigureWebHostDefaults(webBuilder =&gt;
                     {
                         webBuilder.UseHttpSys(options =&gt;
                         {
                             options.Authentication.Schemes = AuthenticationSchemes.Basic | AuthenticationSchemes.Negotiate;
                             options.Authentication.AllowAnonymous = true;
                             options.UrlPrefixes.Add(&quot;https://*:20010/&quot;);
                         });
                         webBuilder.UseStartup&lt;Startup&gt;();
                     })
                     .UseWindowsService();
      }
  </code></pre>
  <p>Startup class:</p>
  <pre><code>public class Startup
  {
      public Startup(IConfiguration configuration)
      {
          Configuration = configuration;
      }
  
      public IConfiguration Configuration { get; }
  
      public void ConfigureServices(IServiceCollection services)
      {
          services.AddControllers().AddJsonOptions(opts =&gt;
          {
              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 =&gt;
          {
              endpoints.MapControllers();
          });
      }
  }
  </code></pre>
  <p>Controller:</p>
  <pre><code>[ApiController]
  [Route(&quot;test&quot;)]
  [Authorize]
  public class TestController : ControllerBase
  {
      [HttpGet(&quot;run&quot;)]
      public ContentResult Run()
      {
          return new ContentResult
          {
              Content = $&quot;Run Requested: {string.Join(&quot;,&quot;, this.User?.Identity?.Name, this.User?.Identity?.IsAuthenticated, this.User?.Identity?.AuthenticationType)}&quot;,
          };
      }
  }
  </code></pre>
  <p>I have paid for a proper certificate which I setup on port 20010 with netsh in a ps1 script:</p>
  <pre><code> $guid = [guid]::NewGuid()
   $certHash = &quot;&lt;CORRECT THUMBNAIL&gt;&quot;
   $ip = &quot;0.0.0.0&quot; # This means all IP addresses
   $port = &quot;20010&quot; # the default HTTPS port
   &quot;http add sslcert ipport=$($ip):$port certhash=$certHash appid={$guid}&quot; | netsh
  </code></pre>
  <p>The Webserver:</p>
  <ul>
  <li>properly joined to the domain</li>
  <li>netbios name: mywebserver</li>
  <li>full name: mywebserver.ad.mydomain.com</li>
  </ul>
  <p>The service:</p>
  <ul>
  <li>.net core 3.1</li>
  <li>running under domain account 'myserviceaccount'</li>
  </ul>
  <p>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.</p>
  <p>The active directory:</p>
  <ul>
  <li>ad.mydomain.com</li>
  <li>server netbios name: domainserver</li>
  <li>server full name: domainserver.ad.mydomain.com</li>
  </ul>
  <p>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.</p>
  <p>I have tried to set the following SPNs on the web server:</p>
  <p>setspn -S HTTP/mywebserver.ad.mydomain.com:20010 MYDOMAIN\mywebserver</p>
  <p>setspn -S HTTPS/mywebserver.ad.mydomain.com:20010 MYDOMAIN\mywebserver</p>
  <p>setspn -S HTTP/mywebserver.ad.mydomain.com:20010 MYDOMAIN\myserviceaccount</p>
  <p>setspn -S HTTPS/mywebserver.ad.mydomain.com:20010 MYDOMAIN\myserviceaccount</p>
  <p>I made sure to restart the service each time I tried a new SPN, and fully close down all browsers.</p>
  <p>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.</p>
  <p>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.</p>
  <p>Can anyone help me get over the line? Thanks in advance!</p>