From 6b257f52900b5e65cdb27956a7bdb05696451965 Mon Sep 17 00:00:00 2001 From: idotta Date: Fri, 2 Jan 2026 12:51:51 -0300 Subject: [PATCH 1/4] Enhance CurrentUserServiceTests with additional tenant ID and active status checks --- .../Services/CoreServicesTests.cs | 126 +++++++++++++++++- 1 file changed, 123 insertions(+), 3 deletions(-) diff --git a/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs b/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs index 295d384..732bec3 100644 --- a/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs +++ b/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs @@ -20,13 +20,14 @@ namespace Idmt.UnitTests.Services; /// public class CurrentUserServiceTests { - private readonly Mock _tenantAccessorMock; + private readonly Mock> _optionsMock; private readonly CurrentUserService _service; public CurrentUserServiceTests() { - _tenantAccessorMock = new Mock(); - _service = new CurrentUserService(_tenantAccessorMock.Object); + _optionsMock = new Mock>(); + _optionsMock.Setup(x => x.Value).Returns(IdmtOptions.Default); + _service = new CurrentUserService(_optionsMock.Object); } [Fact] @@ -43,6 +44,7 @@ public void UserId_ReturnsCurrentUserId_WhenUserExists() var result = _service.UserId; + Assert.NotNull(result); Assert.Equal(userId, result); } @@ -56,6 +58,7 @@ public void UserId_ReturnsEmptyGuid_WhenUserDoesNotExist() var result = _service.UserId; + Assert.NotNull(result); Assert.Equal(Guid.Empty, result); } @@ -98,6 +101,123 @@ public void IsInRole_ReturnsFalse_WhenUserNotSet() Assert.False(result); } + + [Fact] + public void TenantId_ReturnsTenantId_WhenClaimExists() + { + const string tenantId = "tenant-123"; + var user = new System.Security.Claims.ClaimsPrincipal( + new System.Security.Claims.ClaimsIdentity(new[] + { + new System.Security.Claims.Claim(IdmtMultiTenantStrategy.DefaultClaimType, tenantId) + })); + + _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); + + var result = _service.TenantId; + + Assert.Equal(tenantId, result); + } + + [Fact] + public void TenantId_ReturnsNull_WhenClaimDoesNotExist() + { + var user = new System.Security.Claims.ClaimsPrincipal( + new System.Security.Claims.ClaimsIdentity()); + + _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); + + var result = _service.TenantId; + + Assert.Null(result); + } + + [Fact] + public void TenantId_ReturnsTenantId_WhenCustomClaimTypeIsConfigured() + { + const string customClaimType = "custom_tenant_claim"; + const string tenantId = "tenant-456"; + + var customOptions = new IdmtOptions + { + MultiTenant = new MultiTenantOptions + { + StrategyOptions = new Dictionary + { + { IdmtMultiTenantStrategy.ClaimOption, customClaimType } + } + } + }; + + var customOptionsMock = new Mock>(); + customOptionsMock.Setup(x => x.Value).Returns(customOptions); + var customService = new CurrentUserService(customOptionsMock.Object); + + var user = new System.Security.Claims.ClaimsPrincipal( + new System.Security.Claims.ClaimsIdentity(new[] + { + new System.Security.Claims.Claim(customClaimType, tenantId) + })); + + customService.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); + + var result = customService.TenantId; + + Assert.Equal(tenantId, result); + } + + [Fact] + public void IsActive_ReturnsTrue_WhenClaimIsTrue() + { + var user = new System.Security.Claims.ClaimsPrincipal( + new System.Security.Claims.ClaimsIdentity(new[] + { + new System.Security.Claims.Claim("is_active", "true") + })); + + _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); + + var result = _service.IsActive; + + Assert.True(result); + } + + [Fact] + public void IsActive_ReturnsFalse_WhenClaimIsNotTrue() + { + var user = new System.Security.Claims.ClaimsPrincipal( + new System.Security.Claims.ClaimsIdentity(new[] + { + new System.Security.Claims.Claim("is_active", "false") + })); + + _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); + + var result = _service.IsActive; + + Assert.False(result); + } + + [Fact] + public void IsActive_ReturnsFalse_WhenClaimDoesNotExist() + { + var user = new System.Security.Claims.ClaimsPrincipal( + new System.Security.Claims.ClaimsIdentity()); + + _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); + + var result = _service.IsActive; + + Assert.False(result); + } + + [Fact] + public void IsActive_ReturnsFalse_WhenUserNotSet() + { + var result = _service.IsActive; + + Assert.False(result); + } } /// From a6e3ab480022b0acc6a06542e64b534c7bee7df2 Mon Sep 17 00:00:00 2001 From: idotta Date: Fri, 2 Jan 2026 12:51:59 -0300 Subject: [PATCH 2/4] Add multi-tenant support to IdmtUserClaimsPrincipalFactory and implement unit tests --- .../IdmtUserClaimsPrincipalFactory.cs | 5 +- .../Idmt.BasicSample.Tests/IdmtApiFactory.cs | 2 +- .../IdmtUserClaimsPrincipalFactoryTests.cs | 238 ++++++++++++++++++ 3 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs diff --git a/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs b/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs index e1ff1d8..f7c96a8 100644 --- a/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs +++ b/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs @@ -1,4 +1,5 @@ using System.Security.Claims; +using Finbuckle.MultiTenant.Abstractions; using Idmt.Plugin.Configuration; using Idmt.Plugin.Models; using Microsoft.AspNetCore.Identity; @@ -10,6 +11,7 @@ internal sealed class IdmtUserClaimsPrincipalFactory( UserManager userManager, RoleManager roleManager, IOptions optionsAccessor, + IMultiTenantStore tenantStore, IOptions idmtOptions) : UserClaimsPrincipalFactory(userManager, roleManager, optionsAccessor) { @@ -23,7 +25,8 @@ protected override async Task GenerateClaimsAsync(IdmtUser user) // Add tenant claim for multi-tenant strategies (header, claim, route) // This ensures token validation includes tenant context var claimKey = idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.ClaimOption, IdmtMultiTenantStrategy.DefaultClaimType); - identity.AddClaim(new Claim(claimKey, user.TenantId)); + var tenantInfo = await tenantStore.GetAsync(user.TenantId); + identity.AddClaim(new Claim(claimKey, tenantInfo?.Identifier ?? throw new InvalidOperationException("Tenant information not found."))); return identity; } diff --git a/src/tests/Idmt.BasicSample.Tests/IdmtApiFactory.cs b/src/tests/Idmt.BasicSample.Tests/IdmtApiFactory.cs index 22a5461..5ec3e56 100644 --- a/src/tests/Idmt.BasicSample.Tests/IdmtApiFactory.cs +++ b/src/tests/Idmt.BasicSample.Tests/IdmtApiFactory.cs @@ -98,7 +98,7 @@ public HttpClient CreateClientWithTenant(string? tenantId = null, bool allowAuto } if (_strategies.Contains(IdmtMultiTenantStrategy.Header)) { - client.DefaultRequestHeaders.TryAddWithoutValidation("__tenant__", tenantId); + client.DefaultRequestHeaders.TryAddWithoutValidation(IdmtMultiTenantStrategy.DefaultHeaderName, tenantId); } return client; } diff --git a/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs b/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs new file mode 100644 index 0000000..72cf48c --- /dev/null +++ b/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs @@ -0,0 +1,238 @@ +using System.Security.Claims; +using Idmt.Plugin.Configuration; +using Idmt.Plugin.Models; +using Idmt.Plugin.Services; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using Moq; + +namespace Idmt.UnitTests.Services; + +/// +/// Unit tests for IdmtUserClaimsPrincipalFactory. +/// Tests that custom claims (is_active and tenant) are correctly added to the user's claims identity. +/// +public class IdmtUserClaimsPrincipalFactoryTests +{ + private readonly Mock> _userManagerMock; + private readonly Mock> _roleManagerMock; + private readonly Mock> _identityOptionsMock; + private readonly Mock> _idmtOptionsMock; + private readonly IdmtUserClaimsPrincipalFactory _factory; + + public IdmtUserClaimsPrincipalFactoryTests() + { + var userStoreMock = Mock.Of>(); + _userManagerMock = new Mock>( + userStoreMock, + null!, null!, null!, null!, null!, null!, null!, null!); + + // Mock UserManager methods that the base class might call + _userManagerMock.Setup(x => x.GetRolesAsync(It.IsAny())) + .ReturnsAsync(Array.Empty()); + _userManagerMock.Setup(x => x.GetClaimsAsync(It.IsAny())) + .ReturnsAsync(Array.Empty()); + + var roleStoreMock = Mock.Of>(); + _roleManagerMock = new Mock>( + roleStoreMock, + null!, null!, null!, null!); + + _identityOptionsMock = new Mock>(); + var identityOptions = new IdentityOptions + { + ClaimsIdentity = new ClaimsIdentityOptions + { + // Configure claim types to avoid null value issues + EmailClaimType = ClaimTypes.Email, + RoleClaimType = ClaimTypes.Role, + SecurityStampClaimType = "AspNet.Identity.SecurityStamp", + UserIdClaimType = ClaimTypes.NameIdentifier, + UserNameClaimType = ClaimTypes.Name + } + }; + _identityOptionsMock.Setup(x => x.Value).Returns(identityOptions); + + _idmtOptionsMock = new Mock>(); + _idmtOptionsMock.Setup(x => x.Value).Returns(IdmtOptions.Default); + + _factory = new IdmtUserClaimsPrincipalFactory( + _userManagerMock.Object, + _roleManagerMock.Object, + _identityOptionsMock.Object, + _idmtOptionsMock.Object); + } + + [Fact] + public async Task CreateAsync_AddsIsActiveClaim_WithCorrectValue() + { + var user = new IdmtUser + { + Id = Guid.NewGuid(), + UserName = "testuser", + Email = "test@example.com", + EmailConfirmed = false, + PhoneNumber = null, + PhoneNumberConfirmed = false, + TwoFactorEnabled = false, + LockoutEnabled = false, + AccessFailedCount = 0, + TenantId = "tenant-123", + IsActive = true, + SecurityStamp = Guid.NewGuid().ToString(), + ConcurrencyStamp = Guid.NewGuid().ToString() + }; + + var principal = await _factory.CreateAsync(user); + + var isActiveClaim = principal.FindFirst("is_active"); + Assert.NotNull(isActiveClaim); + Assert.Equal("True", isActiveClaim.Value); + } + + [Fact] + public async Task CreateAsync_AddsIsActiveClaim_WhenUserIsInactive() + { + var user = new IdmtUser + { + Id = Guid.NewGuid(), + UserName = "testuser", + Email = "test@example.com", + TenantId = "tenant-123", + IsActive = false, + SecurityStamp = Guid.NewGuid().ToString(), + ConcurrencyStamp = Guid.NewGuid().ToString() + }; + + var principal = await _factory.CreateAsync(user); + + var isActiveClaim = principal.FindFirst("is_active"); + Assert.NotNull(isActiveClaim); + Assert.Equal("False", isActiveClaim.Value); + } + + [Fact] + public async Task CreateAsync_AddsTenantClaim_WithDefaultClaimType() + { + const string tenantId = "tenant-456"; + var user = new IdmtUser + { + Id = Guid.NewGuid(), + UserName = "testuser", + Email = "test@example.com", + TenantId = tenantId, + IsActive = true, + SecurityStamp = Guid.NewGuid().ToString(), + ConcurrencyStamp = Guid.NewGuid().ToString() + }; + + var principal = await _factory.CreateAsync(user); + + var tenantClaim = principal.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType); + Assert.NotNull(tenantClaim); + Assert.Equal(tenantId, tenantClaim.Value); + } + + [Fact] + public async Task CreateAsync_AddsTenantClaim_WithCustomClaimType() + { + const string customClaimType = "custom_tenant_claim"; + const string tenantId = "tenant-789"; + + var customOptions = new IdmtOptions + { + MultiTenant = new MultiTenantOptions + { + StrategyOptions = new Dictionary + { + { IdmtMultiTenantStrategy.ClaimOption, customClaimType } + } + } + }; + + var customOptionsMock = new Mock>(); + customOptionsMock.Setup(x => x.Value).Returns(customOptions); + + var customFactory = new IdmtUserClaimsPrincipalFactory( + _userManagerMock.Object, + _roleManagerMock.Object, + _identityOptionsMock.Object, + customOptionsMock.Object); + + var user = new IdmtUser + { + Id = Guid.NewGuid(), + UserName = "testuser", + Email = "test@example.com", + TenantId = tenantId, + IsActive = true, + SecurityStamp = Guid.NewGuid().ToString(), + ConcurrencyStamp = Guid.NewGuid().ToString() + }; + + var principal = await customFactory.CreateAsync(user); + + var tenantClaim = principal.FindFirst(customClaimType); + Assert.NotNull(tenantClaim); + Assert.Equal(tenantId, tenantClaim.Value); + + // Verify default claim type is not present + var defaultTenantClaim = principal.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType); + Assert.Null(defaultTenantClaim); + } + + [Fact] + public async Task CreateAsync_IncludesBaseClaims() + { + var userId = Guid.NewGuid(); + var user = new IdmtUser + { + Id = userId, + UserName = "testuser", + Email = "test@example.com", + TenantId = "tenant-123", + IsActive = true, + SecurityStamp = Guid.NewGuid().ToString(), + ConcurrencyStamp = Guid.NewGuid().ToString() + }; + + var principal = await _factory.CreateAsync(user); + + // Verify base claims are present (from base.GenerateClaimsAsync) + var nameIdentifierClaim = principal.FindFirst(ClaimTypes.NameIdentifier); + Assert.NotNull(nameIdentifierClaim); + Assert.Equal(userId.ToString(), nameIdentifierClaim.Value); + + var nameClaim = principal.FindFirst(ClaimTypes.Name); + Assert.NotNull(nameClaim); + Assert.Equal(user.UserName, nameClaim.Value); + } + + [Fact] + public async Task CreateAsync_AddsAllCustomClaims() + { + const string tenantId = "tenant-999"; + var user = new IdmtUser + { + Id = Guid.NewGuid(), + UserName = "testuser", + Email = "test@example.com", + TenantId = tenantId, + IsActive = true, + SecurityStamp = Guid.NewGuid().ToString(), + ConcurrencyStamp = Guid.NewGuid().ToString() + }; + + var principal = await _factory.CreateAsync(user); + + // Verify both custom claims are present + var isActiveClaim = principal.FindFirst("is_active"); + Assert.NotNull(isActiveClaim); + Assert.Equal("True", isActiveClaim.Value); + + var tenantClaim = principal.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType); + Assert.NotNull(tenantClaim); + Assert.Equal(tenantId, tenantClaim.Value); + } +} + From 6f51fc7cba623ad561d00c18808b98f039f9c032 Mon Sep 17 00:00:00 2001 From: idotta Date: Fri, 2 Jan 2026 15:51:45 -0300 Subject: [PATCH 3/4] Enhance multi-tenant support in user management services - Updated RegisterUser to retrieve tenant ID from the current user service, ensuring user registration is context-aware. - Modified ValidateBearerTokenTenantMiddleware to validate tenant claims against the current request's tenant identifier. - Enhanced CurrentUserService to include TenantIdentifier for better tenant context handling. - Updated IdmtUserClaimsPrincipalFactory to ensure tenant claims are correctly generated and tested. - Improved unit tests for CurrentUserService and IdmtUserClaimsPrincipalFactory to cover new tenant handling logic. --- .../Features/Manage/RegisterUser.cs | 9 +- .../ValidateBearerTokenTenantMiddleware.cs | 15 ++- .../Services/CurrentUserService.cs | 12 +- .../Services/ICurrentUserService.cs | 1 + .../IdmtUserClaimsPrincipalFactory.cs | 6 +- .../Services/CoreServicesTests.cs | 88 +++++++----- .../IdmtUserClaimsPrincipalFactoryTests.cs | 127 ++++++++++++++---- 7 files changed, 187 insertions(+), 71 deletions(-) diff --git a/src/Idmt.Plugin/Features/Manage/RegisterUser.cs b/src/Idmt.Plugin/Features/Manage/RegisterUser.cs index 5380d1e..7df98ce 100644 --- a/src/Idmt.Plugin/Features/Manage/RegisterUser.cs +++ b/src/Idmt.Plugin/Features/Manage/RegisterUser.cs @@ -131,6 +131,11 @@ public async Task> HandleAsync( { return Result.Failure("Insufficient permissions to assign this role.", StatusCodes.Status403Forbidden); } + + // Get the tenant ID from the current user service (from tenant context) + var tenantId = currentUserService.TenantId + ?? throw new InvalidOperationException("Tenant context is not available. Cannot register user without tenant context."); + // Create user entity with basic information, no password set // User is active by default, but email is not confirmed until password is set // When the user is unregistered, we set IsActive to false (soft delete) @@ -140,7 +145,7 @@ public async Task> HandleAsync( Email = request.Email, EmailConfirmed = false, // Will be confirmed when password is set IsActive = true, - TenantId = currentUserService.TenantId!, + TenantId = tenantId, LastLoginAt = null, }; @@ -204,7 +209,7 @@ public async Task> HandleAsync( ? linkGenerator.GeneratePasswordResetApiLink(user.Email, token) : linkGenerator.GeneratePasswordResetFormLink(user.Email, token); - logger.LogInformation("User created: {Email}. Request by {RequestingUserId}. Tenant: {TenantId}.", user.Email, currentUserService.UserId, currentUserService.TenantId); + logger.LogInformation("User created: {Email}. Request by {RequestingUserId}. Tenant: {TenantId}.", user.Email, currentUserService.UserId, tenantId); await emailSender.SendPasswordResetLinkAsync(user, user.Email, passwordSetupUrl); diff --git a/src/Idmt.Plugin/Middleware/ValidateBearerTokenTenantMiddleware.cs b/src/Idmt.Plugin/Middleware/ValidateBearerTokenTenantMiddleware.cs index 12c16a0..68ae323 100644 --- a/src/Idmt.Plugin/Middleware/ValidateBearerTokenTenantMiddleware.cs +++ b/src/Idmt.Plugin/Middleware/ValidateBearerTokenTenantMiddleware.cs @@ -1,9 +1,13 @@ using Finbuckle.MultiTenant.Abstractions; +using Idmt.Plugin.Configuration; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; namespace Idmt.Plugin.Middleware; -public class ValidateBearerTokenTenantMiddleware(IMultiTenantContextAccessor tenantContextAccessor) : IMiddleware +public class ValidateBearerTokenTenantMiddleware( + IMultiTenantContextAccessor tenantContextAccessor, + IOptions idmtOptions) : IMiddleware { public async Task InvokeAsync(HttpContext context, RequestDelegate next) { @@ -39,7 +43,9 @@ private bool ValidateTokenTenant( } // Get the tenant claim type from configuration - string tenantClaimType = "__tenant__"; + var tenantClaimType = idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault( + IdmtMultiTenantStrategy.ClaimOption, + IdmtMultiTenantStrategy.DefaultClaimType); // Extract tenant claim from token var tokenTenantClaim = context.User.FindFirst(tenantClaimType)?.Value; @@ -51,8 +57,9 @@ private bool ValidateTokenTenant( return false; } - // Validate that the token's tenant matches the current request's tenant - if (!tokenTenantClaim.Equals(currentTenant.Id, StringComparison.Ordinal)) + // Validate that the token's tenant identifier matches the current request's tenant identifier + // The factory adds tenantInfo.Identifier to the claim, so we compare with Identifier, not Id + if (!tokenTenantClaim.Equals(currentTenant.Identifier, StringComparison.Ordinal)) { context.Response.StatusCode = StatusCodes.Status403Forbidden; return false; diff --git a/src/Idmt.Plugin/Services/CurrentUserService.cs b/src/Idmt.Plugin/Services/CurrentUserService.cs index 0edb1f5..040d395 100644 --- a/src/Idmt.Plugin/Services/CurrentUserService.cs +++ b/src/Idmt.Plugin/Services/CurrentUserService.cs @@ -1,10 +1,13 @@ using System.Security.Claims; +using Finbuckle.MultiTenant.Abstractions; using Idmt.Plugin.Configuration; using Microsoft.Extensions.Options; namespace Idmt.Plugin.Services; -internal sealed class CurrentUserService(IOptions idmtOptions) : ICurrentUserService +internal sealed class CurrentUserService( + IOptions idmtOptions, + IMultiTenantContextAccessor multiTenantContextAccessor) : ICurrentUserService { public ClaimsPrincipal? User { get; private set; } @@ -22,8 +25,11 @@ internal sealed class CurrentUserService(IOptions idmtOptions) : IC public string? UserName => User?.FindFirstValue(ClaimTypes.Name); public string? TenantId => - User?.FindFirstValue(idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.ClaimOption, - IdmtMultiTenantStrategy.DefaultClaimType)); + multiTenantContextAccessor.MultiTenantContext?.TenantInfo?.Id; + + public string? TenantIdentifier => + User?.FindFirstValue(idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.ClaimOption, IdmtMultiTenantStrategy.DefaultClaimType)) ?? + multiTenantContextAccessor.MultiTenantContext?.TenantInfo?.Identifier; public bool IsActive => User?.FindFirstValue("is_active") == "true"; diff --git a/src/Idmt.Plugin/Services/ICurrentUserService.cs b/src/Idmt.Plugin/Services/ICurrentUserService.cs index 459169f..40c57df 100644 --- a/src/Idmt.Plugin/Services/ICurrentUserService.cs +++ b/src/Idmt.Plugin/Services/ICurrentUserService.cs @@ -13,6 +13,7 @@ public interface ICurrentUserService string? Email { get; } string? UserName { get; } string? TenantId { get; } + string? TenantIdentifier { get; } bool IsInRole(string role); diff --git a/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs b/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs index f7c96a8..de80835 100644 --- a/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs +++ b/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs @@ -25,8 +25,10 @@ protected override async Task GenerateClaimsAsync(IdmtUser user) // Add tenant claim for multi-tenant strategies (header, claim, route) // This ensures token validation includes tenant context var claimKey = idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.ClaimOption, IdmtMultiTenantStrategy.DefaultClaimType); - var tenantInfo = await tenantStore.GetAsync(user.TenantId); - identity.AddClaim(new Claim(claimKey, tenantInfo?.Identifier ?? throw new InvalidOperationException("Tenant information not found."))); + + // Try to get tenant info from store using user's TenantId + var tenantInfo = await tenantStore.GetAsync(user.TenantId) ?? throw new InvalidOperationException($"Tenant information not found for tenant ID: {user.TenantId}. User ID: {user.Id}"); + identity.AddClaim(new Claim(claimKey, tenantInfo.Identifier)); return identity; } diff --git a/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs b/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs index 732bec3..8de40fa 100644 --- a/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs +++ b/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs @@ -21,13 +21,15 @@ namespace Idmt.UnitTests.Services; public class CurrentUserServiceTests { private readonly Mock> _optionsMock; + private readonly Mock _tenantContextAccessorMock; private readonly CurrentUserService _service; public CurrentUserServiceTests() { _optionsMock = new Mock>(); _optionsMock.Setup(x => x.Value).Returns(IdmtOptions.Default); - _service = new CurrentUserService(_optionsMock.Object); + _tenantContextAccessorMock = new Mock(); + _service = new CurrentUserService(_optionsMock.Object, _tenantContextAccessorMock.Object); } [Fact] @@ -35,10 +37,10 @@ public void UserId_ReturnsCurrentUserId_WhenUserExists() { var userId = Guid.NewGuid(); var user = new System.Security.Claims.ClaimsPrincipal( - new System.Security.Claims.ClaimsIdentity(new[] - { + new System.Security.Claims.ClaimsIdentity( + [ new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.NameIdentifier, userId.ToString()) - })); + ])); _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); @@ -66,10 +68,10 @@ public void UserId_ReturnsEmptyGuid_WhenUserDoesNotExist() public void IsInRole_ReturnsTrue_WhenUserHasRole() { var user = new System.Security.Claims.ClaimsPrincipal( - new System.Security.Claims.ClaimsIdentity(new[] - { + new System.Security.Claims.ClaimsIdentity( + [ new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, "Admin") - })); + ])); _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); @@ -82,10 +84,10 @@ public void IsInRole_ReturnsTrue_WhenUserHasRole() public void IsInRole_ReturnsFalse_WhenUserDoesNotHaveRole() { var user = new System.Security.Claims.ClaimsPrincipal( - new System.Security.Claims.ClaimsIdentity(new[] - { + new System.Security.Claims.ClaimsIdentity( + [ new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, "User") - })); + ])); _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); @@ -103,37 +105,56 @@ public void IsInRole_ReturnsFalse_WhenUserNotSet() } [Fact] - public void TenantId_ReturnsTenantId_WhenClaimExists() + public void TenantIdentifier_ReturnsTenantIdentifier_WhenClaimExists() { const string tenantId = "tenant-123"; var user = new System.Security.Claims.ClaimsPrincipal( - new System.Security.Claims.ClaimsIdentity(new[] - { + new System.Security.Claims.ClaimsIdentity( + [ new System.Security.Claims.Claim(IdmtMultiTenantStrategy.DefaultClaimType, tenantId) - })); + ])); _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); - var result = _service.TenantId; + var result = _service.TenantIdentifier; Assert.Equal(tenantId, result); } [Fact] - public void TenantId_ReturnsNull_WhenClaimDoesNotExist() + public void TenantIdentifier_ReturnsNull_WhenClaimDoesNotExist() { var user = new System.Security.Claims.ClaimsPrincipal( new System.Security.Claims.ClaimsIdentity()); _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); - var result = _service.TenantId; + var result = _service.TenantIdentifier; Assert.Null(result); } [Fact] - public void TenantId_ReturnsTenantId_WhenCustomClaimTypeIsConfigured() + public void TenantIdentifier_ReturnsIdentifierFromTenantContext_WhenClaimDoesNotExist() + { + const string tenantIdentifier = "tenant-123"; + var tenantInfo = new IdmtTenantInfo("tenant-id-123", tenantIdentifier, "Test Tenant"); + var tenantContext = new MultiTenantContext(tenantInfo); + + _tenantContextAccessorMock.Setup(x => x.MultiTenantContext).Returns(tenantContext); + + var user = new System.Security.Claims.ClaimsPrincipal( + new System.Security.Claims.ClaimsIdentity()); + + _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); + + var result = _service.TenantIdentifier; + + Assert.Equal(tenantIdentifier, result); + } + + [Fact] + public void TenantIdentifier_ReturnsTenantIdentifier_WhenCustomClaimTypeIsConfigured() { const string customClaimType = "custom_tenant_claim"; const string tenantId = "tenant-456"; @@ -151,17 +172,18 @@ public void TenantId_ReturnsTenantId_WhenCustomClaimTypeIsConfigured() var customOptionsMock = new Mock>(); customOptionsMock.Setup(x => x.Value).Returns(customOptions); - var customService = new CurrentUserService(customOptionsMock.Object); + var customTenantContextAccessorMock = new Mock(); + var customService = new CurrentUserService(customOptionsMock.Object, customTenantContextAccessorMock.Object); var user = new System.Security.Claims.ClaimsPrincipal( - new System.Security.Claims.ClaimsIdentity(new[] - { + new System.Security.Claims.ClaimsIdentity( + [ new System.Security.Claims.Claim(customClaimType, tenantId) - })); + ])); customService.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); - var result = customService.TenantId; + var result = customService.TenantIdentifier; Assert.Equal(tenantId, result); } @@ -170,10 +192,10 @@ public void TenantId_ReturnsTenantId_WhenCustomClaimTypeIsConfigured() public void IsActive_ReturnsTrue_WhenClaimIsTrue() { var user = new System.Security.Claims.ClaimsPrincipal( - new System.Security.Claims.ClaimsIdentity(new[] - { + new System.Security.Claims.ClaimsIdentity( + [ new System.Security.Claims.Claim("is_active", "true") - })); + ])); _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); @@ -186,10 +208,10 @@ public void IsActive_ReturnsTrue_WhenClaimIsTrue() public void IsActive_ReturnsFalse_WhenClaimIsNotTrue() { var user = new System.Security.Claims.ClaimsPrincipal( - new System.Security.Claims.ClaimsIdentity(new[] - { + new System.Security.Claims.ClaimsIdentity( + [ new System.Security.Claims.Claim("is_active", "false") - })); + ])); _service.SetCurrentUser(user, "127.0.0.1", "TestAgent/1.0"); @@ -348,7 +370,7 @@ public void CanManageUser_ReturnsFalse_WhenSysSupportManagesSysAdmin() { _currentUserServiceMock.Setup(x => x.IsInRole(IdmtDefaultRoleTypes.SysSupport)).Returns(true); - var result = _service.CanManageUser(new[] { IdmtDefaultRoleTypes.SysAdmin }); + var result = _service.CanManageUser([IdmtDefaultRoleTypes.SysAdmin]); Assert.False(result); } @@ -358,7 +380,7 @@ public void CanManageUser_ReturnsTrue_WhenSysSupportManagesTenantAdmin() { _currentUserServiceMock.Setup(x => x.IsInRole(IdmtDefaultRoleTypes.SysSupport)).Returns(true); - var result = _service.CanManageUser(new[] { IdmtDefaultRoleTypes.TenantAdmin }); + var result = _service.CanManageUser([IdmtDefaultRoleTypes.TenantAdmin]); Assert.True(result); } @@ -368,7 +390,7 @@ public void CanManageUser_ReturnsFalse_WhenTenantAdminManagesSysUser() { _currentUserServiceMock.Setup(x => x.IsInRole(IdmtDefaultRoleTypes.TenantAdmin)).Returns(true); - var result = _service.CanManageUser(new[] { IdmtDefaultRoleTypes.SysSupport }); + var result = _service.CanManageUser([IdmtDefaultRoleTypes.SysSupport]); Assert.False(result); } @@ -378,7 +400,7 @@ public void CanManageUser_ReturnsTrue_WhenTenantAdminManagesTenantUser() { _currentUserServiceMock.Setup(x => x.IsInRole(IdmtDefaultRoleTypes.TenantAdmin)).Returns(true); - var result = _service.CanManageUser(new[] { "CustomRole" }); + var result = _service.CanManageUser(["CustomRole"]); Assert.True(result); } diff --git a/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs b/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs index 72cf48c..316b376 100644 --- a/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs +++ b/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs @@ -1,4 +1,5 @@ using System.Security.Claims; +using Finbuckle.MultiTenant.Abstractions; using Idmt.Plugin.Configuration; using Idmt.Plugin.Models; using Idmt.Plugin.Services; @@ -17,6 +18,7 @@ public class IdmtUserClaimsPrincipalFactoryTests private readonly Mock> _userManagerMock; private readonly Mock> _roleManagerMock; private readonly Mock> _identityOptionsMock; + private readonly Mock> _tenantStoreMock; private readonly Mock> _idmtOptionsMock; private readonly IdmtUserClaimsPrincipalFactory _factory; @@ -32,6 +34,16 @@ public IdmtUserClaimsPrincipalFactoryTests() .ReturnsAsync(Array.Empty()); _userManagerMock.Setup(x => x.GetClaimsAsync(It.IsAny())) .ReturnsAsync(Array.Empty()); + _userManagerMock.Setup(x => x.GetSecurityStampAsync(It.IsAny())) + .ReturnsAsync(() => Guid.NewGuid().ToString()); + _userManagerMock.Setup(x => x.GetUserIdAsync(It.IsAny())) + .ReturnsAsync((IdmtUser u) => u.Id.ToString()); + _userManagerMock.Setup(x => x.GetUserNameAsync(It.IsAny())) + .ReturnsAsync((IdmtUser u) => u.UserName ?? string.Empty); + _userManagerMock.Setup(x => x.GetEmailAsync(It.IsAny())) + .ReturnsAsync((IdmtUser u) => u.Email ?? string.Empty); + _userManagerMock.Setup(x => x.GetPhoneNumberAsync(It.IsAny())) + .ReturnsAsync((IdmtUser u) => u.PhoneNumber ?? string.Empty); var roleStoreMock = Mock.Of>(); _roleManagerMock = new Mock>( @@ -53,6 +65,8 @@ public IdmtUserClaimsPrincipalFactoryTests() }; _identityOptionsMock.Setup(x => x.Value).Returns(identityOptions); + _tenantStoreMock = new Mock>(); + _idmtOptionsMock = new Mock>(); _idmtOptionsMock.Setup(x => x.Value).Returns(IdmtOptions.Default); @@ -60,32 +74,53 @@ public IdmtUserClaimsPrincipalFactoryTests() _userManagerMock.Object, _roleManagerMock.Object, _identityOptionsMock.Object, + _tenantStoreMock.Object, _idmtOptionsMock.Object); } + private async Task CallGenerateClaimsAsync(IdmtUser user) + { + var method = typeof(IdmtUserClaimsPrincipalFactory) + .GetMethod("GenerateClaimsAsync", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + if (method == null) + { + throw new InvalidOperationException("GenerateClaimsAsync method not found."); + } + return (ClaimsIdentity)await (dynamic)method.Invoke(_factory, new object[] { user })!; + } + [Fact] public async Task CreateAsync_AddsIsActiveClaim_WithCorrectValue() { + const string tenantId = "tenant-id-123"; + const string tenantIdentifier = "tenant-123"; + var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); + var user = new IdmtUser { Id = Guid.NewGuid(), UserName = "testuser", + NormalizedUserName = "TESTUSER", Email = "test@example.com", - EmailConfirmed = false, - PhoneNumber = null, - PhoneNumberConfirmed = false, + NormalizedEmail = "TEST@EXAMPLE.COM", + EmailConfirmed = true, + PhoneNumber = "1234567890", + PhoneNumberConfirmed = true, TwoFactorEnabled = false, LockoutEnabled = false, AccessFailedCount = 0, - TenantId = "tenant-123", + TenantId = tenantId, IsActive = true, SecurityStamp = Guid.NewGuid().ToString(), ConcurrencyStamp = Guid.NewGuid().ToString() }; - var principal = await _factory.CreateAsync(user); + _tenantStoreMock.Setup(x => x.GetAsync(tenantId)) + .ReturnsAsync(tenantInfo); + + var identity = await CallGenerateClaimsAsync(user); - var isActiveClaim = principal.FindFirst("is_active"); + var isActiveClaim = identity.FindFirst("is_active"); Assert.NotNull(isActiveClaim); Assert.Equal("True", isActiveClaim.Value); } @@ -93,20 +128,27 @@ public async Task CreateAsync_AddsIsActiveClaim_WithCorrectValue() [Fact] public async Task CreateAsync_AddsIsActiveClaim_WhenUserIsInactive() { + const string tenantId = "tenant-id-123"; + const string tenantIdentifier = "tenant-123"; + var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); + var user = new IdmtUser { Id = Guid.NewGuid(), UserName = "testuser", Email = "test@example.com", - TenantId = "tenant-123", + TenantId = tenantId, IsActive = false, SecurityStamp = Guid.NewGuid().ToString(), ConcurrencyStamp = Guid.NewGuid().ToString() }; - var principal = await _factory.CreateAsync(user); + _tenantStoreMock.Setup(x => x.GetAsync(tenantId)) + .ReturnsAsync(tenantInfo); - var isActiveClaim = principal.FindFirst("is_active"); + var identity = await CallGenerateClaimsAsync(user); + + var isActiveClaim = identity.FindFirst("is_active"); Assert.NotNull(isActiveClaim); Assert.Equal("False", isActiveClaim.Value); } @@ -114,7 +156,10 @@ public async Task CreateAsync_AddsIsActiveClaim_WhenUserIsInactive() [Fact] public async Task CreateAsync_AddsTenantClaim_WithDefaultClaimType() { - const string tenantId = "tenant-456"; + const string tenantId = "tenant-id-456"; + const string tenantIdentifier = "tenant-456"; + var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); + var user = new IdmtUser { Id = Guid.NewGuid(), @@ -126,18 +171,24 @@ public async Task CreateAsync_AddsTenantClaim_WithDefaultClaimType() ConcurrencyStamp = Guid.NewGuid().ToString() }; - var principal = await _factory.CreateAsync(user); + _tenantStoreMock.Setup(x => x.GetAsync(tenantId)) + .ReturnsAsync(tenantInfo); + + var identity = await CallGenerateClaimsAsync(user); - var tenantClaim = principal.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType); + var tenantClaim = identity.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType); Assert.NotNull(tenantClaim); - Assert.Equal(tenantId, tenantClaim.Value); + // The factory adds tenantInfo.Identifier, not tenantId + Assert.Equal(tenantIdentifier, tenantClaim.Value); } [Fact] public async Task CreateAsync_AddsTenantClaim_WithCustomClaimType() { const string customClaimType = "custom_tenant_claim"; - const string tenantId = "tenant-789"; + const string tenantId = "tenant-id-789"; + const string tenantIdentifier = "tenant-789"; + var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); var customOptions = new IdmtOptions { @@ -153,10 +204,15 @@ public async Task CreateAsync_AddsTenantClaim_WithCustomClaimType() var customOptionsMock = new Mock>(); customOptionsMock.Setup(x => x.Value).Returns(customOptions); + var customTenantStoreMock = new Mock>(); + customTenantStoreMock.Setup(x => x.GetAsync(tenantId)) + .ReturnsAsync(tenantInfo); + var customFactory = new IdmtUserClaimsPrincipalFactory( _userManagerMock.Object, _roleManagerMock.Object, _identityOptionsMock.Object, + customTenantStoreMock.Object, customOptionsMock.Object); var user = new IdmtUser @@ -170,40 +226,50 @@ public async Task CreateAsync_AddsTenantClaim_WithCustomClaimType() ConcurrencyStamp = Guid.NewGuid().ToString() }; - var principal = await customFactory.CreateAsync(user); + var customMethod = typeof(IdmtUserClaimsPrincipalFactory) + .GetMethod("GenerateClaimsAsync", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var identity = (ClaimsIdentity)await (dynamic)customMethod!.Invoke(customFactory, new object[] { user })!; - var tenantClaim = principal.FindFirst(customClaimType); + var tenantClaim = identity.FindFirst(customClaimType); Assert.NotNull(tenantClaim); - Assert.Equal(tenantId, tenantClaim.Value); + // The factory adds tenantInfo.Identifier, not tenantId + Assert.Equal(tenantIdentifier, tenantClaim.Value); // Verify default claim type is not present - var defaultTenantClaim = principal.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType); + var defaultTenantClaim = identity.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType); Assert.Null(defaultTenantClaim); } [Fact] public async Task CreateAsync_IncludesBaseClaims() { + const string tenantId = "tenant-id-123"; + const string tenantIdentifier = "tenant-123"; + var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); + var userId = Guid.NewGuid(); var user = new IdmtUser { Id = userId, UserName = "testuser", Email = "test@example.com", - TenantId = "tenant-123", + TenantId = tenantId, IsActive = true, SecurityStamp = Guid.NewGuid().ToString(), ConcurrencyStamp = Guid.NewGuid().ToString() }; - var principal = await _factory.CreateAsync(user); + _tenantStoreMock.Setup(x => x.GetAsync(tenantId)) + .ReturnsAsync(tenantInfo); + + var identity = await CallGenerateClaimsAsync(user); // Verify base claims are present (from base.GenerateClaimsAsync) - var nameIdentifierClaim = principal.FindFirst(ClaimTypes.NameIdentifier); + var nameIdentifierClaim = identity.FindFirst(ClaimTypes.NameIdentifier); Assert.NotNull(nameIdentifierClaim); Assert.Equal(userId.ToString(), nameIdentifierClaim.Value); - var nameClaim = principal.FindFirst(ClaimTypes.Name); + var nameClaim = identity.FindFirst(ClaimTypes.Name); Assert.NotNull(nameClaim); Assert.Equal(user.UserName, nameClaim.Value); } @@ -211,7 +277,10 @@ public async Task CreateAsync_IncludesBaseClaims() [Fact] public async Task CreateAsync_AddsAllCustomClaims() { - const string tenantId = "tenant-999"; + const string tenantId = "tenant-id-999"; + const string tenantIdentifier = "tenant-999"; + var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); + var user = new IdmtUser { Id = Guid.NewGuid(), @@ -223,16 +292,20 @@ public async Task CreateAsync_AddsAllCustomClaims() ConcurrencyStamp = Guid.NewGuid().ToString() }; - var principal = await _factory.CreateAsync(user); + _tenantStoreMock.Setup(x => x.GetAsync(tenantId)) + .ReturnsAsync(tenantInfo); + + var identity = await CallGenerateClaimsAsync(user); // Verify both custom claims are present - var isActiveClaim = principal.FindFirst("is_active"); + var isActiveClaim = identity.FindFirst("is_active"); Assert.NotNull(isActiveClaim); Assert.Equal("True", isActiveClaim.Value); - var tenantClaim = principal.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType); + var tenantClaim = identity.FindFirst(IdmtMultiTenantStrategy.DefaultClaimType); Assert.NotNull(tenantClaim); - Assert.Equal(tenantId, tenantClaim.Value); + // The factory adds tenantInfo.Identifier, not tenantId + Assert.Equal(tenantIdentifier, tenantClaim.Value); } } From 3ad54e03236637fafe04d965e0530f403544d0bc Mon Sep 17 00:00:00 2001 From: idotta Date: Fri, 2 Jan 2026 15:53:28 -0300 Subject: [PATCH 4/4] Fix formatting --- src/Idmt.Plugin/Features/Manage/RegisterUser.cs | 4 ++-- .../Services/IdmtUserClaimsPrincipalFactory.cs | 2 +- .../Idmt.UnitTests/Services/CoreServicesTests.cs | 4 ++-- .../Services/IdmtUserClaimsPrincipalFactoryTests.cs | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Idmt.Plugin/Features/Manage/RegisterUser.cs b/src/Idmt.Plugin/Features/Manage/RegisterUser.cs index 7df98ce..2f37490 100644 --- a/src/Idmt.Plugin/Features/Manage/RegisterUser.cs +++ b/src/Idmt.Plugin/Features/Manage/RegisterUser.cs @@ -131,11 +131,11 @@ public async Task> HandleAsync( { return Result.Failure("Insufficient permissions to assign this role.", StatusCodes.Status403Forbidden); } - + // Get the tenant ID from the current user service (from tenant context) var tenantId = currentUserService.TenantId ?? throw new InvalidOperationException("Tenant context is not available. Cannot register user without tenant context."); - + // Create user entity with basic information, no password set // User is active by default, but email is not confirmed until password is set // When the user is unregistered, we set IsActive to false (soft delete) diff --git a/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs b/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs index de80835..21d3b64 100644 --- a/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs +++ b/src/Idmt.Plugin/Services/IdmtUserClaimsPrincipalFactory.cs @@ -25,7 +25,7 @@ protected override async Task GenerateClaimsAsync(IdmtUser user) // Add tenant claim for multi-tenant strategies (header, claim, route) // This ensures token validation includes tenant context var claimKey = idmtOptions.Value.MultiTenant.StrategyOptions.GetValueOrDefault(IdmtMultiTenantStrategy.ClaimOption, IdmtMultiTenantStrategy.DefaultClaimType); - + // Try to get tenant info from store using user's TenantId var tenantInfo = await tenantStore.GetAsync(user.TenantId) ?? throw new InvalidOperationException($"Tenant information not found for tenant ID: {user.TenantId}. User ID: {user.Id}"); identity.AddClaim(new Claim(claimKey, tenantInfo.Identifier)); diff --git a/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs b/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs index 8de40fa..6d929c6 100644 --- a/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs +++ b/src/tests/Idmt.UnitTests/Services/CoreServicesTests.cs @@ -140,9 +140,9 @@ public void TenantIdentifier_ReturnsIdentifierFromTenantContext_WhenClaimDoesNot const string tenantIdentifier = "tenant-123"; var tenantInfo = new IdmtTenantInfo("tenant-id-123", tenantIdentifier, "Test Tenant"); var tenantContext = new MultiTenantContext(tenantInfo); - + _tenantContextAccessorMock.Setup(x => x.MultiTenantContext).Returns(tenantContext); - + var user = new System.Security.Claims.ClaimsPrincipal( new System.Security.Claims.ClaimsIdentity()); diff --git a/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs b/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs index 316b376..8abc9b2 100644 --- a/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs +++ b/src/tests/Idmt.UnitTests/Services/IdmtUserClaimsPrincipalFactoryTests.cs @@ -66,7 +66,7 @@ public IdmtUserClaimsPrincipalFactoryTests() _identityOptionsMock.Setup(x => x.Value).Returns(identityOptions); _tenantStoreMock = new Mock>(); - + _idmtOptionsMock = new Mock>(); _idmtOptionsMock.Setup(x => x.Value).Returns(IdmtOptions.Default); @@ -95,7 +95,7 @@ public async Task CreateAsync_AddsIsActiveClaim_WithCorrectValue() const string tenantId = "tenant-id-123"; const string tenantIdentifier = "tenant-123"; var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); - + var user = new IdmtUser { Id = Guid.NewGuid(), @@ -131,7 +131,7 @@ public async Task CreateAsync_AddsIsActiveClaim_WhenUserIsInactive() const string tenantId = "tenant-id-123"; const string tenantIdentifier = "tenant-123"; var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); - + var user = new IdmtUser { Id = Guid.NewGuid(), @@ -159,7 +159,7 @@ public async Task CreateAsync_AddsTenantClaim_WithDefaultClaimType() const string tenantId = "tenant-id-456"; const string tenantIdentifier = "tenant-456"; var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); - + var user = new IdmtUser { Id = Guid.NewGuid(), @@ -246,7 +246,7 @@ public async Task CreateAsync_IncludesBaseClaims() const string tenantId = "tenant-id-123"; const string tenantIdentifier = "tenant-123"; var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); - + var userId = Guid.NewGuid(); var user = new IdmtUser { @@ -280,7 +280,7 @@ public async Task CreateAsync_AddsAllCustomClaims() const string tenantId = "tenant-id-999"; const string tenantIdentifier = "tenant-999"; var tenantInfo = new IdmtTenantInfo(tenantId, tenantIdentifier, "Test Tenant"); - + var user = new IdmtUser { Id = Guid.NewGuid(),