1

I have a Console App and a Web API 2 project, both run on the same server. I have setup my Console App to call a RESTful endpoint in my Web API using HttpClient while impersonating a domain account.

            Console.WriteLine("Setting up impersonator.");
            using (new Impersonator(accountUsername, accountDomain, accountPwd))
            {
                Console.WriteLine("Impersonator set up.");

                HttpClientHandler handler = new HttpClientHandler();
                handler.UseDefaultCredentials = true;

                Console.WriteLine("Executing as: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name);

                using (var client = new HttpClient(handler))
                {
                    client.BaseAddress = new Uri(serviceBaseUrl);
                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                    HttpResponseMessage response = await client.GetAsync("api/resource/3/");
                    Console.WriteLine(response.ToString());
                    if (response.IsSuccessStatusCode)
                    {
                        result = await response.Content.ReadAsAsync<ResourceType>();
                    }
                }

                if (result != null)
                {
                    // Do something...
                }
            }

I don't think the actual endpoint is relevant to this question, as the Http Request never makes it to this point (even without any authorization attribute). When I run the two projects locally, the Console App is successful when making the call. However, when I run it on the server, the Console App receives a 401 unauthorized. I added some logging to my Web API pipeline to log the HttpContext.Current.User information.

    protected void Application_BeginRequest()
    {
        var currentContext = HttpContext.Current;
        ILogHelper _logger = new LogHelper("System");

        _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "BeginRequest System Principal Name: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name);
        _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "BeginRequest Is User Null? " + (currentContext.User == null? "YES":"NO"));

        if (currentContext.User != null)
        {
            _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "BeginRequest User: " + currentContext.User.Identity.Name);
            _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "BeginRequest User Authenticated: " + currentContext.User.Identity.IsAuthenticated.ToString());
        }
    }

    protected void Application_AuthenticateRequest()
    {
        var currentContext = HttpContext.Current;
        ILogHelper _logger = new LogHelper("System");

        _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "AuthenticateRequest System Principal Name: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name);
        _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "AuthenticateRequest Is User Null? " + (currentContext.User == null ? "YES" : "NO"));

        if (currentContext.User != null)
        {
            _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "AuthenticateRequest User: " + currentContext.User.Identity.Name);
            _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "AuthenticateRequest User Authenticated: " + currentContext.User.Identity.IsAuthenticated.ToString());
        }
    }

    protected void Application_AuthorizeRequest()
    {
        var currentContext = HttpContext.Current;
        ILogHelper _logger = new LogHelper("System");

        _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "AuthorizeRequest System Principal Name: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name);
        _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "AuthorizeRequest Is User Null? " + (currentContext.User == null ? "YES" : "NO"));

        if (currentContext.User != null)
        {
            _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "AuthorizeRequest User: " + currentContext.User.Identity.Name);
            _logger.LogLine(NLog.LogLevel.Info, LogHelper.Tier.Business, "AuthorizeRequest User Authenticated: " + currentContext.User.Identity.IsAuthenticated.ToString());
        }
    }

When ran locally, the impersonated user is logged in the 'AuthenticateRequest' and 'AuthorizeRequest'. But, when ran on the server, the user is null the whole way through the pipeline.

I have Windows Authentication and Impersonation Enabled in IIS (everything else disabled). I have been working on this for 40+ hours and feel like I haven't made any progress. Any help with this issue would be huge!

Willy_B
  • 61
  • 1
  • 6
  • Are both the client and server using the same endpoint? Do you start the server before the client? A connection consists of a 1) Source IP 2) Destination IP 3) Port number. You can only have one connection with all 3 items being the same. So normally the server starts first and connects to the IPAny address with the port number. The client then connects to the IP address of the PC. So the virtual connection is really two connections. The server to IPAny and the client to IP. The pc is setup that sending to IP will get routed to IPAny. – jdweng Jun 16 '16 at 12:13
  • @jdweng I'm not sure what you mean by 'Are both the client and server using the same endpoint?'. But to answer your second question, yes, the Web API is running before the Console App makes its request. – Willy_B Jun 16 '16 at 12:58
  • Your server would look like following webpage and the port number can be any port number (that isn't blocked). If you are running your server on a PC that already has a Webpage running you can't use the default port number 8080 (you would have two apps running with same port number). https://msdn.microsoft.com/en-us/library/system.net.httplistener(v=vs.100).aspx – jdweng Jun 16 '16 at 15:41

1 Answers1

1

From this SO question, I determined that it is, in fact, a FQDN problem. To "fix", I just had to change out the "servername.com/service/" base URL in my Web.config with "localhost/service/". Once I did this, it ran flawlessly. I don't like the thought of using localhost as the URL, but I am unable to edit the server Registry values, so the fix provided by Microsoft wouldn't work for me.

Also, it turns out that I don't need Impersonation Enabled on my Web API site in IIS. Now, I only have Windows Authentication enabled.

Community
  • 1
  • 1
Willy_B
  • 61
  • 1
  • 6