Part 3: Adding Basic Authentication to Asp.Net Core the right way

This blog is all about adding Basic Authentication to Asp.Net Core.

Warning: Although implementing Basic Authentication seems easy, it brings a vulnerability to your site! names and passwords provided are sent over the internet unencrypted. This means: the authentication method does not hide the name and password for hackers. You have to encrypt the communication yourself! Therefore, always combine Basic Authentication with SSL, also known as HTTPS.

In the past, I have written my own simple Basic Authentication NuGet package. It’s still ok for simple classic Asp.Net MVC projects.

But I want to use Basic Authentication In Asp.Net Core. Instead of (re)writing my own NuGet package, I checked out the NuGet store and found a nice solution.

This NuGet package provides me the flexibility to add Basic Authentication to my (test) projects.

In this blog, we will see what we have to do to get it running. And we will see how we can beef up the security by using HTTPS.

This is a series of blogs regarding using SignalR on Asp.Net MVC Core:

  1. Getting SignalR running on Asp.Net MVC Core
  2. Passing data from outside an Asp.Net MVC Core site to the browser using SignalR
  3. Adding Basic Authentication to Asp.Net Core the right way

Adding Basic Authentication

First, we add the Basic Authentication NuGet package and we consume it during start up.

Add the NuGet package using the .csproj file (just edit it, if you dare):

<PackageReference Include="ZNetCS.AspNetCore.Authentication.Basic" Version="2.0.0" />

Or, more convenient, use the NuGet PAckage manager (via right-click Dependencies in the Application Folder, Manage NuGet Packages):

Or, use the NuGet Package Console:

PM> Install-Package ZNetCS.AspNetCore.Authentication.Basic

Once the NuGet package is added, go to the ‘Startup’ class in the root folder and add these pieces of code:

public void ConfigureServices(IServiceCollection services)
{
#if !DEBUG
  services
    .AddAuthentication(BasicAuthenticationDefaults.AuthenticationScheme)
    .AddBasicAuthentication(
      options =>
      {
        options.Realm = "My Application";
        options.Events = new BasicAuthenticationEvents
        {
          OnValidatePrincipal = context =>
          {
            if ((context.UserName.ToLower() == "name") 
                    && (context.Password == "password"))
            {
              var claims = new List<Claim>
              {
                new Claim(ClaimTypes.Name, 
                          context.UserName, 
                          context.Options.ClaimsIssuer)
              };

              var ticket = new AuthenticationTicket(
                new ClaimsPrincipal(new ClaimsIdentity(
                  claims, 
                  BasicAuthenticationDefaults.AuthenticationScheme)),
                new Microsoft.AspNetCore.Authentication.AuthenticationProperties(),
                BasicAuthenticationDefaults.AuthenticationScheme);

              return Task.FromResult(AuthenticateResult.Success(ticket));
            }

            return Task.FromResult(AuthenticateResult.Fail("Authentication failed."));
          }
        };
      });
#endif

...
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
#if !DEBUG
  app.UseAuthentication();
#endif
...
}

Note: I use compiler directives (#if !DEBUG etc.) because I do not need basic authentication on my development machine during debugging. Here the Basic Authentication is only active during de release in Azure:

Note: Here I use a hardcoded name and password, just for simplicity. Check out the Nuget Git page for more intelligent examples of providing more dynamic name-and-password combinations.

Do not forget to add these namespaces; otherwise, deployment will fail:

using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using ZNetCS.AspNetCore.Authentication.Basic;
using ZNetCS.AspNetCore.Authentication.Basic.Events;

Recompile your code, just to be sure…

Consuming Basic Authentication

For those who already tried to run the website and expected a login screen, at this point nothing new happens.

We are not consuming Basic Authentication, We have to use set the Authorize attribute yet.

So go to the HomeController to add that attribute. This tells the website that for any action, the user has to provide legit credentials:

using Microsoft.AspNetCore.Authorization;

#if !DEBUG
    [Authorize]
#endif
public class HomeController : Controller
{

Note: Again, this is build to be used in release mode. If you want to use it locally, remove the compiler directives.

Note: The Authorize attribute has a lot more to offer than shown here. Check out the documentation

Now publish the site and run in Chrome. You will see a dialog like this:

And we get access to any page (action) of the Home Controller.

This security implementation also works fine with SignalR. The security does not affect the SignalR communication.

Making it more secure

But look at the address of the site, it starts with HTTP. This means the communication is not secure, the transport of data to this server is not encrypted. Within Basic Authentication, the name and password are sent unencrypted to the server. So everyone with tools like Fiddler or Wireshark can sniff the HTTP traffic to your site and see your name and password.

Luckily, Azure websites are secure by default. Our website is a subsite of “azurewebsites.net”. The main site implements HTTPS and so does our site.

The only thing our users have to do is calling all pages using the HTTPS address:

This is the login dialog for Firefox. And the result of passing  the correct name and password is:

Look at that green lock, we are secure!

But this is a bit cumbersome. Users are not trained to do this ‘redirection’. How can we help them?

Forcing HTTPS

It’s possible to redirect HTTP traffic automatically to HTTPS. We just follow the documentation:

public void ConfigureServices(IServiceCollection services)
{
#if !DEBUG
  services.Configure<MvcOptions>(options =>
  {
    options.Filters.Add(new RequireHttpsAttribute());
  });
#endif
  ...
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
#if !DEBUG
  var options = new RewriteOptions()
                  .AddRedirectToHttps();
#endif
  ...
}

Again, add the necessary namespaces:


using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Rewrite;

What we do here, we enforce the automatic redirection to HTTPS for all HTTP traffic!

So redeploy the website to Azure and try to connect to it using HTTP. You will soon find out that all calls are redirected to HTTPS:

Conclusion

With just a NuGet package and some common sense, we have introduced a simple but yet robust security layer around our website.

But, security is a journey. What we see here is not the end goal, it more the very first stop on your way.

Advertenties

Reacties zijn gesloten.