Version 5.x has been out of support since December 13, 2022, and this corresponding section of the documentation is no longer maintained. We strongly recommend upgrading to a supported version.
There are several ways how you can enable Windows authentication in ASP.NET Core (and thus in your IdentityServer).
See the Microsoft documentation for additional information.
The typical ASP.NET Core CreateDefaultBuilder host setup enables support for IIS-based Windows authentication when hosting in IIS. Make sure that Windows authentication is enabled in launchSettings.json or your IIS configuration.
The IIS integration layer will configure a Windows authentication handler into DI that can be invoked via the authentication service. Typically in your IdentityServer it is advisable to disable the automatic behavior.
This is done in ConfigureServices (details vary depending on in-proc vs out-of-proc hosting)::
// configures IIS out-of-proc settings (see https://github.com/aspnet/AspNetCore/issues/14882)
services.Configure<IISOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
// ..or configures IIS in-proc settings
services.Configure<IISServerOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
You trigger Windows authentication by calling ChallengeAsync using the Windows scheme (or if you want to use a constant: Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme).
This will send the Www-Authenticate header back to the browser which will then re-load the current URL including the Windows identity. You can tell that Windows authentication was successful, when you call AuthenticateAsync on the Windows scheme and the principal returned is of type WindowsPrincipal.
The principal will have information like user and group SID and the Windows account name. The following snippet shows how to trigger authentication, and if successful convert the information into a standard ClaimsPrincipal for the temp-Cookie approach::
private async Task<IActionResult> ChallengeWindowsAsync(string returnUrl)
{
// see if windows auth has already been requested and succeeded
var result = await HttpContext.AuthenticateAsync("Windows");
if (result?.Principal is WindowsPrincipal wp)
{
// we will issue the external cookie and then redirect the
// user back to the external callback, in essence, treating windows
// auth the same as any other external authentication mechanism
var props = new AuthenticationProperties()
{
RedirectUri = Url.Action("Callback"),
Items =
{
{ "returnUrl", returnUrl },
{ "scheme", "Windows" },
}
};
var id = new ClaimsIdentity("Windows");
// the sid is a good sub value
id.AddClaim(new Claim(JwtClaimTypes.Subject, wp.FindFirst(ClaimTypes.PrimarySid).Value));
// the account name is the closest we have to a display name
id.AddClaim(new Claim(JwtClaimTypes.Name, wp.Identity.Name));
// add the groups as claims -- be careful if the number of groups is too large
var wi = wp.Identity as WindowsIdentity;
// translate group SIDs to display names
var groups = wi.Groups.Translate(typeof(NTAccount));
var roles = groups.Select(x => new Claim(JwtClaimTypes.Role, x.Value));
id.AddClaims(roles);
await HttpContext.SignInAsync(
IdentityServerConstants.ExternalCookieAuthenticationScheme,
new ClaimsPrincipal(id),
props);
return Redirect(props.RedirectUri);
}
else
{
// trigger windows auth
// since windows auth don't support the redirect uri,
// this URL is re-triggered when we call challenge
return Challenge("Windows");
}
}
A sample is provided here.