Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enable both Windows authentication and Anonymous authentication in an ASP.NET Core app

I know that this has been asked many times before, but unfortunately not about ASP.NET Core web apps, just the classic ASP.NET web apps. All the answers i've found on the internet don't help me, because the IIS configuration of ASP.NET Core apps is so different than classic ASP.NET. For example, ASP.NET Core uses the Kestrel proxy, so many of the configurations relevant in ASP.NET are not in ASP.NET Core. I've basically tried everything i could possibly found on the Internet but none helped me. I whish it was as simple as enabling both anonymous and windows authentications on the app in IIS and that's it, but I guess it will more work than that.

What is the procedure of enabling both these authentications in a single asp.net core web app?

like image 660
ashilon Avatar asked Jun 27 '17 10:06

ashilon


People also ask

How do I turn on anonymous authentication?

Go to Administrative Tools and open Internet Information Services (IIS). In the Internet Information Services dialog box, expand local computer ► Sites, and click Default Website. Double-click Authentication. Click Anonymous Authentication and make sure it is enabled.

How do I use Windows Authentication in .NET Core API?

For . Start Visual Studio and select Create a new project. In the Create a new project dialog, select ASP.NET Core Web App (or Web API) > Next. In the Configure your new project dialog, enter Project name > Next. In the Additional Information dialog, select Authentication Type as Windows.

How do you set authentication mode in the ASP.NET application?

Configure security settings in the Web. This section demonstrates how to add and modify the <authentication> and <authorization> configuration sections to configure the ASP.NET application to use forms-based authentication. In Solution Explorer, open the Web. config file. Change the authentication mode to Forms.

How do I enable Windows Authentication?

In Control Panel, click Programs and Features, and then click Turn Windows features on or off. Expand Internet Information Services, expand World Wide Web Services, expand Security, and then select Windows Authentication. Click OK. Click Close.


3 Answers

IIS will act as a reverse proxy and will be responsible for setting and transmitting to Kestrel the Windows identity of the user. So first, set up IIS to allow both Windows and Anonymous Authentication:

enter image description here

Then, you need to change your web.config to ask IIS to transmit the Windows identity (in case one is found) to your ASP.NET Core application like that: https://stackoverflow.com/a/42163175/6827240

At this point, if you create a controller action with an "[Authorize]" attribute, HttpContext.User.Identity.Name; should have the value of the Windows identity used by your client. I replied to something similar here: NTLM authentication on specific route in ASP.NET Core

The good thing is that a standard controller action will still work if your client doesn't pass along Windows identity token, while a protected one (using [Authorize] tag) will fail.

PS: I like to use curl.exe in verbose mode to see what is happening in terms of authorization protocol (Negotiate protocol, NTLM tokens ...)

like image 151
Daboul Avatar answered Oct 20 '22 10:10

Daboul


I have a similar scenario for an ASP.NET Core 2.0 application (use Windows Authentication throughout the app except a single controller) and Daboul's explanation was not enough.

I had to set up a custom middleware as indicated here since anonymous takes precedence.

The 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");     }  } 

and its usage in Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {     app.UseMiddleware<NtlmAndAnonymousSetupMiddleware>();      // other code here } 

So, the middleware accept anonymous requests for AnonymousController only and will provide a challenge if Windows Authentication info is not provided.

Anonymous controller

Since the middleware makes the differece between what is anonymous and requires authentication, this will look just like any ordinary controller:

[Route("Anonymous")] public class AnonymousController : Controller {     [HttpGet("Echo")]     public string Echo(string data)     {         return data;     } } 

Tests

(all done on a Windows machine)

  1. Chrome + access non-anonymous controller action => works fine (both @User.Identity.Name and @Context.User.Identity.Name return the correct user

  2. Chrome + anonymous action => works directly

  3. Firefox (which does not directly transfer NTLM ticket from OS) + non-anonymous => a modal asks for user/pass => if provided correctly, it works fine

  4. Firefox + anonymous action => works directly

like image 38
Alexei - check Codidact Avatar answered Oct 20 '22 10:10

Alexei - check Codidact


In case anyone wonders, I modified @Alexei's answer to use Attributes rather than request path in Netcore 3.X

First create the class and get the endpoints metadata

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 || HasAnonymousAttribute(context))
        {
            await next(context);
            return;
        }

        await context.ChallengeAsync("Windows");
    }

    private bool HasAnonymousAttribute(HttpContext context)
    {
        var endpoint = context.GetEndpoint();
        var retVal = (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null);

        return retVal;
    }
}

Then modify public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

        app.UseAuthentication();
        app.UseAuthorization();
        app.UseMiddleware<NtlmAndAnonymousSetupMiddleware>();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
            endpoints.MapControllers();
        });
like image 20
Alberto L. Bonfiglio Avatar answered Oct 20 '22 10:10

Alberto L. Bonfiglio