aspnet / HttpSysServer

[Archived] A web server for ASP.NET Core based on the Windows Http Server API. Project moved to https://github.com/aspnet/AspNetCore
Apache License 2.0
106 stars 39 forks source link

WebListener Negotiate auth doesn't work with non-machine account #333

Closed davidmatson closed 6 years ago

davidmatson commented 7 years ago

I was using Web API with the OWIN HttpListener running as a Windows service with a domain service account. I configured the SPN so Kerberos authentication was working successfully.

When I switched to ASP.NET Core with WebListener, Negotiate authentication worked during initial testing that used the machine name as the site name and ran the service under the system account. However, once I switched into production mode using the production site name and production service account, Negotiate authentication stopped working.

I was able to workaround by using the old OWIN HttpListener server in place of WebListener:

using System;
using System.Collections.Generic;
using System.Net;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Owin;
using Microsoft.Owin.Host.HttpListener;

namespace Servers
{
    public class HttpListenerServer : IServer
    {
        readonly IFeatureCollection features = new FeatureCollection();
        readonly IDictionary<string, object> properties = new Dictionary<string, object>();

        IDisposable server;

        public HttpListenerServer()
        {
            features.Set<IServerAddressesFeature>(new ServerAddressesFeature());
        }

        public IFeatureCollection Features => features;

        public void Start<TContext>(IHttpApplication<TContext> application)
        {
            OwinServerFactory.Initialize(properties);

            var addressesFeature = features.Get<IServerAddressesFeature>();

            var addressList = new List<IDictionary<string, object>>();

            foreach (var address in addressesFeature.Addresses)
            {
                Uri uri = new Uri(address);

                addressList.Add(new Dictionary<string, object>() {
                    { "scheme", uri.Scheme },
                    { "host", uri.Host },
                    { "port", uri.Port.ToString() },
                    { "path", uri.AbsolutePath }
                });
            }

            properties["host.Addresses"] = addressList;

            HttpListener listener = (HttpListener)properties["System.Net.HttpListener"];
            listener.AuthenticationSchemes = AuthenticationSchemes.Negotiate;

            server = OwinServerFactory.Create(async (environment) =>

            {
                TContext context = application.CreateContext(new FeatureCollection(new OwinFeatureCollection(environment)));

                try
                {
                    await application.ProcessRequestAsync(context);
                }
                catch (Exception exception)
                {
                    application.DisposeContext(context, exception);
                    throw;
                }

                application.DisposeContext(context, null);
            }, properties);
        }

        public void Dispose()
        {
            server.Dispose();
        }
    }
}

With the exact same configuration and using the production service account, I tried running the Web API exe (using OWIN HttpListener), and auth worked. I switched to ASP.NET Core using WebListener, and auth stopped working. I switched to using OWIN HttpListener within ASP.NET Core, and auth started working again, so I believe the problem is in WebListener.

Does WebListener (HttpSysServer) set the SPN on the server side the same way HttpListener did? That's my best guess for where the bug would be.

Tratcher commented 7 years ago

This behavior is different because WebListener uses the kernel mode http.sys auth (running as the machine account), where HttpListener implemented this in user mode. It's not clear if you'd be able to get the old behavior.

davidmatson commented 7 years ago

Is it possible to set the SPN when using kernel mode auth? Otherwise, is the fix to to switch to user mode auth?

Thanks,

David

Tratcher commented 7 years ago

https://blogs.msdn.microsoft.com/amol/2010/10/29/understanding-kernel-mode-authentication-in-iis-7/ https://github.com/aspnet/HttpSysServer/issues/42 It sounds like UseAppPoolCredentials maps to HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL and would be one way of enabling this.

strabu commented 6 years ago

Hey guys, we are running into the same problem with Kerberos-Authentication. We have a Windows on premises Service Fabric Cluster with an Asp.Net Core Web API/WebListener running on all cluster-nodes. HTTP-Traffic is distributed via DNS round-robin across the nodes. We can't use the machine-account for the spn in our scenario because it would tie our public URL to only one of the cluster nodes.

There is a support ticket open at MS: REG:117103016576681

I hope you'll be able to focus on that Issue soon because we can't go-live without appropriate Authentication in place.

Thanks, Alex

davidmatson commented 6 years ago

@strabu This bug has been open for a while, so I wouldn't tend to expect an immediate solution. A workaround such as the code above may be your best option for go-live (it's what I had to do to unblock moving to ASP.NET Core for our service).

muratg commented 6 years ago

Bringing this back to triage.

muratg commented 6 years ago

Triage decision: We only support kernel mode NTLM, we don't plan to support user mode.

davidmatson commented 6 years ago

If you could provide information about future plans of HttpListener vs HttpSysServer that would be helpful - I had been assuming HttpSysServer was the replacement for HttpListener and would cover its scenarios.

Also, I believe this support is key to running in Docker when using Windows Authentication. With Windows Containers, AD authentication uses a gMSA, which won't match the machine account. See: https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts

strabu commented 6 years ago

Thanks for taking this into consideration. We'll stick with NTLM for a few more months and move on to something completely different later this year.