From 58b854438ec9a9a9c8dc348acb63cba4a4a12fa8 Mon Sep 17 00:00:00 2001 From: Carl Sixsmith Date: Tue, 4 Jun 2024 14:00:43 +0100 Subject: [PATCH] Custom allow list options for IP based 2fa selection --- src/Infrastructure/DependencyInjection.cs | 10 +++++- .../Services/Identity/AllowlistOptions.cs | 6 ++++ .../Services/Identity/CustomSigninManager.cs | 33 +++++++++++++++++++ src/Server.UI/appsettings.Development.json | 11 ++++--- src/Server.UI/appsettings.json | 5 +++ 5 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 src/Infrastructure/Services/Identity/AllowlistOptions.cs create mode 100644 src/Infrastructure/Services/Identity/CustomSigninManager.cs diff --git a/src/Infrastructure/DependencyInjection.cs b/src/Infrastructure/DependencyInjection.cs index 8a4b9e56..06303341 100644 --- a/src/Infrastructure/DependencyInjection.cs +++ b/src/Infrastructure/DependencyInjection.cs @@ -164,13 +164,21 @@ private static IServiceCollection AddAuthenticationService( IConfiguration configuration ) { + + services.Configure(configuration.GetSection(nameof(AllowlistOptions))); + services .AddIdentityCore() .AddRoles() .AddEntityFrameworkStores() - .AddSignInManager() + //.AddSignInManager() .AddClaimsPrincipalFactory() .AddDefaultTokenProviders(); + + services.AddScoped, CustomSigninManager>(); + services.AddScoped>(); + + services.Configure(options => { var identitySettings = configuration diff --git a/src/Infrastructure/Services/Identity/AllowlistOptions.cs b/src/Infrastructure/Services/Identity/AllowlistOptions.cs new file mode 100644 index 00000000..d4803a69 --- /dev/null +++ b/src/Infrastructure/Services/Identity/AllowlistOptions.cs @@ -0,0 +1,6 @@ +namespace Cfo.Cats.Infrastructure.Services.Identity; + +public class AllowlistOptions +{ + public List AllowedIPs { get; set; } = new(); +} diff --git a/src/Infrastructure/Services/Identity/CustomSigninManager.cs b/src/Infrastructure/Services/Identity/CustomSigninManager.cs new file mode 100644 index 00000000..da7d12b6 --- /dev/null +++ b/src/Infrastructure/Services/Identity/CustomSigninManager.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; + +namespace Cfo.Cats.Infrastructure.Services.Identity; + +public class CustomSigninManager(UserManager userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory claimsFactory, IOptions optionsAccessor, ILogger> logger, IAuthenticationSchemeProvider schemes, IUserConfirmation confirmation, IHttpContextAccessor httpContextAccessor, IOptions allowlistOptions) + : SignInManager(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation) + where TUser : class +{ + public override async Task PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure) + { + var user = await UserManager.FindByNameAsync(userName); + + if (user == null) + { + return SignInResult.Failed; + } + + var ipAddress = httpContextAccessor.HttpContext!.Connection.RemoteIpAddress?.ToString(); + if (string.IsNullOrWhiteSpace(ipAddress) == false && allowlistOptions.Value.AllowedIPs.Contains(ipAddress)) + { + var result = await CheckPasswordSignInAsync(user, password, lockoutOnFailure); + if (result.Succeeded) + { + await SignInAsync(user, isPersistent); + } + return result; + } + return await base.PasswordSignInAsync(userName, password, isPersistent, lockoutOnFailure); + } + + +} \ No newline at end of file diff --git a/src/Server.UI/appsettings.Development.json b/src/Server.UI/appsettings.Development.json index 55b63674..a5362cc9 100644 --- a/src/Server.UI/appsettings.Development.json +++ b/src/Server.UI/appsettings.Development.json @@ -1,7 +1,8 @@ { -/* "DatabaseSettings": { - "DbProvider": "sqlite", - "ConnectionString": "Data Source=./cats.db;" - },*/ - "DetailedErrors": true + "DetailedErrors": true, + "AllowlistOptions": { + "AllowedIPs": [ + "::1" + ] + } } \ No newline at end of file diff --git a/src/Server.UI/appsettings.json b/src/Server.UI/appsettings.json index bacfcc45..89b6987e 100644 --- a/src/Server.UI/appsettings.json +++ b/src/Server.UI/appsettings.json @@ -49,5 +49,10 @@ "ApiKey": "", "SmsTemplate": "", "EmailTemplate": "" + }, + "AllowlistOptions": { + "AllowedIPs": [ + + ] } } \ No newline at end of file