From 2229648171f392a1d6055f511d84ab8893c60fc0 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 4 Dec 2025 11:50:53 +0000 Subject: [PATCH 1/3] fix some codacy issues --- .../ChangePassword/ChangePassword.feature.cs | 8 +- .../ForgotPassword/ForgotPassword.feature.cs | 8 +- .../UserLogin/UserLogin.feature.cs | 8 +- .../BootstrapperTests.cs | 2 +- SecurityService.UnitTests/MediatorTests.cs | 6 +- .../ModelFactoryTests.cs | 172 ++++------- .../Common/ClaimExtensions.cs | 46 +++ .../Account/ForgotPassword/Confirm.cshtml.cs | 6 +- .../Pages/Ciba/Consent.cshtml.cs | 90 +++--- .../Pages/Device/Index.cshtml.cs | 70 +++-- .../Pages/ExternalLogin/Callback.cshtml.cs | 283 +++++++++++------- SecurityService/Bootstrapper/MiscRegistry.cs | 2 - SecurityService/Dockerfile | 2 +- SecurityService/Factories/IModelFactory.cs | 105 ------- SecurityService/Factories/ModelFactory.cs | 273 +++++------------ .../Handlers/ApiResourceHandler.cs | 12 +- SecurityService/Handlers/ApiScopeHandler.cs | 12 +- SecurityService/Handlers/ClientHandler.cs | 16 +- SecurityService/Handlers/DeveloperHandler.cs | 9 +- .../Handlers/IdentityResourceHandler.cs | 12 +- SecurityService/Handlers/RoleHandler.cs | 12 +- SecurityService/Handlers/UserHandler.cs | 12 +- SecurityService/Startup.cs | 95 ++---- 23 files changed, 547 insertions(+), 714 deletions(-) create mode 100644 SecurityService.UserInterface/Common/ClaimExtensions.cs delete mode 100644 SecurityService/Factories/IModelFactory.cs diff --git a/SecurityService.OpenIdConnect.IntegrationTests/ChangePassword/ChangePassword.feature.cs b/SecurityService.OpenIdConnect.IntegrationTests/ChangePassword/ChangePassword.feature.cs index a296be55..1e172814 100644 --- a/SecurityService.OpenIdConnect.IntegrationTests/ChangePassword/ChangePassword.feature.cs +++ b/SecurityService.OpenIdConnect.IntegrationTests/ChangePassword/ChangePassword.feature.cs @@ -129,10 +129,10 @@ public void ScenarioInitialize(global::Reqnroll.ScenarioInfo scenarioInfo, globa "Scopes", "UserClaims"}); table2.AddRow(new string[] { - "estateManagement", - "Estate Managememt REST", + "transactionProcessor", + "Transaction Processor REST", "Secret1", - "estateManagement", + "transactionProcessor", "MerchantId,EstateId,role"}); #line 10 await testRunner.GivenAsync("I create the following api resources", ((string)(null)), table2, "Given "); @@ -175,7 +175,7 @@ public void ScenarioInitialize(global::Reqnroll.ScenarioInfo scenarioInfo, globa "estateUIClient", "Merchant Client", "Secret1", - "estateManagement,openid,email,profile", + "transactionProcessor,openid,email,profile", "hybrid", "https://[url]:[port]/signin-oidc", "https://[url]:[port]/signout-oidc", diff --git a/SecurityService.OpenIdConnect.IntegrationTests/ForgotPassword/ForgotPassword.feature.cs b/SecurityService.OpenIdConnect.IntegrationTests/ForgotPassword/ForgotPassword.feature.cs index 266083f7..97fd1696 100644 --- a/SecurityService.OpenIdConnect.IntegrationTests/ForgotPassword/ForgotPassword.feature.cs +++ b/SecurityService.OpenIdConnect.IntegrationTests/ForgotPassword/ForgotPassword.feature.cs @@ -129,10 +129,10 @@ public void ScenarioInitialize(global::Reqnroll.ScenarioInfo scenarioInfo, globa "Scopes", "UserClaims"}); table7.AddRow(new string[] { - "estateManagement", - "Estate Managememt REST", + "transactionProcessor", + "Transaction Processor REST", "Secret1", - "estateManagement", + "transactionProcessor", "MerchantId,EstateId,role"}); #line 10 await testRunner.GivenAsync("I create the following api resources", ((string)(null)), table7, "Given "); @@ -175,7 +175,7 @@ public void ScenarioInitialize(global::Reqnroll.ScenarioInfo scenarioInfo, globa "estateUIClient", "Merchant Client", "Secret1", - "estateManagement,openid,email,profile", + "transactionProcessor,openid,email,profile", "hybrid", "https://[url]:[port]/signin-oidc", "https://[url]:[port]/signout-oidc", diff --git a/SecurityService.OpenIdConnect.IntegrationTests/UserLogin/UserLogin.feature.cs b/SecurityService.OpenIdConnect.IntegrationTests/UserLogin/UserLogin.feature.cs index f86d98f0..d68f2567 100644 --- a/SecurityService.OpenIdConnect.IntegrationTests/UserLogin/UserLogin.feature.cs +++ b/SecurityService.OpenIdConnect.IntegrationTests/UserLogin/UserLogin.feature.cs @@ -127,10 +127,10 @@ public void ScenarioInitialize(global::Reqnroll.ScenarioInfo scenarioInfo, globa "Scopes", "UserClaims"}); table12.AddRow(new string[] { - "estateManagement", - "Estate Managememt REST", + "transactionProcessor", + "Transaction Processor REST", "Secret1", - "estateManagement", + "transactionProcessor", "MerchantId,EstateId,role"}); #line 10 await testRunner.GivenAsync("I create the following api resources", ((string)(null)), table12, "Given "); @@ -173,7 +173,7 @@ public void ScenarioInitialize(global::Reqnroll.ScenarioInfo scenarioInfo, globa "estateUIClient", "Merchant Client", "Secret1", - "estateManagement,openid,email,profile", + "transactionProcessor,openid,email,profile", "hybrid", "https://[url]:[port]/signin-oidc", "https://[url]:[port]/signout-oidc", diff --git a/SecurityService.UnitTests/BootstrapperTests.cs b/SecurityService.UnitTests/BootstrapperTests.cs index 5a7aaabf..3854dcb8 100644 --- a/SecurityService.UnitTests/BootstrapperTests.cs +++ b/SecurityService.UnitTests/BootstrapperTests.cs @@ -37,7 +37,7 @@ public void VerifyBootstrapperIsValid() this.AddTestRegistrations(services, hostingEnvironment.Object); s.ConfigureContainer(services); - Startup.Container.AssertConfigurationIsValid(); + Startup.GetContainer().AssertConfigurationIsValid(); } private IConfigurationRoot SetupMemoryConfiguration() diff --git a/SecurityService.UnitTests/MediatorTests.cs b/SecurityService.UnitTests/MediatorTests.cs index b4dbed69..a4c5636a 100644 --- a/SecurityService.UnitTests/MediatorTests.cs +++ b/SecurityService.UnitTests/MediatorTests.cs @@ -81,11 +81,11 @@ public async Task Mediator_Send_RequestHandled() this.AddTestRegistrations(services, hostingEnvironment.Object); s.ConfigureContainer(services); - - RoleManager authDb = Startup.Container.GetInstance>(); + Container container = Startup.GetContainer(); + RoleManager authDb = container.GetInstance>(); List errors = new List(); - IMediator mediator = Startup.Container.GetService(); + IMediator mediator = container.GetService(); foreach (IBaseRequest baseRequest in this.Requests) { try diff --git a/SecurityService.UnitTests/ModelFactoryTests.cs b/SecurityService.UnitTests/ModelFactoryTests.cs index 55a24e38..22ee1447 100644 --- a/SecurityService.UnitTests/ModelFactoryTests.cs +++ b/SecurityService.UnitTests/ModelFactoryTests.cs @@ -18,8 +18,6 @@ public class ModelFactoryTests [Fact] public void ModelFactory_ConvertFrom_ApiResource_ModelConverted() { - IModelFactory modelFactory = new ModelFactory(); - ApiResource apiResourceModel = new ApiResource { Scopes = new List @@ -33,7 +31,7 @@ public void ModelFactory_ConvertFrom_ApiResource_ModelConverted() Enabled = true }; - ApiResourceDetails apiResourceDto = modelFactory.ConvertFrom(apiResourceModel); + ApiResourceDetails apiResourceDto = ModelFactory.ConvertFrom(apiResourceModel); apiResourceDto.Scopes.First().ShouldBe(TestData.AllowedScopes.First()); apiResourceDto.Description.ShouldBe(TestData.ApiResourceDescription); @@ -46,11 +44,9 @@ public void ModelFactory_ConvertFrom_ApiResource_ModelConverted() [Fact] public void ModelFactory_ConvertFrom_ApiResource_ModelIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - ApiResource apiResourceModel = null; - ApiResourceDetails apiResourceDto = modelFactory.ConvertFrom(apiResourceModel); + ApiResourceDetails apiResourceDto = ModelFactory.ConvertFrom(apiResourceModel); apiResourceDto.ShouldBeNull(); } @@ -58,8 +54,6 @@ public void ModelFactory_ConvertFrom_ApiResource_ModelIsNull_NullReturned() [Fact] public void ModelFactory_ConvertFrom_ApiScope_ModelConverted() { - IModelFactory modelFactory = new ModelFactory(); - ApiScope apiScopeModel = new ApiScope { Description = TestData.ApiScopeDescription, @@ -68,7 +62,7 @@ public void ModelFactory_ConvertFrom_ApiScope_ModelConverted() Enabled = true }; - ApiScopeDetails apiScopeDto = modelFactory.ConvertFrom(apiScopeModel); + ApiScopeDetails apiScopeDto = ModelFactory.ConvertFrom(apiScopeModel); apiScopeDto.Description.ShouldBe(TestData.ApiScopeDescription); apiScopeDto.DisplayName.ShouldBe(TestData.ApiScopeDisplayName); @@ -79,11 +73,9 @@ public void ModelFactory_ConvertFrom_ApiScope_ModelConverted() [Fact] public void ModelFactory_ConvertFrom_ApiScope_ModelIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - ApiScope apiScopeModel = null; - ApiScopeDetails apiScopeDto = modelFactory.ConvertFrom(apiScopeModel); + ApiScopeDetails apiScopeDto = ModelFactory.ConvertFrom(apiScopeModel); apiScopeDto.ShouldBeNull(); } @@ -91,32 +83,26 @@ public void ModelFactory_ConvertFrom_ApiScope_ModelIsNull_NullReturned() [Fact] public void ModelFactory_ConvertFrom_ApiResourceList_ListIsEmpty_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - List apiResourceList = new List(); - List apiResourceDtoList = modelFactory.ConvertFrom(apiResourceList); + List apiResourceDtoList = ModelFactory.ConvertFrom(apiResourceList); - apiResourceDtoList.ShouldBeNull(); + apiResourceDtoList.ShouldBeEmpty(); } [Fact] public void ModelFactory_ConvertFrom_ApiResourceList_ListIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - List apiResourceList = null; - List apiResourceDtoList = modelFactory.ConvertFrom(apiResourceList); + List apiResourceDtoList = ModelFactory.ConvertFrom(apiResourceList); - apiResourceDtoList.ShouldBeNull(); + apiResourceDtoList.ShouldBeEmpty(); } [Fact] public void ModelFactory_ConvertFrom_ApiResourceList_ModelsConverted() { - IModelFactory modelFactory = new ModelFactory(); - ApiResource apiResourceModel = new ApiResource { Scopes = new List @@ -130,10 +116,11 @@ public void ModelFactory_ConvertFrom_ApiResourceList_ModelsConverted() Enabled = true }; - List apiResourceModelList = new List(); - apiResourceModelList.Add(apiResourceModel); + List apiResourceModelList = [ + apiResourceModel + ]; - List apiResourceDtoList = modelFactory.ConvertFrom(apiResourceModelList); + List apiResourceDtoList = ModelFactory.ConvertFrom(apiResourceModelList); apiResourceDtoList.ShouldNotBeNull(); apiResourceDtoList.ShouldNotBeEmpty(); @@ -149,32 +136,26 @@ public void ModelFactory_ConvertFrom_ApiResourceList_ModelsConverted() [Fact] public void ModelFactory_ConvertFrom_ApiScopeList_ListIsEmpty_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - - List apiScopeList = new List(); + List apiScopeList = new(); - List apiScopeDtoList = modelFactory.ConvertFrom(apiScopeList); + List apiScopeDtoList = ModelFactory.ConvertFrom(apiScopeList); - apiScopeDtoList.ShouldBeNull(); + apiScopeDtoList.ShouldBeEmpty(); } [Fact] public void ModelFactory_ConvertFrom_ApiScopeList_ListIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - List apiScopeList = null; - List apiScopeDtoList = modelFactory.ConvertFrom(apiScopeList); + List apiScopeDtoList = ModelFactory.ConvertFrom(apiScopeList); - apiScopeDtoList.ShouldBeNull(); + apiScopeDtoList.ShouldBeEmpty(); } [Fact] public void ModelFactory_ConvertFrom_ApiScopeList_ModelsConverted() { - IModelFactory modelFactory = new ModelFactory(); - ApiScope apiScopeModel = new ApiScope { Description = TestData.ApiScopeDescription, @@ -183,10 +164,11 @@ public void ModelFactory_ConvertFrom_ApiScopeList_ModelsConverted() Enabled = true }; - List apiScopeModelList = new List(); - apiScopeModelList.Add(apiScopeModel); + List apiScopeModelList = [ + apiScopeModel + ]; - List apiScopeDtoList = modelFactory.ConvertFrom(apiScopeModelList); + List apiScopeDtoList = ModelFactory.ConvertFrom(apiScopeModelList); apiScopeDtoList.ShouldNotBeNull(); apiScopeDtoList.ShouldNotBeEmpty(); @@ -200,8 +182,6 @@ public void ModelFactory_ConvertFrom_ApiScopeList_ModelsConverted() [Fact] public void ModelFactory_ConvertFrom_Client_ModelConverted() { - IModelFactory modelFactory = new ModelFactory(); - Client clientModel = new Client { ClientId = TestData.ClientId, @@ -212,7 +192,7 @@ public void ModelFactory_ConvertFrom_Client_ModelConverted() Enabled = true }; - ClientDetails clientDto = modelFactory.ConvertFrom(clientModel); + ClientDetails clientDto = ModelFactory.ConvertFrom(clientModel); clientDto.AllowedGrantTypes.ShouldBe(TestData.AllowedGrantTypes); clientDto.AllowedScopes.ShouldBe(TestData.AllowedScopes); @@ -225,11 +205,9 @@ public void ModelFactory_ConvertFrom_Client_ModelConverted() [Fact] public void ModelFactory_ConvertFrom_Client_ModelIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - Client clientModel = null; - ClientDetails clientDto = modelFactory.ConvertFrom(clientModel); + ClientDetails clientDto = ModelFactory.ConvertFrom(clientModel); clientDto.ShouldBeNull(); } @@ -237,32 +215,26 @@ public void ModelFactory_ConvertFrom_Client_ModelIsNull_NullReturned() [Fact] public void ModelFactory_ConvertFrom_ClientList_ListIsEmpty_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); + List clientModelList = new(); - List clientModelList = new List(); + List clientDtoList = ModelFactory.ConvertFrom(clientModelList); - List clientDtoList = modelFactory.ConvertFrom(clientModelList); - - clientDtoList.ShouldBeNull(); + clientDtoList.ShouldBeEmpty(); } [Fact] public void ModelFactory_ConvertFrom_ClientList_ListIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - List clientModelList = null; - List clientDtoList = modelFactory.ConvertFrom(clientModelList); + List clientDtoList = ModelFactory.ConvertFrom(clientModelList); - clientDtoList.ShouldBeNull(); + clientDtoList.ShouldBeEmpty(); } [Fact] public void ModelFactory_ConvertFrom_ClientList_ModelsConverted() { - IModelFactory modelFactory = new ModelFactory(); - Client clientModel = new Client { ClientId = TestData.ClientId, @@ -272,10 +244,11 @@ public void ModelFactory_ConvertFrom_ClientList_ModelsConverted() AllowedScopes = TestData.AllowedScopes, Enabled = true }; - List clientModelList = new List(); - clientModelList.Add(clientModel); + List clientModelList = [ + clientModel + ]; - List clientDtoList = modelFactory.ConvertFrom(clientModelList); + List clientDtoList = ModelFactory.ConvertFrom(clientModelList); clientDtoList.ShouldNotBeNull(); clientDtoList.ShouldNotBeEmpty(); @@ -291,8 +264,6 @@ public void ModelFactory_ConvertFrom_ClientList_ModelsConverted() [Fact] public void ModelFactory_ConvertFrom_IdentityResource_ModelConverted() { - IModelFactory modelFactory = new ModelFactory(); - IdentityResource identityResourceModel = new IdentityResource { Description = TestData.IdentityResourceDescription, @@ -303,7 +274,7 @@ public void ModelFactory_ConvertFrom_IdentityResource_ModelConverted() Required = true }; - IdentityResourceDetails identityResourceDto = modelFactory.ConvertFrom(identityResourceModel); + IdentityResourceDetails identityResourceDto = ModelFactory.ConvertFrom(identityResourceModel); identityResourceDto.Description.ShouldBe(TestData.IdentityResourceDescription); identityResourceDto.DisplayName.ShouldBe(TestData.IdentityResourceDisplayName); @@ -316,11 +287,9 @@ public void ModelFactory_ConvertFrom_IdentityResource_ModelConverted() [Fact] public void ModelFactory_ConvertFrom_IdentityResource_ModelIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - IdentityResource identityResourceModel = null; - IdentityResourceDetails identityResourceDto = modelFactory.ConvertFrom(identityResourceModel); + IdentityResourceDetails identityResourceDto = ModelFactory.ConvertFrom(identityResourceModel); identityResourceDto.ShouldBeNull(); } @@ -328,20 +297,16 @@ public void ModelFactory_ConvertFrom_IdentityResource_ModelIsNull_NullReturned() [Fact] public void ModelFactory_ConvertFrom_IdentityResourceList_ListIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - List identityResourceList = null; - List identityResourceDtoList = modelFactory.ConvertFrom(identityResourceList); + List identityResourceDtoList = ModelFactory.ConvertFrom(identityResourceList); - identityResourceDtoList.ShouldBeNull(); + identityResourceDtoList.ShouldBeEmpty(); } [Fact] public void ModelFactory_ConvertFrom_IdentityResourceList_ModelConverted() { - IModelFactory modelFactory = new ModelFactory(); - IdentityResource identityResourceModel = new IdentityResource { Description = TestData.IdentityResourceDescription, @@ -352,10 +317,11 @@ public void ModelFactory_ConvertFrom_IdentityResourceList_ModelConverted() Required = true }; - List identityResourceModelList = new List(); - identityResourceModelList.Add(identityResourceModel); + List identityResourceModelList = [ + identityResourceModel + ]; - List identityResourceDtoList = modelFactory.ConvertFrom(identityResourceModelList); + List identityResourceDtoList = ModelFactory.ConvertFrom(identityResourceModelList); identityResourceDtoList.ShouldNotBeNull(); identityResourceDtoList.ShouldNotBeEmpty(); @@ -371,41 +337,36 @@ public void ModelFactory_ConvertFrom_IdentityResourceList_ModelConverted() [Fact] public void ModelFactory_ConvertFrom_ListRoleDetails_ListIsEmpty_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); + List roleDetailsModelList = new(); - List roleDetailsModelList = new List(); + List roleDetailsDtoList = ModelFactory.ConvertFrom(roleDetailsModelList); - List roleDetailsDtoList = modelFactory.ConvertFrom(roleDetailsModelList); - - roleDetailsDtoList.ShouldBeNull(); + roleDetailsDtoList.ShouldBeEmpty(); } [Fact] public void ModelFactory_ConvertFrom_ListRoleDetails_ListIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - List roleDetailsModelList = null; - List roleDetailsDtoList = modelFactory.ConvertFrom(roleDetailsModelList); + List roleDetailsDtoList = ModelFactory.ConvertFrom(roleDetailsModelList); - roleDetailsDtoList.ShouldBeNull(); + roleDetailsDtoList.ShouldBeEmpty(); } [Fact] public void ModelFactory_ConvertFrom_ListRoleDetails_ModelsConverted() { - IModelFactory modelFactory = new ModelFactory(); - RoleDetails roleDetailsModel = new RoleDetails { RoleId = Guid.Parse(TestData.Role1Id), RoleName = TestData.RoleName }; - List roleDetailsModelList = new List(); - roleDetailsModelList.Add(roleDetailsModel); + List roleDetailsModelList = [ + roleDetailsModel + ]; - List rolesDetailsDtoList = modelFactory.ConvertFrom(roleDetailsModelList); + List rolesDetailsDtoList = ModelFactory.ConvertFrom(roleDetailsModelList); rolesDetailsDtoList.ShouldNotBeNull(); rolesDetailsDtoList.ShouldNotBeEmpty(); @@ -417,11 +378,9 @@ public void ModelFactory_ConvertFrom_ListRoleDetails_ModelsConverted() [Fact] public void ModelFactory_ConvertFrom_ListUserDetails_ListIsEmpty_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); + List userDetailsModelList = new(); - List userDetailsModelList = new List(); - - List userDetailsDtoList = modelFactory.ConvertFrom(userDetailsModelList); + List userDetailsDtoList = ModelFactory.ConvertFrom(userDetailsModelList); userDetailsDtoList.ShouldNotBeNull(); userDetailsDtoList.ShouldBeEmpty(); @@ -430,11 +389,9 @@ public void ModelFactory_ConvertFrom_ListUserDetails_ListIsEmpty_NullReturned() [Fact] public void ModelFactory_ConvertFrom_ListUserDetails_ListIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - List userDetailsModelList = null; - List userDetailsDtoList = modelFactory.ConvertFrom(userDetailsModelList); + List userDetailsDtoList = ModelFactory.ConvertFrom(userDetailsModelList); userDetailsDtoList.ShouldNotBeNull(); userDetailsDtoList.ShouldBeEmpty(); @@ -443,8 +400,6 @@ public void ModelFactory_ConvertFrom_ListUserDetails_ListIsNull_NullReturned() [Fact] public void ModelFactory_ConvertFrom_ListUserDetails_ModelsConverted() { - IModelFactory modelFactory = new ModelFactory(); - UserDetails userDetailsModel = new UserDetails { PhoneNumber = TestData.PhoneNumber, @@ -455,10 +410,11 @@ public void ModelFactory_ConvertFrom_ListUserDetails_ModelsConverted() Claims = TestData.Claims, RegistrationDateTime = new DateTime(2025,2,1) }; - List userDetailsModelList = new List(); - userDetailsModelList.Add(userDetailsModel); + List userDetailsModelList = [ + userDetailsModel + ]; - List userDetailsDtoList = modelFactory.ConvertFrom(userDetailsModelList); + List userDetailsDtoList = ModelFactory.ConvertFrom(userDetailsModelList); userDetailsDtoList.ShouldNotBeNull(); userDetailsDtoList.ShouldNotBeEmpty(); @@ -475,15 +431,13 @@ public void ModelFactory_ConvertFrom_ListUserDetails_ModelsConverted() [Fact] public void ModelFactory_ConvertFrom_RoleDetails_ModelConverted() { - IModelFactory modelFactory = new ModelFactory(); - RoleDetails roleDetailsModel = new RoleDetails { RoleId = Guid.Parse(TestData.Role1Id), RoleName = TestData.RoleName }; - DataTransferObjects.Responses.RoleDetails roleDetailsDto = modelFactory.ConvertFrom(roleDetailsModel); + DataTransferObjects.Responses.RoleDetails roleDetailsDto = ModelFactory.ConvertFrom(roleDetailsModel); roleDetailsDto.RoleId.ShouldBe(Guid.Parse(TestData.Role1Id)); roleDetailsDto.RoleName.ShouldBe(TestData.RoleName); @@ -492,11 +446,9 @@ public void ModelFactory_ConvertFrom_RoleDetails_ModelConverted() [Fact] public void ModelFactory_ConvertFrom_RoleDetails_ModelIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - RoleDetails roleDetailsModel = null; - DataTransferObjects.Responses.RoleDetails roleDetailsDto = modelFactory.ConvertFrom(roleDetailsModel); + DataTransferObjects.Responses.RoleDetails roleDetailsDto = ModelFactory.ConvertFrom(roleDetailsModel); roleDetailsDto.ShouldBeNull(); } @@ -504,8 +456,6 @@ public void ModelFactory_ConvertFrom_RoleDetails_ModelIsNull_NullReturned() [Fact] public void ModelFactory_ConvertFrom_UserDetails_ModelConverted() { - IModelFactory modelFactory = new ModelFactory(); - UserDetails userDetailsModel = new UserDetails { PhoneNumber = TestData.PhoneNumber, @@ -516,7 +466,7 @@ public void ModelFactory_ConvertFrom_UserDetails_ModelConverted() Claims = TestData.Claims }; - DataTransferObjects.Responses.UserDetails userDetailsDto = modelFactory.ConvertFrom(userDetailsModel); + DataTransferObjects.Responses.UserDetails userDetailsDto = ModelFactory.ConvertFrom(userDetailsModel); userDetailsDto.UserName.ShouldBe(TestData.UserName); userDetailsDto.EmailAddress.ShouldBe(TestData.EmailAddress); @@ -529,11 +479,9 @@ public void ModelFactory_ConvertFrom_UserDetails_ModelConverted() [Fact] public void ModelFactory_ConvertFrom_UserDetails_ModelIsNull_NullReturned() { - IModelFactory modelFactory = new ModelFactory(); - UserDetails userDetailsModel = null; - DataTransferObjects.Responses.UserDetails userDetailsDto = modelFactory.ConvertFrom(userDetailsModel); + DataTransferObjects.Responses.UserDetails userDetailsDto = ModelFactory.ConvertFrom(userDetailsModel); userDetailsDto.ShouldBeNull(); } diff --git a/SecurityService.UserInterface/Common/ClaimExtensions.cs b/SecurityService.UserInterface/Common/ClaimExtensions.cs new file mode 100644 index 00000000..0adbe7ab --- /dev/null +++ b/SecurityService.UserInterface/Common/ClaimExtensions.cs @@ -0,0 +1,46 @@ +using Duende.IdentityModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; + +namespace SecurityService.UserInterface.Common +{ + public static class ClaimExtensions + { + public static string? GetClaimValue(this IEnumerable claims, params string[] types) + { + return types + .Select(t => claims.FirstOrDefault(c => c.Type == t)?.Value) + .FirstOrDefault(v => v != null); + } + + public static List BuildDisplayNameClaims(this IEnumerable claims) + { + // 1. Name + var name = claims.GetClaimValue(JwtClaimTypes.Name, ClaimTypes.Name); + if (name != null) + { + return new List { new Claim(JwtClaimTypes.Name, name) }; + } + + // 2. Given/Family name fallback + var first = claims.GetClaimValue(JwtClaimTypes.GivenName, ClaimTypes.GivenName); + var last = claims.GetClaimValue(JwtClaimTypes.FamilyName, ClaimTypes.Surname); + + var full = (first, last) switch + { + (not null, not null) => $"{first} {last}", + (not null, null) => first, + (null, not null) => last, + _ => null + }; + + return full != null + ? new List { new Claim(JwtClaimTypes.Name, full) } + : new List(); + } + } +} diff --git a/SecurityService.UserInterface/Pages/Account/ForgotPassword/Confirm.cshtml.cs b/SecurityService.UserInterface/Pages/Account/ForgotPassword/Confirm.cshtml.cs index 50c4aeb7..c764d0ed 100644 --- a/SecurityService.UserInterface/Pages/Account/ForgotPassword/Confirm.cshtml.cs +++ b/SecurityService.UserInterface/Pages/Account/ForgotPassword/Confirm.cshtml.cs @@ -37,9 +37,9 @@ public Confirm(IMediator mediator){ this.Mediator = mediator; } - public async Task OnGet(string returnUrl) { + public async Task OnGet() { // Process the query string and populate the view model with username (read only) - await BuildModelAsync(returnUrl, Request.QueryString); + await BuildModelAsync(Request.QueryString); return Page(); } @@ -74,7 +74,7 @@ public async Task OnPost(CancellationToken cancellationToken) return Page(); } - private async Task BuildModelAsync(string returnUrl, QueryString queryString) + private async Task BuildModelAsync(QueryString queryString) { NameValueCollection parsedQueryString = HttpUtility.ParseQueryString(Request.QueryString.ToString()); String userName = parsedQueryString["userName"]; diff --git a/SecurityService.UserInterface/Pages/Ciba/Consent.cshtml.cs b/SecurityService.UserInterface/Pages/Ciba/Consent.cshtml.cs index ee59dcb1..1b836c65 100644 --- a/SecurityService.UserInterface/Pages/Ciba/Consent.cshtml.cs +++ b/SecurityService.UserInterface/Pages/Ciba/Consent.cshtml.cs @@ -9,11 +9,14 @@ namespace IdentityServerHost.Pages.Ciba; +using Azure.Core; +using MediatR; +using Microsoft.Extensions.Logging; +using SimpleResults; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; [Authorize] [SecurityHeadersAttribute] @@ -54,12 +57,45 @@ public async Task OnGet(string id) return Page(); } + private async Task HandleNoButtonClicked(BackchannelUserLoginRequest request) { + CompleteBackchannelLoginRequest result = new(Input.Id); + + // emit event + await _events.RaiseAsync(new ConsentDeniedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues)); + + return result; + } + + private async Task HandleYesButtonClicked(BackchannelUserLoginRequest request) { + // if the user consented to some scope, build the response model + if (Input.ScopesConsented != null && Input.ScopesConsented.Any()) + { + var scopes = Input.ScopesConsented; + if (ConsentOptions.EnableOfflineAccess == false) + { + scopes = scopes.Where(x => x != Duende.IdentityServer.IdentityServerConstants.StandardScopes.OfflineAccess); + } + + CompleteBackchannelLoginRequest result = new CompleteBackchannelLoginRequest(Input.Id) + { + ScopesValuesConsented = scopes.ToArray(), + Description = Input.Description + }; + + // emit event + await _events.RaiseAsync(new ConsentGrantedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues, result.ScopesValuesConsented, false)); + return result; + } + + this.ModelState.AddModelError("", ConsentOptions.MustChooseOneErrorMessage); + return null; + } + public async Task OnPost() { // validate return url is still valid - var request = await _interaction.GetLoginRequestByInternalIdAsync(Input.Id); - if (request == null || request.Subject.GetSubjectId() != User.GetSubjectId()) - { + BackchannelUserLoginRequest? request = await _interaction.GetLoginRequestByInternalIdAsync(Input.Id); + if (request == null || request.Subject.GetSubjectId() != User.GetSubjectId()) { _logger.LogError("Invalid id {id}", Input.Id); return RedirectToPage("/Home/Error/Index"); } @@ -67,49 +103,20 @@ public async Task OnPost() CompleteBackchannelLoginRequest result = null; // user clicked 'no' - send back the standard 'access_denied' response - if (Input?.Button == "no") - { - result = new CompleteBackchannelLoginRequest(Input.Id); - - // emit event - await _events.RaiseAsync(new ConsentDeniedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues)); + if (Input?.Button == "no") { + result = await HandleNoButtonClicked(request); } // user clicked 'yes' - validate the data - else if (Input?.Button == "yes") - { - // if the user consented to some scope, build the response model - if (Input.ScopesConsented != null && Input.ScopesConsented.Any()) - { - var scopes = Input.ScopesConsented; - if (ConsentOptions.EnableOfflineAccess == false) - { - scopes = scopes.Where(x => x != Duende.IdentityServer.IdentityServerConstants.StandardScopes.OfflineAccess); - } - - result = new CompleteBackchannelLoginRequest(Input.Id) - { - ScopesValuesConsented = scopes.ToArray(), - Description = Input.Description - }; - - // emit event - await _events.RaiseAsync(new ConsentGrantedEvent(User.GetSubjectId(), request.Client.ClientId, request.ValidatedResources.RawScopeValues, result.ScopesValuesConsented, false)); - } - else - { - ModelState.AddModelError("", ConsentOptions.MustChooseOneErrorMessage); - } + else if (Input?.Button == "yes") { + result = await HandleYesButtonClicked(request); } - else - { + else { ModelState.AddModelError("", ConsentOptions.InvalidSelectionErrorMessage); } - if (result != null) - { + if (result != null) { // communicate outcome of consent back to identityserver await _interaction.CompleteLoginRequestAsync(result); - return RedirectToPage("/Ciba/All"); } @@ -123,7 +130,7 @@ private async Task BuildViewModelAsync(string id, InputModel model = var request = await _interaction.GetLoginRequestByInternalIdAsync(id); if (request != null && request.Subject.GetSubjectId() == User.GetSubjectId()) { - return CreateConsentViewModel(model, id, request); + return CreateConsentViewModel(model, request); } else { @@ -133,8 +140,7 @@ private async Task BuildViewModelAsync(string id, InputModel model = } private ViewModel CreateConsentViewModel( - InputModel model, string id, - BackchannelUserLoginRequest request) + InputModel model, BackchannelUserLoginRequest request) { var vm = new ViewModel { diff --git a/SecurityService.UserInterface/Pages/Device/Index.cshtml.cs b/SecurityService.UserInterface/Pages/Device/Index.cshtml.cs index c1f27aff..fa4f64ee 100644 --- a/SecurityService.UserInterface/Pages/Device/Index.cshtml.cs +++ b/SecurityService.UserInterface/Pages/Device/Index.cshtml.cs @@ -147,35 +147,69 @@ private async Task BuildViewModelAsync(string userCode, InputModel mo private ViewModel CreateConsentViewModel(InputModel model, DeviceFlowAuthorizationRequest request) { - var vm = new ViewModel + return new ViewModel { - ClientName = request.Client.ClientName ?? request.Client.ClientId, + ClientName = GetClientName(request), ClientUrl = request.Client.ClientUri, ClientLogoUrl = request.Client.LogoUri, - AllowRememberConsent = request.Client.AllowRememberConsent + AllowRememberConsent = request.Client.AllowRememberConsent, + IdentityScopes = CreateIdentityScopes(model, request), + ApiScopes = CreateApiScopes(model, request) }; + } - vm.IdentityScopes = request.ValidatedResources.Resources.IdentityResources.Select(x => CreateScopeViewModel(x, model == null || model.ScopesConsented?.Contains(x.Name) == true)).ToArray(); + private string GetClientName(DeviceFlowAuthorizationRequest request) => + request.Client.ClientName ?? request.Client.ClientId; - var apiScopes = new List(); - foreach (var parsedScope in request.ValidatedResources.ParsedScopes) - { - var apiScope = request.ValidatedResources.Resources.FindApiScope(parsedScope.ParsedName); - if (apiScope != null) - { - var scopeVm = CreateScopeViewModel(parsedScope, apiScope, model == null || model.ScopesConsented?.Contains(parsedScope.RawValue) == true); - apiScopes.Add(scopeVm); - } - } - if (DeviceOptions.EnableOfflineAccess && request.ValidatedResources.Resources.OfflineAccess) + private bool IsConsented(InputModel model, string scope) => + model == null || model.ScopesConsented?.Contains(scope) == true; + + private ScopeViewModel[] CreateIdentityScopes(InputModel model, DeviceFlowAuthorizationRequest request) + { + return request.ValidatedResources.Resources.IdentityResources + .Select(x => CreateScopeViewModel(x, IsConsented(model, x.Name))) + .ToArray(); + } + + private List CreateApiScopes(InputModel model, DeviceFlowAuthorizationRequest request) + { + var apiScopes = request.ValidatedResources.ParsedScopes + .Select(parsed => BuildApiScopeViewModel(model, request, parsed)) + .Where(vm => vm != null) + .ToList(); + + if (ShouldIncludeOfflineAccess(request)) { - apiScopes.Add(GetOfflineAccessScope(model == null || model.ScopesConsented?.Contains(Duende.IdentityServer.IdentityServerConstants.StandardScopes.OfflineAccess) == true)); + apiScopes.Add(GetOfflineAccessScope( + IsConsented(model, Duende.IdentityServer.IdentityServerConstants.StandardScopes.OfflineAccess) + )); } - vm.ApiScopes = apiScopes; - return vm; + return apiScopes; + } + + private ScopeViewModel? BuildApiScopeViewModel( + InputModel model, + DeviceFlowAuthorizationRequest request, + ParsedScopeValue parsedScope) + { + var apiScope = request.ValidatedResources.Resources.FindApiScope(parsedScope.ParsedName); + if (apiScope == null) return null; + + return CreateScopeViewModel( + parsedScope, + apiScope, + IsConsented(model, parsedScope.RawValue) + ); } + private bool ShouldIncludeOfflineAccess(DeviceFlowAuthorizationRequest request) + { + return DeviceOptions.EnableOfflineAccess && + request.ValidatedResources.Resources.OfflineAccess; + } + + private ScopeViewModel CreateScopeViewModel(IdentityResource identity, bool check) { return new ScopeViewModel diff --git a/SecurityService.UserInterface/Pages/ExternalLogin/Callback.cshtml.cs b/SecurityService.UserInterface/Pages/ExternalLogin/Callback.cshtml.cs index e9714e96..5d475665 100644 --- a/SecurityService.UserInterface/Pages/ExternalLogin/Callback.cshtml.cs +++ b/SecurityService.UserInterface/Pages/ExternalLogin/Callback.cshtml.cs @@ -9,6 +9,8 @@ using Microsoft.AspNetCore.Mvc.RazorPages; using System.Security.Claims; using Duende.IdentityModel; +using Duende.IdentityServer.Models; +using SecurityService.UserInterface.Common; namespace IdentityServerHost.Pages.ExternalLogin; @@ -42,141 +44,222 @@ public Callback( _logger = logger; _events = events; } - + public async Task OnGet() { - // read external identity from the temporary cookie - var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme); + var result = await AuthenticateExternalAsync(); + + LogExternalClaims(result.Principal); + + var (provider, providerUserId) = GetExternalProviderInfo(result); + var user = await FindOrProvisionUserAsync(provider, providerUserId, result.Principal.Claims); + + var (claims, props) = CaptureExternalContext(result); + await SignInUserAsync(user, claims, props); + + await ClearTemporaryExternalCookieAsync(); + + var returnUrl = GetReturnUrl(result); + var context = await _interaction.GetAuthorizationContextAsync(returnUrl); + + await RaiseLoginSuccessEvent(provider, providerUserId, user, context); + + return context?.IsNativeClient() == true + ? this.LoadingPage(returnUrl) + : Redirect(returnUrl); + } + + private async Task AuthenticateExternalAsync() + { + var result = await HttpContext.AuthenticateAsync( + IdentityServerConstants.ExternalCookieAuthenticationScheme); + if (result?.Succeeded != true) - { throw new AuthenticationException("External authentication error"); - } - var externalUser = result.Principal; + return result; + } - if (_logger.IsEnabled(LogLevel.Debug)) - { - var externalClaims = externalUser.Claims.Select(c => $"{c.Type}: {c.Value}"); - _logger.LogDebug("External claims: {@claims}", externalClaims); - } + private void LogExternalClaims(ClaimsPrincipal externalUser) + { + if (!_logger.IsEnabled(LogLevel.Debug)) return; - // lookup our user and external provider info - // try to determine the unique id of the external user (issued by the provider) - // the most common claim type for that are the sub claim and the NameIdentifier - // depending on the external provider, some other claim type might be used - var userIdClaim = externalUser.FindFirst(JwtClaimTypes.Subject) ?? - externalUser.FindFirst(ClaimTypes.NameIdentifier) ?? - throw new AuthenticationException("Unknown userid"); + var claims = externalUser.Claims.Select(c => $"{c.Type}: {c.Value}"); + _logger.LogDebug("External claims: {@claims}", claims); + } + + private (string provider, string providerUserId) GetExternalProviderInfo(AuthenticateResult result) + { + var externalUser = result.Principal; + + var userIdClaim = + externalUser.FindFirst(JwtClaimTypes.Subject) ?? + externalUser.FindFirst(ClaimTypes.NameIdentifier) ?? + throw new AuthenticationException("Unknown userid"); var provider = result.Properties.Items["scheme"]; var providerUserId = userIdClaim.Value; - // find external user + return (provider, providerUserId); + } + + private async Task FindOrProvisionUserAsync( + string provider, string providerUserId, IEnumerable claims) + { var user = await _userManager.FindByLoginAsync(provider, providerUserId); - if (user == null) - { - // this might be where you might initiate a custom workflow for user registration - // in this sample we don't show how that would be done, as our sample implementation - // simply auto-provisions new external user - user = await AutoProvisionUserAsync(provider, providerUserId, externalUser.Claims); - } - // this allows us to collect any additional claims or properties - // for the specific protocols used and store them in the local auth cookie. - // this is typically used to store data needed for signout from those protocols. - var additionalLocalClaims = new List(); - var localSignInProps = new AuthenticationProperties(); - CaptureExternalLoginContext(result, additionalLocalClaims, localSignInProps); + return user ?? await AutoProvisionUserAsync(provider, providerUserId, claims); + } - // issue authentication cookie for user - await _signInManager.SignInWithClaimsAsync(user, localSignInProps, additionalLocalClaims); + private (List claims, AuthenticationProperties props) + CaptureExternalContext(AuthenticateResult result) + { + var additionalClaims = new List(); + var props = new AuthenticationProperties(); - // delete temporary cookie used during external authentication - await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme); + CaptureExternalLoginContext(result, additionalClaims, props); - // retrieve return URL - var returnUrl = result.Properties.Items["returnUrl"] ?? "~/"; + return (additionalClaims, props); + } - // check if external login is in the context of an OIDC request - var context = await _interaction.GetAuthorizationContextAsync(returnUrl); - await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, user.UserName, true, context?.Client.ClientId)); + private Task SignInUserAsync( + ApplicationUser user, + List claims, + AuthenticationProperties props) + { + return _signInManager.SignInWithClaimsAsync(user, props, claims); + } + + private Task RaiseLoginSuccessEvent( + string provider, + string providerUserId, + ApplicationUser user, + AuthorizationRequest context) + { + return _events.RaiseAsync( + new UserLoginSuccessEvent( + provider, + providerUserId, + user.Id, + user.UserName, + true, + context?.Client.ClientId)); + } - if (context != null) - { - if (context.IsNativeClient()) - { - // The client is native, so this change in how to - // return the response is for better UX for the end user. - return this.LoadingPage(returnUrl); - } - } - return Redirect(returnUrl); + private static string GetReturnUrl(AuthenticateResult result) + { + return result.Properties.Items["returnUrl"] ?? "~/"; } - private async Task AutoProvisionUserAsync(string provider, string providerUserId, IEnumerable claims) + + private Task ClearTemporaryExternalCookieAsync() { - var sub = Guid.NewGuid().ToString(); - - var user = new ApplicationUser() + return HttpContext.SignOutAsync( + IdentityServerConstants.ExternalCookieAuthenticationScheme); + } + + + private static async Task EnsureSucceededAsync(IdentityResult result) + { + if (!result.Succeeded) + throw new AuthenticationException(result.Errors.First().Description); + } + + private async Task AutoProvisionUserAsync( + string provider, + string providerUserId, + IEnumerable claims) + { + string sub = Guid.NewGuid().ToString(); + + var user = new ApplicationUser { Id = sub, - UserName = sub, // don't need a username, since the user will be using an external provider to login + UserName = sub, + Email = claims.GetClaimValue(JwtClaimTypes.Email, ClaimTypes.Email) }; - // email - var email = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Email)?.Value ?? - claims.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value; - if (email != null) - { - user.Email = email; - } - - // create a list of claims that we want to transfer into our store - var filtered = new List(); - - // user's display name - var name = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Name)?.Value ?? - claims.FirstOrDefault(x => x.Type == ClaimTypes.Name)?.Value; - if (name != null) - { - filtered.Add(new Claim(JwtClaimTypes.Name, name)); - } - else - { - var first = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.GivenName)?.Value ?? - claims.FirstOrDefault(x => x.Type == ClaimTypes.GivenName)?.Value; - var last = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.FamilyName)?.Value ?? - claims.FirstOrDefault(x => x.Type == ClaimTypes.Surname)?.Value; - if (first != null && last != null) - { - filtered.Add(new Claim(JwtClaimTypes.Name, first + " " + last)); - } - else if (first != null) - { - filtered.Add(new Claim(JwtClaimTypes.Name, first)); - } - else if (last != null) - { - filtered.Add(new Claim(JwtClaimTypes.Name, last)); - } - } + var nameClaims = claims.BuildDisplayNameClaims(); - var identityResult = await _userManager.CreateAsync(user); - if (!identityResult.Succeeded) throw new AuthenticationException(identityResult.Errors.First().Description); + await EnsureSucceededAsync(await _userManager.CreateAsync(user)); - if (filtered.Any()) + if (nameClaims.Any()) { - identityResult = await _userManager.AddClaimsAsync(user, filtered); - if (!identityResult.Succeeded) throw new AuthenticationException(identityResult.Errors.First().Description); + await EnsureSucceededAsync(await _userManager + .AddClaimsAsync(user, nameClaims)); } - identityResult = await _userManager.AddLoginAsync(user, new UserLoginInfo(provider, providerUserId, provider)); - if (!identityResult.Succeeded) throw new AuthenticationException(identityResult.Errors.First().Description); + await EnsureSucceededAsync( + _userManager.AddLoginAsync(user, new UserLoginInfo(provider, providerUserId, provider))); return user; } + + //private async Task AutoProvisionUserAsync(string provider, string providerUserId, IEnumerable claims) + //{ + // var sub = Guid.NewGuid().ToString(); + + // var user = new ApplicationUser() + // { + // Id = sub, + // UserName = sub, // don't need a username, since the user will be using an external provider to login + // }; + + // // email + // var email = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Email)?.Value ?? + // claims.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value; + // if (email != null) + // { + // user.Email = email; + // } + + // // create a list of claims that we want to transfer into our store + // var filtered = new List(); + + // // user's display name + // var name = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Name)?.Value ?? + // claims.FirstOrDefault(x => x.Type == ClaimTypes.Name)?.Value; + // if (name != null) + // { + // filtered.Add(new Claim(JwtClaimTypes.Name, name)); + // } + // else + // { + // var first = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.GivenName)?.Value ?? + // claims.FirstOrDefault(x => x.Type == ClaimTypes.GivenName)?.Value; + // var last = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.FamilyName)?.Value ?? + // claims.FirstOrDefault(x => x.Type == ClaimTypes.Surname)?.Value; + // if (first != null && last != null) + // { + // filtered.Add(new Claim(JwtClaimTypes.Name, first + " " + last)); + // } + // else if (first != null) + // { + // filtered.Add(new Claim(JwtClaimTypes.Name, first)); + // } + // else if (last != null) + // { + // filtered.Add(new Claim(JwtClaimTypes.Name, last)); + // } + // } + + // var identityResult = await _userManager.CreateAsync(user); + // if (!identityResult.Succeeded) throw new AuthenticationException(identityResult.Errors.First().Description); + + // if (filtered.Any()) + // { + // identityResult = await _userManager.AddClaimsAsync(user, filtered); + // if (!identityResult.Succeeded) throw new AuthenticationException(identityResult.Errors.First().Description); + // } + + // identityResult = await _userManager.AddLoginAsync(user, new UserLoginInfo(provider, providerUserId, provider)); + // if (!identityResult.Succeeded) throw new AuthenticationException(identityResult.Errors.First().Description); + + // return user; + //} + // if the external login is OIDC-based, there are certain things we need to preserve to make logout work // this will be different for WS-Fed, SAML2p or other protocols private void CaptureExternalLoginContext(AuthenticateResult externalResult, List localClaims, AuthenticationProperties localSignInProps) diff --git a/SecurityService/Bootstrapper/MiscRegistry.cs b/SecurityService/Bootstrapper/MiscRegistry.cs index 20e34b39..2e0b8f69 100644 --- a/SecurityService/Bootstrapper/MiscRegistry.cs +++ b/SecurityService/Bootstrapper/MiscRegistry.cs @@ -27,8 +27,6 @@ public MiscRegistry() { this.AddHttpContextAccessor(); - this.AddSingleton(); - if (Startup.WebHostEnvironment.IsEnvironment("IntegrationTest")) { this.AddSingleton(); } diff --git a/SecurityService/Dockerfile b/SecurityService/Dockerfile index 166c72fe..e63307f1 100644 --- a/SecurityService/Dockerfile +++ b/SecurityService/Dockerfile @@ -1,4 +1,4 @@ -FROM stuartferguson/txnprocbase AS base +FROM stuartferguson/txnprocbase:latest AS base WORKDIR /app FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build diff --git a/SecurityService/Factories/IModelFactory.cs b/SecurityService/Factories/IModelFactory.cs deleted file mode 100644 index e5376cd7..00000000 --- a/SecurityService/Factories/IModelFactory.cs +++ /dev/null @@ -1,105 +0,0 @@ -using UserDetailsDto = SecurityService.DataTransferObjects.Responses.UserDetails; -using RoleDetailsDto = SecurityService.DataTransferObjects.Responses.RoleDetails; -using UserDetailsModel = SecurityService.Models.UserDetails; -using RoleDetailsModel = SecurityService.Models.RoleDetails; - -namespace SecurityService.Factories -{ - using System.Collections.Generic; - using DataTransferObjects.Responses; - using Duende.IdentityServer.Models; - - /// - /// - /// - public interface IModelFactory - { - #region Methods - - /// - /// Converts from. - /// - /// The model. - /// - UserDetailsDto ConvertFrom(UserDetailsModel model); - - /// - /// Converts from. - /// - /// The model. - /// - RoleDetailsDto ConvertFrom(RoleDetailsModel model); - - /// - /// Converts from. - /// - /// The model. - /// - List ConvertFrom(List model); - - /// - /// Converts from. - /// - /// The model. - /// - List ConvertFrom(List model); - - /// - /// Converts from. - /// - /// The model. - /// - ClientDetails ConvertFrom(Client model); - - /// - /// Converts from. - /// - /// The model. - /// - List ConvertFrom(List model); - - /// - /// Converts from. - /// - /// The model. - /// - ApiResourceDetails ConvertFrom(ApiResource model); - - /// - /// Converts from. - /// - /// The model. - /// - ApiScopeDetails ConvertFrom(ApiScope model); - - /// - /// Converts from. - /// - /// The model. - /// - List ConvertFrom(List model); - - /// - /// Converts from. - /// - /// The model. - /// - IdentityResourceDetails ConvertFrom(IdentityResource model); - - /// - /// Converts from. - /// - /// The model. - /// - List ConvertFrom(List model); - - /// - /// Converts from. - /// - /// The model. - /// - List ConvertFrom(List model); - - #endregion - } -} \ No newline at end of file diff --git a/SecurityService/Factories/ModelFactory.cs b/SecurityService/Factories/ModelFactory.cs index 3298cabf..28ea355d 100644 --- a/SecurityService/Factories/ModelFactory.cs +++ b/SecurityService/Factories/ModelFactory.cs @@ -5,279 +5,170 @@ using DataTransferObjects.Responses; using Duende.IdentityServer.Models; - /// - /// - /// - /// - public class ModelFactory : IModelFactory - { + public static class ModelFactory { #region Methods - /// - /// Converts from. - /// - /// The model. - /// - public UserDetails ConvertFrom(Models.UserDetails model) - { - if (model == null) - { + public static UserDetails ConvertFrom(Models.UserDetails model) { + if (model == null) { return null; } - return new UserDetails - { - UserName = model.Username, - PhoneNumber = model.PhoneNumber, - Roles = model.Roles, - Claims = model.Claims, - UserId = model.UserId, - EmailAddress = model.Email, - RegistrationDateTime = model.RegistrationDateTime - }; + return new UserDetails { + UserName = model.Username, + PhoneNumber = model.PhoneNumber, + Roles = model.Roles, + Claims = model.Claims, + UserId = model.UserId, + EmailAddress = model.Email, + RegistrationDateTime = model.RegistrationDateTime + }; } - /// - /// Converts from. - /// - /// The model. - /// - public RoleDetails ConvertFrom(Models.RoleDetails model) - { - if (model == null) - { + public static RoleDetails ConvertFrom(Models.RoleDetails model) { + if (model == null) { return null; } - return new RoleDetails - { - RoleId = model.RoleId, - RoleName = model.RoleName - }; + return new RoleDetails { RoleId = model.RoleId, RoleName = model.RoleName }; } - /// - /// Converts from. - /// - /// The model. - /// - public List ConvertFrom(List model) - { - if (model == null || model.Any() == false) - { + public static List ConvertFrom(List model) { + if (model == null || model.Any() == false) { return new List(); } List userDetailsList = new List(); - foreach (Models.UserDetails userDetails in model) - { - userDetailsList.Add(this.ConvertFrom(userDetails)); + foreach (Models.UserDetails userDetails in model) { + userDetailsList.Add(ConvertFrom(userDetails)); } return userDetailsList; } - /// - /// Converts from. - /// - /// The model. - /// - public List ConvertFrom(List model) - { - if (model == null || model.Any() == false) - { - return null; + public static List ConvertFrom(List model) { + if (model == null || model.Any() == false) { + return new List(); } List roleDetailsList = new List(); - foreach (Models.RoleDetails roleDetails in model) - { - roleDetailsList.Add(this.ConvertFrom(roleDetails)); + foreach (Models.RoleDetails roleDetails in model) { + roleDetailsList.Add(ConvertFrom(roleDetails)); } return roleDetailsList; } - /// - /// Converts from. - /// - /// The model. - /// - public ClientDetails ConvertFrom(Client model) - { - if (model == null) - { + public static ClientDetails ConvertFrom(Client model) { + if (model == null) { return null; } - return new ClientDetails - { - ClientId = model.ClientId, - AllowedScopes = model.AllowedScopes.ToList(), - AllowedGrantTypes = model.AllowedGrantTypes.ToList(), - ClientName = model.ClientName, - ClientDescription = model.Description, - Enabled = model.Enabled, - ClientPostLogoutRedirectUris = model.PostLogoutRedirectUris.ToList(), - RequireConsent = model.RequireConsent, - ClientRedirectUris = model.RedirectUris.ToList(), - AllowOfflineAccess = model.AllowOfflineAccess - }; + return new ClientDetails { + ClientId = model.ClientId, + AllowedScopes = model.AllowedScopes.ToList(), + AllowedGrantTypes = model.AllowedGrantTypes.ToList(), + ClientName = model.ClientName, + ClientDescription = model.Description, + Enabled = model.Enabled, + ClientPostLogoutRedirectUris = model.PostLogoutRedirectUris.ToList(), + RequireConsent = model.RequireConsent, + ClientRedirectUris = model.RedirectUris.ToList(), + AllowOfflineAccess = model.AllowOfflineAccess + }; } - /// - /// Converts from. - /// - /// The model. - /// - public List ConvertFrom(List model) - { - if (model == null || model.Any() == false) - { - return null; + public static List ConvertFrom(List model) { + if (model == null || model.Any() == false) { + return new List(); } List clientDetailsList = new List(); - foreach (Client client in model) - { - clientDetailsList.Add(this.ConvertFrom(client)); + foreach (Client client in model) { + clientDetailsList.Add(ConvertFrom(client)); } return clientDetailsList; } - /// - /// Converts from. - /// - /// The model. - /// - public ApiResourceDetails ConvertFrom(ApiResource model) - { - if (model == null) - { + public static ApiResourceDetails ConvertFrom(ApiResource model) { + if (model == null) { return null; } - return new ApiResourceDetails - { - Description = model.Description, - Scopes = model.Scopes.ToList(), - Name = model.Name, - DisplayName = model.DisplayName, - UserClaims = model.UserClaims.ToList(), - Enabled = model.Enabled - }; + return new ApiResourceDetails { + Description = model.Description, + Scopes = model.Scopes.ToList(), + Name = model.Name, + DisplayName = model.DisplayName, + UserClaims = model.UserClaims.ToList(), + Enabled = model.Enabled + }; } - /// - /// Converts from. - /// - /// The model. - /// - public ApiScopeDetails ConvertFrom(ApiScope model) - { - if (model == null) - { + public static ApiScopeDetails ConvertFrom(ApiScope model) { + if (model == null) { return null; } - return new ApiScopeDetails - { - Enabled = model.Enabled, - DisplayName = model.DisplayName, - Name = model.Name, - Description = model.Description - }; + return new ApiScopeDetails { Enabled = model.Enabled, DisplayName = model.DisplayName, Name = model.Name, Description = model.Description }; } - /// - /// Converts from. - /// - /// The model. - /// - public List ConvertFrom(List model) - { - if (model == null || model.Any() == false) - { - return null; + public static List ConvertFrom(List model) { + if (model == null || model.Any() == false) { + return new List(); } List apiScopeDetailsList = new List(); - foreach (ApiScope apiScope in model) - { - apiScopeDetailsList.Add(this.ConvertFrom(apiScope)); + foreach (ApiScope apiScope in model) { + apiScopeDetailsList.Add(ConvertFrom(apiScope)); } return apiScopeDetailsList; } - /// - /// Converts from. - /// - /// The model. - /// - public IdentityResourceDetails ConvertFrom(IdentityResource model) - { - if (model == null) - { + public static IdentityResourceDetails ConvertFrom(IdentityResource model) { + if (model == null) { return null; } - return new IdentityResourceDetails - { - Claims = model.UserClaims.ToList(), - DisplayName = model.DisplayName, - Emphasize = model.Emphasize, - Required = model.Required, - ShowInDiscoveryDocument = model.ShowInDiscoveryDocument, - Description = model.Description, - Name = model.Name - }; + return new IdentityResourceDetails { + Claims = model.UserClaims.ToList(), + DisplayName = model.DisplayName, + Emphasize = model.Emphasize, + Required = model.Required, + ShowInDiscoveryDocument = model.ShowInDiscoveryDocument, + Description = model.Description, + Name = model.Name + }; } - /// - /// Converts from. - /// - /// The model. - /// - public List ConvertFrom(List model) - { - if (model == null || model.Any() == false) - { - return null; + public static List ConvertFrom(List model) { + if (model == null || model.Any() == false) { + return new List(); } List apiResourceDetailsList = new List(); - foreach (ApiResource apiResource in model) - { - apiResourceDetailsList.Add(this.ConvertFrom(apiResource)); + foreach (ApiResource apiResource in model) { + apiResourceDetailsList.Add(ConvertFrom(apiResource)); } return apiResourceDetailsList; } - /// - /// Converts from. - /// - /// The model. - /// - public List ConvertFrom(List model) - { - if (model == null || model.Any() == false) - { - return null; + public static List ConvertFrom(List model) { + if (model == null || model.Any() == false) { + return new List(); } List identityResourceDetailsList = new List(); - foreach (IdentityResource identityResource in model) - { - identityResourceDetailsList.Add(this.ConvertFrom(identityResource)); + foreach (IdentityResource identityResource in model) { + identityResourceDetailsList.Add(ConvertFrom(identityResource)); } return identityResourceDetailsList; diff --git a/SecurityService/Handlers/ApiResourceHandler.cs b/SecurityService/Handlers/ApiResourceHandler.cs index bdcb2726..e34117a5 100644 --- a/SecurityService/Handlers/ApiResourceHandler.cs +++ b/SecurityService/Handlers/ApiResourceHandler.cs @@ -22,7 +22,7 @@ public static async Task CreateApiResource(IMediator mediator, CreateApiResourceRequest createApiResourceRequest, CancellationToken cancellationToken) { - var command = new SecurityServiceCommands.CreateApiResourceCommand( + SecurityServiceCommands.CreateApiResourceCommand command = new SecurityServiceCommands.CreateApiResourceCommand( createApiResourceRequest.Name, createApiResourceRequest.DisplayName, createApiResourceRequest.Description, @@ -36,26 +36,24 @@ public static async Task CreateApiResource(IMediator mediator, } public static async Task GetApiResource(IMediator mediator, - IModelFactory modelFactory, string apiResourceName, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetApiResourceQuery(apiResourceName); + SecurityServiceQueries.GetApiResourceQuery query = new SecurityServiceQueries.GetApiResourceQuery(apiResourceName); Result result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } public static async Task GetApiResources(IMediator mediator, - IModelFactory modelFactory, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetApiResourcesQuery(); + SecurityServiceQueries.GetApiResourcesQuery query = new SecurityServiceQueries.GetApiResourcesQuery(); Result> result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } } } \ No newline at end of file diff --git a/SecurityService/Handlers/ApiScopeHandler.cs b/SecurityService/Handlers/ApiScopeHandler.cs index 0bb8048c..99338e1c 100644 --- a/SecurityService/Handlers/ApiScopeHandler.cs +++ b/SecurityService/Handlers/ApiScopeHandler.cs @@ -22,7 +22,7 @@ public static async Task CreateApiScope(IMediator mediator, CreateApiScopeRequest createApiScopeRequest, CancellationToken cancellationToken) { - var command = new SecurityServiceCommands.CreateApiScopeCommand( + SecurityServiceCommands.CreateApiScopeCommand command = new SecurityServiceCommands.CreateApiScopeCommand( createApiScopeRequest.Name, createApiScopeRequest.DisplayName, createApiScopeRequest.Description); @@ -33,26 +33,24 @@ public static async Task CreateApiScope(IMediator mediator, } public static async Task GetApiScope(IMediator mediator, - IModelFactory modelFactory, string apiScopeName, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetApiScopeQuery(apiScopeName); + SecurityServiceQueries.GetApiScopeQuery query = new SecurityServiceQueries.GetApiScopeQuery(apiScopeName); Result result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } public static async Task GetApiScopes(IMediator mediator, - IModelFactory modelFactory, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetApiScopesQuery(); + SecurityServiceQueries.GetApiScopesQuery query = new SecurityServiceQueries.GetApiScopesQuery(); Result> result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } } } \ No newline at end of file diff --git a/SecurityService/Handlers/ClientHandler.cs b/SecurityService/Handlers/ClientHandler.cs index d402997e..ecb62dba 100644 --- a/SecurityService/Handlers/ClientHandler.cs +++ b/SecurityService/Handlers/ClientHandler.cs @@ -1,10 +1,8 @@ -using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MediatR; using SecurityService.BusinessLogic.Requests; -using Shared.Results; using Shared.Results.Web; using SimpleResults; @@ -13,8 +11,6 @@ namespace SecurityService.Handlers using DataTransferObjects.Requests; using Factories; using Microsoft.AspNetCore.Http; - using Microsoft.AspNetCore.Mvc; - using SecurityService.BusinessLogic; public static class ClientHandler { @@ -22,7 +18,7 @@ public static async Task CreateClient(IMediator mediator, CreateClientRequest createClientRequest, CancellationToken cancellationToken) { - var command = new SecurityServiceCommands.CreateClientCommand( + SecurityServiceCommands.CreateClientCommand command = new SecurityServiceCommands.CreateClientCommand( createClientRequest.ClientId, createClientRequest.Secret, createClientRequest.ClientName, @@ -41,26 +37,24 @@ public static async Task CreateClient(IMediator mediator, } public static async Task GetClient(IMediator mediator, - IModelFactory modelFactory, string clientId, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetClientQuery(clientId); + SecurityServiceQueries.GetClientQuery query = new SecurityServiceQueries.GetClientQuery(clientId); Result result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } public static async Task GetClients(IMediator mediator, - IModelFactory modelFactory, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetClientsQuery(); + SecurityServiceQueries.GetClientsQuery query = new SecurityServiceQueries.GetClientsQuery(); Result> result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } } } \ No newline at end of file diff --git a/SecurityService/Handlers/DeveloperHandler.cs b/SecurityService/Handlers/DeveloperHandler.cs index 5438d4cb..6e80a381 100644 --- a/SecurityService/Handlers/DeveloperHandler.cs +++ b/SecurityService/Handlers/DeveloperHandler.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using MessagingService.Client; +using MessagingService.DataTransferObjects; using Microsoft.AspNetCore.Http; namespace SecurityService.Handlers @@ -18,7 +19,7 @@ public static Task GetLastEmailMessage(IMessagingServiceClient messagin if (Startup.WebHostEnvironment.IsEnvironment("IntegrationTest") && messagingServiceClient.GetType() == typeof(TestMessagingServiceClient)) { - var lastEmailRequest = ((TestMessagingServiceClient)messagingServiceClient).LastEmailRequest; + SendEmailRequest lastEmailRequest = ((TestMessagingServiceClient)messagingServiceClient).LastEmailRequest; return Task.FromResult(Results.Ok(lastEmailRequest) as IResult); } @@ -28,10 +29,8 @@ public static Task GetLastEmailMessage(IMessagingServiceClient messagin public static Task GetLastSMSMessage(IMessagingServiceClient messagingServiceClient, CancellationToken cancellationToken) { - if (Startup.WebHostEnvironment.IsEnvironment("IntegrationTest") - && messagingServiceClient.GetType() == typeof(TestMessagingServiceClient)) - { - var lastSmsRequest = ((TestMessagingServiceClient)messagingServiceClient).LastSMSRequest; + if (Startup.WebHostEnvironment.IsEnvironment("IntegrationTest") && messagingServiceClient.GetType() == typeof(TestMessagingServiceClient)) { + SendSMSRequest lastSmsRequest = ((TestMessagingServiceClient)messagingServiceClient).LastSMSRequest; return Task.FromResult(Results.Ok(lastSmsRequest) as IResult); } diff --git a/SecurityService/Handlers/IdentityResourceHandler.cs b/SecurityService/Handlers/IdentityResourceHandler.cs index 6d50be97..62b82f42 100644 --- a/SecurityService/Handlers/IdentityResourceHandler.cs +++ b/SecurityService/Handlers/IdentityResourceHandler.cs @@ -21,7 +21,7 @@ public static async Task CreateIdentityResource(IMediator mediator, CreateIdentityResourceRequest createIdentityResourceRequest, CancellationToken cancellationToken) { - var command = new SecurityServiceCommands.CreateIdentityResourceCommand( + SecurityServiceCommands.CreateIdentityResourceCommand command = new( createIdentityResourceRequest.Name, createIdentityResourceRequest.DisplayName, createIdentityResourceRequest.Description, @@ -36,26 +36,24 @@ public static async Task CreateIdentityResource(IMediator mediator, } public static async Task GetIdentityResource(IMediator mediator, - IModelFactory modelFactory, string apiResourceName, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetIdentityResourceQuery(apiResourceName); + SecurityServiceQueries.GetIdentityResourceQuery query = new(apiResourceName); Result result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } public static async Task GetIdentityResources(IMediator mediator, - IModelFactory modelFactory, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetIdentityResourcesQuery(); + SecurityServiceQueries.GetIdentityResourcesQuery query = new(); Result> result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } } } \ No newline at end of file diff --git a/SecurityService/Handlers/RoleHandler.cs b/SecurityService/Handlers/RoleHandler.cs index b3e4e8c0..be76f83c 100644 --- a/SecurityService/Handlers/RoleHandler.cs +++ b/SecurityService/Handlers/RoleHandler.cs @@ -24,7 +24,7 @@ public static async Task CreateRole(IMediator mediator, { Guid roleId = Guid.NewGuid(); - var command = new SecurityServiceCommands.CreateRoleCommand(roleId, createRoleRequest.RoleName); + SecurityServiceCommands.CreateRoleCommand command = new(roleId, createRoleRequest.RoleName); Result result = await mediator.Send(command, cancellationToken); @@ -32,26 +32,24 @@ public static async Task CreateRole(IMediator mediator, } public static async Task GetRole(IMediator mediator, - IModelFactory modelFactory, Guid roleId, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetRoleQuery(roleId); + SecurityServiceQueries.GetRoleQuery query = new(roleId); Result result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } public static async Task GetRoles(IMediator mediator, - IModelFactory modelFactory, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetRolesQuery(); + SecurityServiceQueries.GetRolesQuery query = new(); Result> result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } } } \ No newline at end of file diff --git a/SecurityService/Handlers/UserHandler.cs b/SecurityService/Handlers/UserHandler.cs index c04cda04..66669233 100644 --- a/SecurityService/Handlers/UserHandler.cs +++ b/SecurityService/Handlers/UserHandler.cs @@ -24,7 +24,7 @@ public static async Task CreateUser(IMediator mediator, { Guid userId = Guid.NewGuid(); - var command = new SecurityServiceCommands.CreateUserCommand( + SecurityServiceCommands.CreateUserCommand command = new( userId, createUserRequest.GivenName, createUserRequest.MiddleName, @@ -42,27 +42,25 @@ public static async Task CreateUser(IMediator mediator, } public static async Task GetUser(IMediator mediator, - IModelFactory modelFactory, Guid userId, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetUserQuery(userId); + SecurityServiceQueries.GetUserQuery query = new(userId); Result result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } public static async Task GetUsers(IMediator mediator, - IModelFactory modelFactory, string? userName, CancellationToken cancellationToken) { - var query = new SecurityServiceQueries.GetUsersQuery(userName); + SecurityServiceQueries.GetUsersQuery query = new(userName); Result> result = await mediator.Send(query, cancellationToken); - return ResponseFactory.FromResult(result, modelFactory.ConvertFrom); + return ResponseFactory.FromResult(result, ModelFactory.ConvertFrom); } } } \ No newline at end of file diff --git a/SecurityService/Startup.cs b/SecurityService/Startup.cs index 9d3cd5d1..73ed8a40 100644 --- a/SecurityService/Startup.cs +++ b/SecurityService/Startup.cs @@ -1,31 +1,24 @@ -using System.Threading; -using System.Threading.Tasks; +using Microsoft.AspNetCore.Routing; using SecurityService.Endpoints; namespace SecurityService { using Bootstrapper; - using Database.DbContexts; - using Duende.IdentityServer.EntityFramework.DbContexts; using HealthChecks.UI.Client; using Lamar; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpOverrides; - using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; - using NLog.Extensions.Logging; using Shared.Extensions; using Shared.General; using Shared.Logger; using Shared.Middleware; - using System; using System.Diagnostics.CodeAnalysis; - using System.IO; using ILogger = Microsoft.Extensions.Logging.ILogger; [ExcludeFromCodeCoverage] @@ -33,11 +26,10 @@ public class Startup { #region Fields - /// - /// The container - /// - public static Container Container; + private static Container Container; + public static Container GetContainer() => Container; + #endregion #region Constructors @@ -94,11 +86,10 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { - if (env.IsDevelopment()) - { + if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } - + ILogger logger = loggerFactory.CreateLogger("Security Service"); Logger.Initialise(logger); @@ -126,39 +117,27 @@ public void Configure(IApplicationBuilder app, ForwardedHeaders = ForwardedHeaders.XForwardedProto }); - app.UseEndpoints(endpoints => - { - endpoints.MapRazorPages(); - endpoints.MapDefaultControllerRoute(); - - endpoints.MapApiResourceEndpoints(); - endpoints.MapApiScopeEndpoints(); - endpoints.MapIdentityResourceEndpoints(); - endpoints.MapUserEndpoints(); - endpoints.MapRoleEndpoints(); - endpoints.MapClientEndpoints(); - endpoints.MapDeveloperEndpoints(); - - endpoints.MapHealthChecks("health", - new HealthCheckOptions - { - Predicate = _ => true, - ResponseWriter = Shared.HealthChecks.HealthCheckMiddleware.WriteResponse - }); - endpoints.MapHealthChecks("healthui", - new HealthCheckOptions - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - }); + app.UseEndpoints(this.MapEndpoints); app.UseSwagger(); app.UseSwaggerUI(); + } - // this will do the initial DB population - //this.InitializeDatabase(app); + private void MapEndpoints(IEndpointRouteBuilder endpoints) { + endpoints.MapRazorPages(); + endpoints.MapDefaultControllerRoute(); + + endpoints.MapApiResourceEndpoints(); + endpoints.MapApiScopeEndpoints(); + endpoints.MapIdentityResourceEndpoints(); + endpoints.MapUserEndpoints(); + endpoints.MapRoleEndpoints(); + endpoints.MapClientEndpoints(); + endpoints.MapDeveloperEndpoints(); + + endpoints.MapHealthChecks("health", new HealthCheckOptions { Predicate = _ => true, ResponseWriter = Shared.HealthChecks.HealthCheckMiddleware.WriteResponse }); + endpoints.MapHealthChecks("healthui", new HealthCheckOptions { Predicate = _ => true, ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); } /// @@ -180,36 +159,6 @@ public void ConfigureContainer(ServiceRegistry services) Startup.Container = new Container(services); } - /// - /// Initializes the database. - /// - /// The application. - //private void InitializeDatabase(IApplicationBuilder app) - //{ - // using(IServiceScope serviceScope = app.ApplicationServices.GetService().CreateScope()) - // { - // PersistedGrantDbContext persistedGrantDbContext = serviceScope.ServiceProvider.GetRequiredService(); - // ConfigurationDbContext configurationDbContext = serviceScope.ServiceProvider.GetRequiredService(); - // AuthenticationDbContext authenticationContext = serviceScope.ServiceProvider.GetRequiredService(); - - // if (persistedGrantDbContext != null && persistedGrantDbContext.Database.IsRelational()) - // { - // persistedGrantDbContext.Database.Migrate(); - // //_ = persistedGrantDbContext.SetDbInSimpleMode(CancellationToken.None); - // } - - // if (configurationDbContext != null && configurationDbContext.Database.IsRelational()) - // { - // configurationDbContext.Database.Migrate(); - // } - - // if (authenticationContext != null && authenticationContext.Database.IsRelational()) - // { - // authenticationContext.Database.Migrate(); - // } - // } - //} - #endregion } } \ No newline at end of file From f277505abb0ddd9dc09b48a1c0f9f85ad5d7d8a3 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 4 Dec 2025 12:01:03 +0000 Subject: [PATCH 2/3] oops --- .../Pages/ExternalLogin/Callback.cshtml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SecurityService.UserInterface/Pages/ExternalLogin/Callback.cshtml.cs b/SecurityService.UserInterface/Pages/ExternalLogin/Callback.cshtml.cs index 5d475665..20c91094 100644 --- a/SecurityService.UserInterface/Pages/ExternalLogin/Callback.cshtml.cs +++ b/SecurityService.UserInterface/Pages/ExternalLogin/Callback.cshtml.cs @@ -191,7 +191,7 @@ await EnsureSucceededAsync(await _userManager } await EnsureSucceededAsync( - _userManager.AddLoginAsync(user, new UserLoginInfo(provider, providerUserId, provider))); + await _userManager.AddLoginAsync(user, new UserLoginInfo(provider, providerUserId, provider))); return user; } From 61e21aed2f11c6c50f0e1755db00b726db3dd2db Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 4 Dec 2025 12:14:37 +0000 Subject: [PATCH 3/3] dockerfile version pin --- SecurityService/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SecurityService/Dockerfile b/SecurityService/Dockerfile index e63307f1..56da520b 100644 --- a/SecurityService/Dockerfile +++ b/SecurityService/Dockerfile @@ -1,4 +1,4 @@ -FROM stuartferguson/txnprocbase:latest AS base +FROM stuartferguson/txnprocbase:2025.8.1 AS base WORKDIR /app FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build