1

I am using ASP.NET Core 6 and Kestrel (not IIS). I set up AspNetCore.Identity with an ApplicationUser class extending IndentiyUser which has a property WindowsLogin containing the Active Directory Sid of a user:

builder.Services.AddDefaultIdentity<ApplicationUser>
        (options =>
        {
            options.SignIn.RequireConfirmedAccount = true; 
            options.User.RequireUniqueEmail = true;
        })
        .AddRoles<ApplicationRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>();

I also set up Integrated Authentication for Kestrel with

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();

So, individually, both sign in methods work just fine. My goal is to have integrated authentication take place first, and if either the header is missing or the user is not in the identity database you are redirected to the identity/account/login page to do the class identity logon. I created a middleware (inspired by ASP.NET Core Identity with Windows Authentication)

public class WindowsAuthenticationMiddleware : IMiddleware
{
    private readonly UserManager<ApplicationUser> UserManager;
    private readonly SignInManager<ApplicationUser> SignInManager;

    public WindowsAuthenticationMiddleware(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
    {
        UserManager = userManager;
        SignInManager = signInManager;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        if (!SignInManager.IsSignedIn(context.User))
        {
            if (context.User.Identity is WindowsIdentity windowsIdentity && windowsIdentity.User != null)
            {
                string userSid = windowsIdentity.User.ToString();

                ApplicationUser user = await UserManager.Users.FirstOrDefaultAsync(u => u.WindowsLogin == userSid);

                if (user != null)
                {
                    await SignInManager.SignInAsync(user, true);
                    context.User = await SignInManager.CreateUserPrincipalAsync(user);
                }
            }
        }
        await next(context);
    }
}

registred with

    builder.Services.AddScoped<WindowsAuthenticationMiddleware>();
    app.UseMiddleware<WindowsAuthenticationMiddleware>();
  • When I login with windows auth, my WindowsIdentity is passed to the middleware, the users sid is searched in the identity db, and the resulting user is logged on. Works just perfect.
  • When I do not login with windows auth, the browser keeps asking for windows credentials, but in this case I want the identity login page to appear.
  • When I login with windows auth but the sid is not in the database I also want the identity login page to appear.

So the goal is to have Windows Integrated Authentication to take place first and login the user if it is present in the database. If it isn't present or a kerberos token hasn't been presented redirect to the identity logon page for login.

Alternatively, it is acceptable that the user has to click to use windows integrated authentication, e.g. as a Login provider on the identity login page.

Norman
  • 3,279
  • 3
  • 25
  • 42
  • Have you tried redirecting to the Identity login page after windows authentication fails? – Chen Jan 30 '23 at 09:43

0 Answers0