Search code examples
asp.netasp.net-mvcwindows-authenticationasp.net-web-apiself-hosting

ASP.NET Web API Self-Host with Windows Authentication


I am trying to use the ASP.NET Web API Self-Host option with Windows authentication so I can determine the logged on user and ultimately accept or reject the user based on their identity. Here is my console application code:

using System;
using System.Web.Http;
using System.Web.Http.SelfHost;

namespace SelfHost
{
    class Program
    {
        static void Main(string[] args)
        {
            var config = new HttpSelfHostConfiguration("http://myComputerName:8080");
            config.UseWindowsAuthentication = true;

            config.Routes.MapHttpRoute(
                "API Default", "api/{controller}/{id}",
                new { id = RouteParameter.Optional });

            using (HttpSelfHostServer server = new HttpSelfHostServer(config))
            {
                server.OpenAsync().Wait();

                Console.WriteLine("Press Enter to quit.");
                Console.ReadLine();
            }
        }
    }
}

Here is the controller:

[Authorize]
public class HelloController : ApiController
{
    public string Get()
    {
        // This next line throws an null reference exception if the Authorize
        // attribute is commented out.
        string userName = Request.GetUserPrincipal().Identity.Name;
        return "Hello " + userName;
    }
}

Edit - I added the Authorize attribute, and the debugger shows that the code inside the Get action method is never invoked. The following HTML is returned:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content="text/html; charset=windows-1252" http-equiv=Content-Type></HEAD>
<BODY></BODY></HTML>

If the Authorize attribute is commented out, Request.GetUserPrincipal().Identity.Name throws a null reference exception since Request.GetUserPrincipal() yields null.


Solution

  • I've hit this issue as well and the only solution I've came up with is to deliver dedicated HttpSelfHostedConfiguration:

    public class NtlmSelfHostConfiguration : HttpSelfHostConfiguration
    {
        public NtlmSelfHostConfiguration(string baseAddress)
            : base(baseAddress)
        { }
    
        public NtlmSelfHostConfiguration(Uri baseAddress)
            : base(baseAddress)
        { }
    
        protected override BindingParameterCollection OnConfigureBinding(HttpBinding httpBinding)
        {
            httpBinding.Security.Mode = HttpBindingSecurityMode.TransportCredentialOnly;
            httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
            return base.OnConfigureBinding(httpBinding);
        }
    }
    

    To use it you just need to change one line (you don't need to set UseWindowsAuthentication anymore):

    var config = new NtlmSelfHostConfiguration("http://myComputerName:8080");
    

    The only issue with this approach is that authentication is now required for every request made to server which is using this configuration.