16

I'm trying to mix Windows and Anonymous authentication in a .Net Core 2.0 empty web app. I would like to avoid the [Authorize] attribute as I do not want to use Mvc or controllers.

My setup is as follows:

  1. I created an empty .Net Core 2.0 web application

  2. I went to project properties -> Debug -> Checked "Enable Windows Authentication" and disabled "Enable Anonymous Authentication". Now "windowsAuthentication": true and "anonymousAuthentication": false appeared in my launchSettings.json under "IIS".

  3. Inside Startup.cs, in ConfigureServices I added services.AddAuthentication(Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme); as mentioned in https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x#windows-authentication-httpsys--iisintegration

  4. I added a simple Console.WriteLine(context.User.Identity.Name); to see that it works inside app.Run and... It all works!

However... as soon as I set "anonymousAuthentication" to true in launchSettings.json it stops working and I cannot figure out what can I do to make the Windows authentication work alongside with it. Context.User.Identity.IsAuthenticated is always false. As you can see my configuration is very simple and I need it to stay this way. I want to enable/disable windows authentication on certain dynamic routes, so using controllers with the [Authorize] attribute is not an option.

What I'm trying to achieve is a simple app where the url "/authenticated" would reply with the value of context.User.Identity.Name and the url "/public" would reply with something like say "This is a public page!". Something similar to NTLM authentication on specific route in ASP.NET Core but without the [Authorize] attribute and controllers. The resources are very scarce... Anyone have any idea what I could be missing? Thanks!

Ted Chirvasiu
  • 358
  • 1
  • 3
  • 10

2 Answers2

13

Anonymous takes precedence. You need to call httpContext.ChallengeAsync() when you get an anonymous request to a restricted part of your app. That will cause the client to send credentials on the next request. Here's a test that does this.

Alexei - check Codidact
  • 22,016
  • 16
  • 145
  • 164
Tratcher
  • 5,929
  • 34
  • 44
  • 3
    Thank you very much! `context.ChallengeAsync("Windows")` did the trick! I swear I tried await `context.ChallengeAsync()`, but I used "NTLM" as parameter for schema and it told me the authentication schema does not exist... Didn't know what value to pass... – Ted Chirvasiu Sep 07 '17 at 04:23
  • How to detect if user canceled authentication popup after sending Challenge? I would like to redirect to "LoginFailedPage" – raV720 Apr 20 '23 at 13:08
  • I don't know that you can. I don't think the browser sends a follow up request. You could include some HTML body in the original 401 response with a link or javascrip timeout redirect back to a login page. – Tratcher Apr 20 '23 at 17:25
9

Tratcher's answer saved me after some wasted time on this topic. For a very simple scenario (anonymous controller + windows authentication restricted in the rest), here is a quick start (middleware):

public class NtlmAndAnonymousSetupMiddleware
{
    private readonly RequestDelegate next;

    public NtlmAndAnonymousSetupMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.User.Identity.IsAuthenticated || context.Request.Path.ToString().StartsWith("/Anonymous"))
        {
            await next(context);
            return;
        }

        await context.ChallengeAsync("Windows");
    }

}

I have just plugged this in at the beginning of Startup.Configure method:

app.UseMiddleware<NtlmAndAnonymousSetupMiddleware>();
Alexei - check Codidact
  • 22,016
  • 16
  • 145
  • 164
  • For me, this generates an exception of "No authentication handlers are registered. Did you forget to call AddAuthentication().Add[SomeAuthHandler]("Windows",...)?" But I do have an AddAuthentication defined in my Startup.cs – Mike Gledhill Sep 06 '21 at 16:07