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.
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.