2

In ASP.NET Core 5, can I use Windows Authentication (which allows IIS to authenticate the user) and somehow grab that token and then use that to call a Web API application that also authenticates via Windows Authentication? In other words, we want the same security context in the API app as we have in the UI app. Is that even possible?

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(IISDefaults.AuthenticationScheme);
    var commonApiSettings = Configuration.GetSection("CommonApiSettings").Get<CommonApiSettings>(); 
    services.AddHttpClient("CommonApi",
                    client =>
                    {
                        client.BaseAddress = new Uri(commonApiSettings.BaseAddress);
                        client.DefaultRequestHeaders.Add("Accept", "application/json");
                        client.DefaultRequestHeaders.Add("User-Agent", "AspNetCore-Demo");
                    });
    services.AddControllersWithViews();
}

THen in my controller I want to call a web api. Every time I get 401 Unauthorized.

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly IHttpClientFactory _clientFactory;

    public HomeController(ILogger<HomeController> logger, IHttpClientFactory httpClient)
    {
        _logger = logger;
        _clientFactory = httpClient;
    }

    public async Task<IActionResult> Index()
    {

        IEnumerable<Confection> inventory;

        try
        {
            var user = (WindowsIdentity)User.Identity!;

            await WindowsIdentity.RunImpersonatedAsync(user.AccessToken, async () =>
            {

                var impersonatedUser = WindowsIdentity.GetCurrent();
                var message =
                    $"User: {impersonatedUser.Name}\t" +
                    $"State: {impersonatedUser.ImpersonationLevel}";

                var bytes = Encoding.UTF8.GetBytes(message);
          
                var httpClient = _clientFactory.CreateClient("CommonApi");
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", impersonatedUser.AccessToken.ToString());
                var request = new HttpRequestMessage(HttpMethod.Get, "");

                var httpResponseMessage = await httpClient.SendAsync(request);

                if (httpResponseMessage.IsSuccessStatusCode)
                {
                    using var contentStream = await httpResponseMessage.Content.ReadAsStreamAsync();
                    inventory = await JsonSerializer.DeserializeAsync<IEnumerable<Confection>>(contentStream);
                }
            });
        }
        catch (Exception e)
        {
            //await context.Response.WriteAsync(e.ToString());
        }

        return View();
    }
Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
tnk479
  • 672
  • 11
  • 26
  • Does this answer your question? [How to get HttpClient to pass credentials along with the request?](https://stackoverflow.com/questions/12212116/how-to-get-httpclient-to-pass-credentials-along-with-the-request) – Jim G. May 03 '23 at 20:54

1 Answers1

2

To send Windows credentials, you need to set the UseDefaultCredentials property of the HttpClientHandler used by HttpClient. There is an example of how to do this with IHttpClientFactory in the documentation.

In your case, it should look something like this:

services.AddHttpClient("CommonApi",
                client =>
                {
                    client.BaseAddress = new Uri(commonApiSettings.BaseAddress);
                    client.DefaultRequestHeaders.Add("Accept", "application/json");
                    client.DefaultRequestHeaders.Add("User-Agent", "AspNetCore-Demo");
                })
            .ConfigurePrimaryHttpMessageHandler(() =>
                new HttpClientHandler
                {
                    UseDefaultCredentials = true
                });
Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
  • this did not work for me, because the user i get on the webapi side is not the current user of the UI website, but the user of the applicationpool... any suggestions? – blindmeis Jan 26 '23 at 06:33
  • @blindmeis That sounds like you're using the wrong variable to retrieve the current user. In ASP.NET Core, you can use `User.Identity.Name` in a controller class to get the username of the currently logged in user. – Gabriel Luci Jan 26 '23 at 13:15
  • we host our apsnet.core applications with IIS and we tried all, but no success so far. the only thing what is working, is to create a credential cache with username password and set it with the httpclient :( – blindmeis Jan 30 '23 at 12:06
  • @blindmeis Are you using Windows Authentication to authenticate the user? – Gabriel Luci Jan 30 '23 at 15:44
  • i will do a testproject next week and post a question here. but yes we do Windows Authentication – blindmeis Feb 01 '23 at 07:57