Linux – ASP-DotNet 2 Factor Authentication

Linux – ASP-DotNet 2 Factor Authentication follows from an ASP-DotNet Web App On Linux with Authentication. This guide demonstrates the stages required to enable two-factor authentication in an ASP project under Linux using TOTP authenticator apps. The original instructions for this process are available from Microsoft. However, they did not work as expected.

Download the QR Code library and add it to the project.

  • Download qrcode.js and extract the files
  • Copy ‘qrcode.js’ into wwwroot\lib folder in your project

Work Around a bug in .Net – Linux – ASP-DotNet 2 Factor Authentication

At this stage, Microsoft says that the identity needs to be scaffold-ed to generate ‘to generate /Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml‘. They also provide these instructions. However, there is a bug in .net on all operating systems which use case sensitive file systems. While this may be fixed in future a workaround can be made as follows while scaffolding. Either using the CLI inside your IDE or directly execute the following.

dd if=/dev/zero of=/tmp/mynuget bs=1024k count=2000
mkfs.vfat /tmp/mynuget
sudo mount -o uid=myuser,gid=myuser -t vfat /tmp/mynuget /home/myuser/.nuget
dotnet restore

Install the required NuGet packages – Linux – ASP-DotNet 2 Factor Authentication

Install the list of NuGet packages listed immediately below this paragraph. The instructions provided use the command line and assume you are installing the NuGet package for the highest version of the DotNet SDK you have installed. If this is not how your system is configured, adjusting the version number will be necessary. If you are following on from the ASP-DotNet Web App On Linux with Authentication article only one package is required. Installation through Riders (or any other NuGet package manager ) should work correctly.

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.SqlServer

Alternatively please see the Microsoft page for details matching your requirements. For a Razor pages application which already has Identity enabled (like the previous article), they list the following. SqlServer is required because of scaffolding defaulting to this. It can be changed and removed later.

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Identity.UI
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

Everything other than ‘Microsoft.VisualStudio.Web.CodeGeneration.Design’ and ‘Microsoft.EntityFrameworkCore.SqlServer’ should already be installed. Make sure everything is ready by listing the identity scaffolder options.

dotnet aspnet-codegenerator identity -h

Scaffold out the required packages.

dotnet aspnet-codegenerator identity -dc MyApplication.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.Manage.EnableAuthenticator"

This instruction deviates from the one on Microsoft’s Site

dotnet aspnet-codegenerator identity -dc MyApplication.Data.ApplicationDbContext --files "Account.Register;Account.Login"

Without adding ‘Account.Manage.EnableAuthenticator’ to the list of files it is not scaffold-ed.

Potential Changes to Startup.cs

A small change is required inside the ‘Startup.cs’ file to avoid conflicts with already added services. Please edit this as bellow to comment out the default identity service. Alternatively, remove this completely. This may not be necessary depending on the original configuration of the project.

public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseMySql(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddDatabaseDeveloperPageExceptionFilter();
            /*
            services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores<ApplicationDbContext>();
            */
            services.AddRazorPages();
        }

Changes To Appsettings.json – Linux – ASP-DotNet 2 Factor Authentication

A new string may be added in appsettings.json however this depends on the initial setup of the project. If it has been added it will use a SQL Server connection string with windows authentication. Consequently, this will need changing on a Linux system even if your application uses SQL Server.

Items with a double asterisk as the start and end should be replaced by a setting unique to the system in use. However also note, that the server name is unlikely to need changing. Subsequently in these cases just remove the asterisks.

MySql Changes To Appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=**localhost**;Database=**DatabaseName**;Uid=**YourMySqlUserName;",
    "ApplicationDbContextConnection": "Server=**localhost**;Database=**DatabaseName**;Uid=**YourMySqlUserName"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

SQLite Changes To Appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "DataSource=app.db",
    "ApplicationDbContextConnection": "DataSource=app.db"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

SQL Server Changes To Appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=**localhost**;Database=**DataBaseName**;User Id=**SA**;Password=**SqlServerUserPassword**",
    "ApplicationDbContextConnection": "Server=**localhost**;Database=**DataBaseName**;User Id=**SA**;Password=**SqlServerUserPassword**"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Changes to IdentityHostingStartup.cs

By default the scaffolding sets this file up to use Microsoft’s SQL server. If your application uses another database system this will also need slight amendments.

MySql Changes to IdentityHostingStartup.cs

public class IdentityHostingStartup : IHostingStartup
    {
        public void Configure(IWebHostBuilder builder)
        {
            builder.ConfigureServices((context, services) => {
                services.AddDbContext<ApplicationDbContext>(options =>
                    options.UseMySql(
                        context.Configuration.GetConnectionString("ApplicationDbContextConnection")));

                services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
                    .AddEntityFrameworkStores<ApplicationDbContext>();
            });
        }
    }

SQLite Changes to IdentityHostingStartup.cs

public class IdentityHostingStartup : IHostingStartup
    {
        public void Configure(IWebHostBuilder builder)
        {
            builder.ConfigureServices((context, services) => {
                services.AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlite(
                        context.Configuration.GetConnectionString("ApplicationDbContextConnection")));

                services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
                    .AddEntityFrameworkStores<ApplicationDbContext>();
            });
        }
    }

Update The Scripts Section

The above procedure will have scaffold-ed out a new file called ‘EnableAuthenticator.cshtml’. Inside this file, locate the scripts section and update it, so it looks like the above.

@section Scripts {
    @await Html.PartialAsync("_ValidationScriptsPartial")

    <script type="text/javascript" src="~/lib/qrcode.js"></script>
    <script type="text/javascript">
        new QRCode(document.getElementById("qrCode"),
            {
                text: "@Html.Raw(Model.AuthenticatorUri)",
                width: 150,
                height: 150
            });
    </script>
}

Finally delete the paragraph referring to the Microsoft Instructions

Further Useful Information

Microsoft provides some very useful guides on setting up third party authentication with a number of different providers.

These first four of these worked without the need to modify the instructions provided by Microsoft. The others may require extra work. Additionally, when moving to production there are additional steps to keep them working.

Related Articles

Related Post

3 thoughts on “Linux – ASP-DotNet 2 Factor Authentication

Leave a Reply

Your email address will not be published. Required fields are marked *