diff --git a/src/Admin/Controllers/UsersController.cs b/src/Admin/Controllers/UsersController.cs index cebb7d4b1e..71be19a041 100644 --- a/src/Admin/Controllers/UsersController.cs +++ b/src/Admin/Controllers/UsersController.cs @@ -184,7 +184,7 @@ public class UsersController : Controller private async Task AccountDeprovisioningEnabled(Guid userId) { return _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning) - ? await _userService.IsManagedByAnyOrganizationAsync(userId) + ? await _userService.IsClaimedByAnyOrganizationAsync(userId) : null; } } diff --git a/src/Api/AdminConsole/Controllers/OrganizationUsersController.cs b/src/Api/AdminConsole/Controllers/OrganizationUsersController.cs index 5fd9109077..8a4cd54026 100644 --- a/src/Api/AdminConsole/Controllers/OrganizationUsersController.cs +++ b/src/Api/AdminConsole/Controllers/OrganizationUsersController.cs @@ -56,8 +56,8 @@ public class OrganizationUsersController : Controller private readonly IOrganizationUserUserDetailsQuery _organizationUserUserDetailsQuery; private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery; private readonly IRemoveOrganizationUserCommand _removeOrganizationUserCommand; - private readonly IDeleteManagedOrganizationUserAccountCommand _deleteManagedOrganizationUserAccountCommand; - private readonly IGetOrganizationUsersManagementStatusQuery _getOrganizationUsersManagementStatusQuery; + private readonly IDeleteClaimedOrganizationUserAccountCommand _deleteClaimedOrganizationUserAccountCommand; + private readonly IGetOrganizationUsersClaimedStatusQuery _getOrganizationUsersClaimedStatusQuery; private readonly IPolicyRequirementQuery _policyRequirementQuery; private readonly IFeatureService _featureService; private readonly IPricingClient _pricingClient; @@ -83,8 +83,8 @@ public class OrganizationUsersController : Controller IOrganizationUserUserDetailsQuery organizationUserUserDetailsQuery, ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery, IRemoveOrganizationUserCommand removeOrganizationUserCommand, - IDeleteManagedOrganizationUserAccountCommand deleteManagedOrganizationUserAccountCommand, - IGetOrganizationUsersManagementStatusQuery getOrganizationUsersManagementStatusQuery, + IDeleteClaimedOrganizationUserAccountCommand deleteClaimedOrganizationUserAccountCommand, + IGetOrganizationUsersClaimedStatusQuery getOrganizationUsersClaimedStatusQuery, IPolicyRequirementQuery policyRequirementQuery, IFeatureService featureService, IPricingClient pricingClient, @@ -109,8 +109,8 @@ public class OrganizationUsersController : Controller _organizationUserUserDetailsQuery = organizationUserUserDetailsQuery; _twoFactorIsEnabledQuery = twoFactorIsEnabledQuery; _removeOrganizationUserCommand = removeOrganizationUserCommand; - _deleteManagedOrganizationUserAccountCommand = deleteManagedOrganizationUserAccountCommand; - _getOrganizationUsersManagementStatusQuery = getOrganizationUsersManagementStatusQuery; + _deleteClaimedOrganizationUserAccountCommand = deleteClaimedOrganizationUserAccountCommand; + _getOrganizationUsersClaimedStatusQuery = getOrganizationUsersClaimedStatusQuery; _policyRequirementQuery = policyRequirementQuery; _featureService = featureService; _pricingClient = pricingClient; @@ -127,11 +127,11 @@ public class OrganizationUsersController : Controller throw new NotFoundException(); } - var managedByOrganization = await GetManagedByOrganizationStatusAsync( + var claimedByOrganizationStatus = await GetClaimedByOrganizationStatusAsync( organizationUser.OrganizationId, [organizationUser.Id]); - var response = new OrganizationUserDetailsResponseModel(organizationUser, managedByOrganization[organizationUser.Id], collections); + var response = new OrganizationUserDetailsResponseModel(organizationUser, claimedByOrganizationStatus[organizationUser.Id], collections); if (includeGroups) { @@ -175,13 +175,13 @@ public class OrganizationUsersController : Controller } ); var organizationUsersTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(organizationUsers); - var organizationUsersManagementStatus = await GetManagedByOrganizationStatusAsync(orgId, organizationUsers.Select(o => o.Id)); + var organizationUsersClaimedStatus = await GetClaimedByOrganizationStatusAsync(orgId, organizationUsers.Select(o => o.Id)); var responses = organizationUsers .Select(o => { var userTwoFactorEnabled = organizationUsersTwoFactorEnabled.FirstOrDefault(u => u.user.Id == o.Id).twoFactorIsEnabled; - var managedByOrganization = organizationUsersManagementStatus[o.Id]; - var orgUser = new OrganizationUserUserDetailsResponseModel(o, userTwoFactorEnabled, managedByOrganization); + var claimedByOrganization = organizationUsersClaimedStatus[o.Id]; + var orgUser = new OrganizationUserUserDetailsResponseModel(o, userTwoFactorEnabled, claimedByOrganization); return orgUser; }); @@ -591,7 +591,7 @@ public class OrganizationUsersController : Controller throw new UnauthorizedAccessException(); } - await _deleteManagedOrganizationUserAccountCommand.DeleteUserAsync(orgId, id, currentUser.Id); + await _deleteClaimedOrganizationUserAccountCommand.DeleteUserAsync(orgId, id, currentUser.Id); } [RequireFeature(FeatureFlagKeys.AccountDeprovisioning)] @@ -610,7 +610,7 @@ public class OrganizationUsersController : Controller throw new UnauthorizedAccessException(); } - var results = await _deleteManagedOrganizationUserAccountCommand.DeleteManyUsersAsync(orgId, model.Ids, currentUser.Id); + var results = await _deleteClaimedOrganizationUserAccountCommand.DeleteManyUsersAsync(orgId, model.Ids, currentUser.Id); return new ListResponseModel(results.Select(r => new OrganizationUserBulkResponseModel(r.OrganizationUserId, r.ErrorMessage))); @@ -717,14 +717,14 @@ public class OrganizationUsersController : Controller new OrganizationUserBulkResponseModel(r.Item1.Id, r.Item2))); } - private async Task> GetManagedByOrganizationStatusAsync(Guid orgId, IEnumerable userIds) + private async Task> GetClaimedByOrganizationStatusAsync(Guid orgId, IEnumerable userIds) { if (!_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)) { return userIds.ToDictionary(kvp => kvp, kvp => false); } - var usersOrganizationManagementStatus = await _getOrganizationUsersManagementStatusQuery.GetUsersOrganizationManagementStatusAsync(orgId, userIds); - return usersOrganizationManagementStatus; + var usersOrganizationClaimedStatus = await _getOrganizationUsersClaimedStatusQuery.GetUsersOrganizationClaimedStatusAsync(orgId, userIds); + return usersOrganizationClaimedStatus; } } diff --git a/src/Api/AdminConsole/Controllers/OrganizationsController.cs b/src/Api/AdminConsole/Controllers/OrganizationsController.cs index 9fa9cb6672..6b7d031a00 100644 --- a/src/Api/AdminConsole/Controllers/OrganizationsController.cs +++ b/src/Api/AdminConsole/Controllers/OrganizationsController.cs @@ -140,10 +140,10 @@ public class OrganizationsController : Controller var organizations = await _organizationUserRepository.GetManyDetailsByUserAsync(userId, OrganizationUserStatusType.Confirmed); - var organizationManagingActiveUser = await _userService.GetOrganizationsManagingUserAsync(userId); - var organizationIdsManagingActiveUser = organizationManagingActiveUser.Select(o => o.Id); + var organizationsClaimingActiveUser = await _userService.GetOrganizationsClaimingUserAsync(userId); + var organizationIdsClaimingActiveUser = organizationsClaimingActiveUser.Select(o => o.Id); - var responses = organizations.Select(o => new ProfileOrganizationResponseModel(o, organizationIdsManagingActiveUser)); + var responses = organizations.Select(o => new ProfileOrganizationResponseModel(o, organizationIdsClaimingActiveUser)); return new ListResponseModel(responses); } @@ -277,9 +277,9 @@ public class OrganizationsController : Controller } if (_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning) - && (await _userService.GetOrganizationsManagingUserAsync(user.Id)).Any(x => x.Id == id)) + && (await _userService.GetOrganizationsClaimingUserAsync(user.Id)).Any(x => x.Id == id)) { - throw new BadRequestException("Managed user account cannot leave managing organization. Contact your organization administrator for additional details."); + throw new BadRequestException("Claimed user account cannot leave claiming organization. Contact your organization administrator for additional details."); } await _removeOrganizationUserCommand.UserLeaveAsync(id, user.Id); diff --git a/src/Api/AdminConsole/Models/Response/Organizations/OrganizationUserResponseModel.cs b/src/Api/AdminConsole/Models/Response/Organizations/OrganizationUserResponseModel.cs index 64dca73aaa..f9e5193045 100644 --- a/src/Api/AdminConsole/Models/Response/Organizations/OrganizationUserResponseModel.cs +++ b/src/Api/AdminConsole/Models/Response/Organizations/OrganizationUserResponseModel.cs @@ -66,24 +66,30 @@ public class OrganizationUserDetailsResponseModel : OrganizationUserResponseMode { public OrganizationUserDetailsResponseModel( OrganizationUser organizationUser, - bool managedByOrganization, + bool claimedByOrganization, IEnumerable collections) : base(organizationUser, "organizationUserDetails") { - ManagedByOrganization = managedByOrganization; + ClaimedByOrganization = claimedByOrganization; Collections = collections.Select(c => new SelectionReadOnlyResponseModel(c)); } public OrganizationUserDetailsResponseModel(OrganizationUserUserDetails organizationUser, - bool managedByOrganization, + bool claimedByOrganization, IEnumerable collections) : base(organizationUser, "organizationUserDetails") { - ManagedByOrganization = managedByOrganization; + ClaimedByOrganization = claimedByOrganization; Collections = collections.Select(c => new SelectionReadOnlyResponseModel(c)); } - public bool ManagedByOrganization { get; set; } + [Obsolete("Please use ClaimedByOrganization instead. This property will be removed in a future version.")] + public bool ManagedByOrganization + { + get => ClaimedByOrganization; + set => ClaimedByOrganization = value; + } + public bool ClaimedByOrganization { get; set; } public IEnumerable Collections { get; set; } @@ -117,7 +123,7 @@ public class OrganizationUserUserMiniDetailsResponseModel : ResponseModel public class OrganizationUserUserDetailsResponseModel : OrganizationUserResponseModel { public OrganizationUserUserDetailsResponseModel(OrganizationUserUserDetails organizationUser, - bool twoFactorEnabled, bool managedByOrganization, string obj = "organizationUserUserDetails") + bool twoFactorEnabled, bool claimedByOrganization, string obj = "organizationUserUserDetails") : base(organizationUser, obj) { if (organizationUser == null) @@ -134,7 +140,7 @@ public class OrganizationUserUserDetailsResponseModel : OrganizationUserResponse Groups = organizationUser.Groups; // Prevent reset password when using key connector. ResetPasswordEnrolled = ResetPasswordEnrolled && !organizationUser.UsesKeyConnector; - ManagedByOrganization = managedByOrganization; + ClaimedByOrganization = claimedByOrganization; } public string Name { get; set; } @@ -142,11 +148,17 @@ public class OrganizationUserUserDetailsResponseModel : OrganizationUserResponse public string AvatarColor { get; set; } public bool TwoFactorEnabled { get; set; } public bool SsoBound { get; set; } + [Obsolete("Please use ClaimedByOrganization instead. This property will be removed in a future version.")] + public bool ManagedByOrganization + { + get => ClaimedByOrganization; + set => ClaimedByOrganization = value; + } /// - /// Indicates if the organization manages the user. If a user is "managed" by an organization, + /// Indicates if the organization claimed the user. If a user is "claimed" by an organization, /// the organization has greater control over their account, and some user actions are restricted. /// - public bool ManagedByOrganization { get; set; } + public bool ClaimedByOrganization { get; set; } public IEnumerable Collections { get; set; } public IEnumerable Groups { get; set; } } diff --git a/src/Api/AdminConsole/Models/Response/ProfileOrganizationResponseModel.cs b/src/Api/AdminConsole/Models/Response/ProfileOrganizationResponseModel.cs index 3a901f11c4..437c30b8b9 100644 --- a/src/Api/AdminConsole/Models/Response/ProfileOrganizationResponseModel.cs +++ b/src/Api/AdminConsole/Models/Response/ProfileOrganizationResponseModel.cs @@ -18,7 +18,7 @@ public class ProfileOrganizationResponseModel : ResponseModel public ProfileOrganizationResponseModel( OrganizationUserOrganizationDetails organization, - IEnumerable organizationIdsManagingUser) + IEnumerable organizationIdsClaimingUser) : this("profileOrganization") { Id = organization.OrganizationId; @@ -51,7 +51,7 @@ public class ProfileOrganizationResponseModel : ResponseModel SsoBound = !string.IsNullOrWhiteSpace(organization.SsoExternalId); Identifier = organization.Identifier; Permissions = CoreHelpers.LoadClassFromJsonData(organization.Permissions); - ResetPasswordEnrolled = organization.ResetPasswordKey != null; + ResetPasswordEnrolled = !string.IsNullOrWhiteSpace(organization.ResetPasswordKey); UserId = organization.UserId; OrganizationUserId = organization.OrganizationUserId; ProviderId = organization.ProviderId; @@ -70,7 +70,7 @@ public class ProfileOrganizationResponseModel : ResponseModel LimitCollectionDeletion = organization.LimitCollectionDeletion; LimitItemDeletion = organization.LimitItemDeletion; AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems; - UserIsManagedByOrganization = organizationIdsManagingUser.Contains(organization.OrganizationId); + UserIsClaimedByOrganization = organizationIdsClaimingUser.Contains(organization.OrganizationId); UseRiskInsights = organization.UseRiskInsights; if (organization.SsoConfig != null) @@ -133,15 +133,26 @@ public class ProfileOrganizationResponseModel : ResponseModel public bool LimitItemDeletion { get; set; } public bool AllowAdminAccessToAllCollectionItems { get; set; } /// - /// Indicates if the organization manages the user. + /// Obsolete. + /// + /// See + /// + [Obsolete("Please use UserIsClaimedByOrganization instead. This property will be removed in a future version.")] + public bool UserIsManagedByOrganization + { + get => UserIsClaimedByOrganization; + set => UserIsClaimedByOrganization = value; + } + /// + /// Indicates if the organization claims the user. /// /// - /// An organization manages a user if the user's email domain is verified by the organization and the user is a member of it. + /// An organization claims a user if the user's email domain is verified by the organization and the user is a member of it. /// The organization must be enabled and able to have verified domains. /// /// /// False if the Account Deprovisioning feature flag is disabled. /// - public bool UserIsManagedByOrganization { get; set; } + public bool UserIsClaimedByOrganization { get; set; } public bool UseRiskInsights { get; set; } } diff --git a/src/Api/AdminConsole/Public/Models/Response/MemberResponseModel.cs b/src/Api/AdminConsole/Public/Models/Response/MemberResponseModel.cs index 91e8788d01..933cda9dca 100644 --- a/src/Api/AdminConsole/Public/Models/Response/MemberResponseModel.cs +++ b/src/Api/AdminConsole/Public/Models/Response/MemberResponseModel.cs @@ -30,7 +30,7 @@ public class MemberResponseModel : MemberBaseModel, IResponseModel Email = user.Email; Status = user.Status; Collections = collections?.Select(c => new AssociationWithPermissionsResponseModel(c)); - ResetPasswordEnrolled = user.ResetPasswordKey != null; + ResetPasswordEnrolled = !string.IsNullOrWhiteSpace(user.ResetPasswordKey); } [SetsRequiredMembers] @@ -49,7 +49,7 @@ public class MemberResponseModel : MemberBaseModel, IResponseModel TwoFactorEnabled = twoFactorEnabled; Status = user.Status; Collections = collections?.Select(c => new AssociationWithPermissionsResponseModel(c)); - ResetPasswordEnrolled = user.ResetPasswordKey != null; + ResetPasswordEnrolled = !string.IsNullOrWhiteSpace(user.ResetPasswordKey); SsoExternalId = user.SsoExternalId; } diff --git a/src/Api/Auth/Controllers/AccountsController.cs b/src/Api/Auth/Controllers/AccountsController.cs index 2555a6fe2d..b22d54fa55 100644 --- a/src/Api/Auth/Controllers/AccountsController.cs +++ b/src/Api/Auth/Controllers/AccountsController.cs @@ -124,11 +124,11 @@ public class AccountsController : Controller throw new BadRequestException("MasterPasswordHash", "Invalid password."); } - var managedUserValidationResult = await _userService.ValidateManagedUserDomainAsync(user, model.NewEmail); + var claimedUserValidationResult = await _userService.ValidateClaimedUserDomainAsync(user, model.NewEmail); - if (!managedUserValidationResult.Succeeded) + if (!claimedUserValidationResult.Succeeded) { - throw new BadRequestException(managedUserValidationResult.Errors); + throw new BadRequestException(claimedUserValidationResult.Errors); } await _userService.InitiateEmailChangeAsync(user, model.NewEmail); @@ -437,11 +437,11 @@ public class AccountsController : Controller var twoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user); var hasPremiumFromOrg = await _userService.HasPremiumFromOrganization(user); - var organizationIdsManagingActiveUser = await GetOrganizationIdsManagingUserAsync(user.Id); + var organizationIdsClaimingActiveUser = await GetOrganizationIdsClaimingUserAsync(user.Id); var response = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails, providerUserOrganizationDetails, twoFactorEnabled, - hasPremiumFromOrg, organizationIdsManagingActiveUser); + hasPremiumFromOrg, organizationIdsClaimingActiveUser); return response; } @@ -451,9 +451,9 @@ public class AccountsController : Controller var userId = _userService.GetProperUserId(User); var organizationUserDetails = await _organizationUserRepository.GetManyDetailsByUserAsync(userId.Value, OrganizationUserStatusType.Confirmed); - var organizationIdsManagingActiveUser = await GetOrganizationIdsManagingUserAsync(userId.Value); + var organizationIdsClaimingUser = await GetOrganizationIdsClaimingUserAsync(userId.Value); - var responseData = organizationUserDetails.Select(o => new ProfileOrganizationResponseModel(o, organizationIdsManagingActiveUser)); + var responseData = organizationUserDetails.Select(o => new ProfileOrganizationResponseModel(o, organizationIdsClaimingUser)); return new ListResponseModel(responseData); } @@ -471,9 +471,9 @@ public class AccountsController : Controller var twoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user); var hasPremiumFromOrg = await _userService.HasPremiumFromOrganization(user); - var organizationIdsManagingActiveUser = await GetOrganizationIdsManagingUserAsync(user.Id); + var organizationIdsClaimingActiveUser = await GetOrganizationIdsClaimingUserAsync(user.Id); - var response = new ProfileResponseModel(user, null, null, null, twoFactorEnabled, hasPremiumFromOrg, organizationIdsManagingActiveUser); + var response = new ProfileResponseModel(user, null, null, null, twoFactorEnabled, hasPremiumFromOrg, organizationIdsClaimingActiveUser); return response; } @@ -490,9 +490,9 @@ public class AccountsController : Controller var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user); var userHasPremiumFromOrganization = await _userService.HasPremiumFromOrganization(user); - var organizationIdsManagingActiveUser = await GetOrganizationIdsManagingUserAsync(user.Id); + var organizationIdsClaimingActiveUser = await GetOrganizationIdsClaimingUserAsync(user.Id); - var response = new ProfileResponseModel(user, null, null, null, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationIdsManagingActiveUser); + var response = new ProfileResponseModel(user, null, null, null, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationIdsClaimingActiveUser); return response; } @@ -560,9 +560,9 @@ public class AccountsController : Controller } else { - // If Account Deprovisioning is enabled, we need to check if the user is managed by any organization. + // If Account Deprovisioning is enabled, we need to check if the user is claimed by any organization. if (_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning) - && await _userService.IsManagedByAnyOrganizationAsync(user.Id)) + && await _userService.IsClaimedByAnyOrganizationAsync(user.Id)) { throw new BadRequestException("Cannot delete accounts owned by an organization. Contact your organization administrator for additional details."); } @@ -763,9 +763,9 @@ public class AccountsController : Controller await _userService.SaveUserAsync(user); } - private async Task> GetOrganizationIdsManagingUserAsync(Guid userId) + private async Task> GetOrganizationIdsClaimingUserAsync(Guid userId) { - var organizationManagingUser = await _userService.GetOrganizationsManagingUserAsync(userId); - return organizationManagingUser.Select(o => o.Id); + var organizationsClaimingUser = await _userService.GetOrganizationsClaimingUserAsync(userId); + return organizationsClaimingUser.Select(o => o.Id); } } diff --git a/src/Api/Billing/Controllers/AccountsController.cs b/src/Api/Billing/Controllers/AccountsController.cs index 9c5811b195..bc263691a8 100644 --- a/src/Api/Billing/Controllers/AccountsController.cs +++ b/src/Api/Billing/Controllers/AccountsController.cs @@ -58,10 +58,10 @@ public class AccountsController( var userTwoFactorEnabled = await userService.TwoFactorIsEnabledAsync(user); var userHasPremiumFromOrganization = await userService.HasPremiumFromOrganization(user); - var organizationIdsManagingActiveUser = await GetOrganizationIdsManagingUserAsync(user.Id); + var organizationIdsClaimingActiveUser = await GetOrganizationIdsClaimingUserAsync(user.Id); var profile = new ProfileResponseModel(user, null, null, null, userTwoFactorEnabled, - userHasPremiumFromOrganization, organizationIdsManagingActiveUser); + userHasPremiumFromOrganization, organizationIdsClaimingActiveUser); return new PaymentResponseModel { UserProfile = profile, @@ -229,9 +229,9 @@ public class AccountsController( await paymentService.SaveTaxInfoAsync(user, taxInfo); } - private async Task> GetOrganizationIdsManagingUserAsync(Guid userId) + private async Task> GetOrganizationIdsClaimingUserAsync(Guid userId) { - var organizationManagingUser = await userService.GetOrganizationsManagingUserAsync(userId); - return organizationManagingUser.Select(o => o.Id); + var organizationsClaimingUser = await userService.GetOrganizationsClaimingUserAsync(userId); + return organizationsClaimingUser.Select(o => o.Id); } } diff --git a/src/Api/Billing/Controllers/OrganizationsController.cs b/src/Api/Billing/Controllers/OrganizationsController.cs index de14a8d798..510f6c2835 100644 --- a/src/Api/Billing/Controllers/OrganizationsController.cs +++ b/src/Api/Billing/Controllers/OrganizationsController.cs @@ -409,9 +409,9 @@ public class OrganizationsController( organizationId, OrganizationUserStatusType.Confirmed); - var organizationIdsManagingActiveUser = (await userService.GetOrganizationsManagingUserAsync(userId)) + var organizationIdsClaimingActiveUser = (await userService.GetOrganizationsClaimingUserAsync(userId)) .Select(o => o.Id); - return new ProfileOrganizationResponseModel(organizationUserDetails, organizationIdsManagingActiveUser); + return new ProfileOrganizationResponseModel(organizationUserDetails, organizationIdsClaimingActiveUser); } } diff --git a/src/Api/Models/Response/ProfileResponseModel.cs b/src/Api/Models/Response/ProfileResponseModel.cs index 82ffb05b0b..246b3c3227 100644 --- a/src/Api/Models/Response/ProfileResponseModel.cs +++ b/src/Api/Models/Response/ProfileResponseModel.cs @@ -15,7 +15,7 @@ public class ProfileResponseModel : ResponseModel IEnumerable providerUserOrganizationDetails, bool twoFactorEnabled, bool premiumFromOrganization, - IEnumerable organizationIdsManagingUser) : base("profile") + IEnumerable organizationIdsClaimingUser) : base("profile") { if (user == null) { @@ -38,7 +38,7 @@ public class ProfileResponseModel : ResponseModel AvatarColor = user.AvatarColor; CreationDate = user.CreationDate; VerifyDevices = user.VerifyDevices; - Organizations = organizationsUserDetails?.Select(o => new ProfileOrganizationResponseModel(o, organizationIdsManagingUser)); + Organizations = organizationsUserDetails?.Select(o => new ProfileOrganizationResponseModel(o, organizationIdsClaimingUser)); Providers = providerUserDetails?.Select(p => new ProfileProviderResponseModel(p)); ProviderOrganizations = providerUserOrganizationDetails?.Select(po => new ProfileProviderOrganizationResponseModel(po)); diff --git a/src/Api/Vault/Controllers/CiphersController.cs b/src/Api/Vault/Controllers/CiphersController.cs index 0f03f54be1..a9646acd1c 100644 --- a/src/Api/Vault/Controllers/CiphersController.cs +++ b/src/Api/Vault/Controllers/CiphersController.cs @@ -1091,9 +1091,9 @@ public class CiphersController : Controller throw new BadRequestException(ModelState); } - // If Account Deprovisioning is enabled, we need to check if the user is managed by any organization. + // If Account Deprovisioning is enabled, we need to check if the user is claimed by any organization. if (_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning) - && await _userService.IsManagedByAnyOrganizationAsync(user.Id)) + && await _userService.IsClaimedByAnyOrganizationAsync(user.Id)) { throw new BadRequestException("Cannot purge accounts owned by an organization. Contact your organization administrator for additional details."); } diff --git a/src/Api/Vault/Controllers/SyncController.cs b/src/Api/Vault/Controllers/SyncController.cs index 1b8978fc65..4b66c7f2bd 100644 --- a/src/Api/Vault/Controllers/SyncController.cs +++ b/src/Api/Vault/Controllers/SyncController.cs @@ -104,13 +104,13 @@ public class SyncController : Controller var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user); var userHasPremiumFromOrganization = await _userService.HasPremiumFromOrganization(user); - var organizationManagingActiveUser = await _userService.GetOrganizationsManagingUserAsync(user.Id); - var organizationIdsManagingActiveUser = organizationManagingActiveUser.Select(o => o.Id); + var organizationClaimingActiveUser = await _userService.GetOrganizationsClaimingUserAsync(user.Id); + var organizationIdsClaimingActiveUser = organizationClaimingActiveUser.Select(o => o.Id); var organizationAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); var response = new SyncResponseModel(_globalSettings, user, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationAbilities, - organizationIdsManagingActiveUser, organizationUserDetails, providerUserDetails, providerUserOrganizationDetails, + organizationIdsClaimingActiveUser, organizationUserDetails, providerUserDetails, providerUserOrganizationDetails, folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains, policies, sends); return response; } diff --git a/src/Api/Vault/Models/Response/SyncResponseModel.cs b/src/Api/Vault/Models/Response/SyncResponseModel.cs index f1465264f2..b9da786567 100644 --- a/src/Api/Vault/Models/Response/SyncResponseModel.cs +++ b/src/Api/Vault/Models/Response/SyncResponseModel.cs @@ -23,7 +23,7 @@ public class SyncResponseModel : ResponseModel bool userTwoFactorEnabled, bool userHasPremiumFromOrganization, IDictionary organizationAbilities, - IEnumerable organizationIdsManagingUser, + IEnumerable organizationIdsClaimingingUser, IEnumerable organizationUserDetails, IEnumerable providerUserDetails, IEnumerable providerUserOrganizationDetails, @@ -37,7 +37,7 @@ public class SyncResponseModel : ResponseModel : base("sync") { Profile = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails, - providerUserOrganizationDetails, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationIdsManagingUser); + providerUserOrganizationDetails, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationIdsClaimingingUser); Folders = folders.Select(f => new FolderResponseModel(f)); Ciphers = ciphers.Select(cipher => new CipherDetailsResponseModel( diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommand.cs index e011819f0f..ec635282f7 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommand.cs @@ -154,6 +154,6 @@ public class VerifyOrganizationDomainCommand( var organization = await organizationRepository.GetByIdAsync(domain.OrganizationId); - await mailService.SendClaimedDomainUserEmailAsync(new ManagedUserDomainClaimedEmails(domainUserEmails, organization)); + await mailService.SendClaimedDomainUserEmailAsync(new ClaimedUserDomainClaimedEmails(domainUserEmails, organization)); } } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteManagedOrganizationUserAccountCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteClaimedOrganizationUserAccountCommand.cs similarity index 89% rename from src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteManagedOrganizationUserAccountCommand.cs rename to src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteClaimedOrganizationUserAccountCommand.cs index 7b7d8003a3..49ddf0a548 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteManagedOrganizationUserAccountCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteClaimedOrganizationUserAccountCommand.cs @@ -15,11 +15,11 @@ using Bit.Core.Tools.Services; namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers; -public class DeleteManagedOrganizationUserAccountCommand : IDeleteManagedOrganizationUserAccountCommand +public class DeleteClaimedOrganizationUserAccountCommand : IDeleteClaimedOrganizationUserAccountCommand { private readonly IUserService _userService; private readonly IEventService _eventService; - private readonly IGetOrganizationUsersManagementStatusQuery _getOrganizationUsersManagementStatusQuery; + private readonly IGetOrganizationUsersClaimedStatusQuery _getOrganizationUsersClaimedStatusQuery; private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IUserRepository _userRepository; private readonly ICurrentContext _currentContext; @@ -28,10 +28,10 @@ public class DeleteManagedOrganizationUserAccountCommand : IDeleteManagedOrganiz private readonly IPushNotificationService _pushService; private readonly IOrganizationRepository _organizationRepository; private readonly IProviderUserRepository _providerUserRepository; - public DeleteManagedOrganizationUserAccountCommand( + public DeleteClaimedOrganizationUserAccountCommand( IUserService userService, IEventService eventService, - IGetOrganizationUsersManagementStatusQuery getOrganizationUsersManagementStatusQuery, + IGetOrganizationUsersClaimedStatusQuery getOrganizationUsersClaimedStatusQuery, IOrganizationUserRepository organizationUserRepository, IUserRepository userRepository, ICurrentContext currentContext, @@ -43,7 +43,7 @@ public class DeleteManagedOrganizationUserAccountCommand : IDeleteManagedOrganiz { _userService = userService; _eventService = eventService; - _getOrganizationUsersManagementStatusQuery = getOrganizationUsersManagementStatusQuery; + _getOrganizationUsersClaimedStatusQuery = getOrganizationUsersClaimedStatusQuery; _organizationUserRepository = organizationUserRepository; _userRepository = userRepository; _currentContext = currentContext; @@ -62,10 +62,10 @@ public class DeleteManagedOrganizationUserAccountCommand : IDeleteManagedOrganiz throw new NotFoundException("Member not found."); } - var managementStatus = await _getOrganizationUsersManagementStatusQuery.GetUsersOrganizationManagementStatusAsync(organizationId, new[] { organizationUserId }); + var claimedStatus = await _getOrganizationUsersClaimedStatusQuery.GetUsersOrganizationClaimedStatusAsync(organizationId, new[] { organizationUserId }); var hasOtherConfirmedOwners = await _hasConfirmedOwnersExceptQuery.HasConfirmedOwnersExceptAsync(organizationId, new[] { organizationUserId }, includeProvider: true); - await ValidateDeleteUserAsync(organizationId, organizationUser, deletingUserId, managementStatus, hasOtherConfirmedOwners); + await ValidateDeleteUserAsync(organizationId, organizationUser, deletingUserId, claimedStatus, hasOtherConfirmedOwners); var user = await _userRepository.GetByIdAsync(organizationUser.UserId!.Value); if (user == null) @@ -83,7 +83,7 @@ public class DeleteManagedOrganizationUserAccountCommand : IDeleteManagedOrganiz var userIds = orgUsers.Where(ou => ou.UserId.HasValue).Select(ou => ou.UserId!.Value).ToList(); var users = await _userRepository.GetManyAsync(userIds); - var managementStatus = await _getOrganizationUsersManagementStatusQuery.GetUsersOrganizationManagementStatusAsync(organizationId, orgUserIds); + var claimedStatus = await _getOrganizationUsersClaimedStatusQuery.GetUsersOrganizationClaimedStatusAsync(organizationId, orgUserIds); var hasOtherConfirmedOwners = await _hasConfirmedOwnersExceptQuery.HasConfirmedOwnersExceptAsync(organizationId, orgUserIds, includeProvider: true); var results = new List<(Guid OrganizationUserId, string? ErrorMessage)>(); @@ -97,7 +97,7 @@ public class DeleteManagedOrganizationUserAccountCommand : IDeleteManagedOrganiz throw new NotFoundException("Member not found."); } - await ValidateDeleteUserAsync(organizationId, orgUser, deletingUserId, managementStatus, hasOtherConfirmedOwners); + await ValidateDeleteUserAsync(organizationId, orgUser, deletingUserId, claimedStatus, hasOtherConfirmedOwners); var user = users.FirstOrDefault(u => u.Id == orgUser.UserId); if (user == null) @@ -129,7 +129,7 @@ public class DeleteManagedOrganizationUserAccountCommand : IDeleteManagedOrganiz return results; } - private async Task ValidateDeleteUserAsync(Guid organizationId, OrganizationUser orgUser, Guid? deletingUserId, IDictionary managementStatus, bool hasOtherConfirmedOwners) + private async Task ValidateDeleteUserAsync(Guid organizationId, OrganizationUser orgUser, Guid? deletingUserId, IDictionary claimedStatus, bool hasOtherConfirmedOwners) { if (!orgUser.UserId.HasValue || orgUser.Status == OrganizationUserStatusType.Invited) { @@ -159,10 +159,9 @@ public class DeleteManagedOrganizationUserAccountCommand : IDeleteManagedOrganiz throw new BadRequestException("Custom users can not delete admins."); } - - if (!managementStatus.TryGetValue(orgUser.Id, out var isManaged) || !isManaged) + if (!claimedStatus.TryGetValue(orgUser.Id, out var isClaimed) || !isClaimed) { - throw new BadRequestException("Member is not managed by the organization."); + throw new BadRequestException("Member is not claimed by the organization."); } } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersManagementStatusQuery.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersClaimedStatusQuery.cs similarity index 82% rename from src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersManagementStatusQuery.cs rename to src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersClaimedStatusQuery.cs index 4ff6b87443..1dda9483cd 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersManagementStatusQuery.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersClaimedStatusQuery.cs @@ -4,12 +4,12 @@ using Bit.Core.Services; namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers; -public class GetOrganizationUsersManagementStatusQuery : IGetOrganizationUsersManagementStatusQuery +public class GetOrganizationUsersClaimedStatusQuery : IGetOrganizationUsersClaimedStatusQuery { private readonly IApplicationCacheService _applicationCacheService; private readonly IOrganizationUserRepository _organizationUserRepository; - public GetOrganizationUsersManagementStatusQuery( + public GetOrganizationUsersClaimedStatusQuery( IApplicationCacheService applicationCacheService, IOrganizationUserRepository organizationUserRepository) { @@ -17,11 +17,11 @@ public class GetOrganizationUsersManagementStatusQuery : IGetOrganizationUsersMa _organizationUserRepository = organizationUserRepository; } - public async Task> GetUsersOrganizationManagementStatusAsync(Guid organizationId, IEnumerable organizationUserIds) + public async Task> GetUsersOrganizationClaimedStatusAsync(Guid organizationId, IEnumerable organizationUserIds) { if (organizationUserIds.Any()) { - // Users can only be managed by an Organization that is enabled and can have organization domains + // Users can only be claimed by an Organization that is enabled and can have organization domains var organizationAbility = await _applicationCacheService.GetOrganizationAbilityAsync(organizationId); // TODO: Replace "UseSso" with a new organization ability like "UseOrganizationDomains" (PM-11622). @@ -31,7 +31,7 @@ public class GetOrganizationUsersManagementStatusQuery : IGetOrganizationUsersMa // Get all organization users with claimed domains by the organization var organizationUsersWithClaimedDomain = await _organizationUserRepository.GetManyByOrganizationWithClaimedDomainsAsync(organizationId); - // Create a dictionary with the OrganizationUserId and a boolean indicating if the user is managed by the organization + // Create a dictionary with the OrganizationUserId and a boolean indicating if the user is claimed by the organization return organizationUserIds.ToDictionary(ouId => ouId, ouId => organizationUsersWithClaimedDomain.Any(ou => ou.Id == ouId)); } } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IDeleteManagedOrganizationUserAccountCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IDeleteClaimedOrganizationUserAccountCommand.cs similarity index 92% rename from src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IDeleteManagedOrganizationUserAccountCommand.cs rename to src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IDeleteClaimedOrganizationUserAccountCommand.cs index d548966aaf..1c79687be9 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IDeleteManagedOrganizationUserAccountCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IDeleteClaimedOrganizationUserAccountCommand.cs @@ -2,7 +2,7 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; -public interface IDeleteManagedOrganizationUserAccountCommand +public interface IDeleteClaimedOrganizationUserAccountCommand { /// /// Removes a user from an organization and deletes all of their associated user data. diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IGetOrganizationUsersManagementStatusQuery.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IGetOrganizationUsersClaimedStatusQuery.cs similarity index 67% rename from src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IGetOrganizationUsersManagementStatusQuery.cs rename to src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IGetOrganizationUsersClaimedStatusQuery.cs index 694b44dd78..74a7d5fc0e 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IGetOrganizationUsersManagementStatusQuery.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/Interfaces/IGetOrganizationUsersClaimedStatusQuery.cs @@ -1,19 +1,19 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; -public interface IGetOrganizationUsersManagementStatusQuery +public interface IGetOrganizationUsersClaimedStatusQuery { /// - /// Checks whether each user in the provided list of organization user IDs is managed by the specified organization. + /// Checks whether each user in the provided list of organization user IDs is claimed by the specified organization. /// /// The unique identifier of the organization to check against. /// A list of OrganizationUserIds to be checked. /// - /// A managed user is a user whose email domain matches one of the Organization's verified domains. + /// A claimed user is a user whose email domain matches one of the Organization's verified domains. /// The organization must be enabled and be on an Enterprise plan. /// /// - /// A dictionary containing the OrganizationUserId and a boolean indicating if the user is managed by the organization. + /// A dictionary containing the OrganizationUserId and a boolean indicating if the user is claimed by the organization. /// - Task> GetUsersOrganizationManagementStatusAsync(Guid organizationId, + Task> GetUsersOrganizationClaimedStatusAsync(Guid organizationId, IEnumerable organizationUserIds); } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/RemoveOrganizationUserCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/RemoveOrganizationUserCommand.cs index 3568a2a2b9..4de2cd0ea5 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/RemoveOrganizationUserCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/RemoveOrganizationUserCommand.cs @@ -18,7 +18,7 @@ public class RemoveOrganizationUserCommand : IRemoveOrganizationUserCommand private readonly IPushRegistrationService _pushRegistrationService; private readonly ICurrentContext _currentContext; private readonly IHasConfirmedOwnersExceptQuery _hasConfirmedOwnersExceptQuery; - private readonly IGetOrganizationUsersManagementStatusQuery _getOrganizationUsersManagementStatusQuery; + private readonly IGetOrganizationUsersClaimedStatusQuery _getOrganizationUsersClaimedStatusQuery; private readonly IFeatureService _featureService; private readonly TimeProvider _timeProvider; @@ -38,7 +38,7 @@ public class RemoveOrganizationUserCommand : IRemoveOrganizationUserCommand IPushRegistrationService pushRegistrationService, ICurrentContext currentContext, IHasConfirmedOwnersExceptQuery hasConfirmedOwnersExceptQuery, - IGetOrganizationUsersManagementStatusQuery getOrganizationUsersManagementStatusQuery, + IGetOrganizationUsersClaimedStatusQuery getOrganizationUsersClaimedStatusQuery, IFeatureService featureService, TimeProvider timeProvider) { @@ -49,7 +49,7 @@ public class RemoveOrganizationUserCommand : IRemoveOrganizationUserCommand _pushRegistrationService = pushRegistrationService; _currentContext = currentContext; _hasConfirmedOwnersExceptQuery = hasConfirmedOwnersExceptQuery; - _getOrganizationUsersManagementStatusQuery = getOrganizationUsersManagementStatusQuery; + _getOrganizationUsersClaimedStatusQuery = getOrganizationUsersClaimedStatusQuery; _featureService = featureService; _timeProvider = timeProvider; } @@ -161,8 +161,8 @@ public class RemoveOrganizationUserCommand : IRemoveOrganizationUserCommand if (_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning) && deletingUserId.HasValue && eventSystemUser == null) { - var managementStatus = await _getOrganizationUsersManagementStatusQuery.GetUsersOrganizationManagementStatusAsync(orgUser.OrganizationId, new[] { orgUser.Id }); - if (managementStatus.TryGetValue(orgUser.Id, out var isManaged) && isManaged) + var claimedStatus = await _getOrganizationUsersClaimedStatusQuery.GetUsersOrganizationClaimedStatusAsync(orgUser.OrganizationId, new[] { orgUser.Id }); + if (claimedStatus.TryGetValue(orgUser.Id, out var isClaimed) && isClaimed) { throw new BadRequestException(RemoveClaimedAccountErrorMessage); } @@ -214,8 +214,8 @@ public class RemoveOrganizationUserCommand : IRemoveOrganizationUserCommand deletingUserIsOwner = await _currentContext.OrganizationOwner(organizationId); } - var managementStatus = _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning) && deletingUserId.HasValue && eventSystemUser == null - ? await _getOrganizationUsersManagementStatusQuery.GetUsersOrganizationManagementStatusAsync(organizationId, filteredUsers.Select(u => u.Id)) + var claimedStatus = _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning) && deletingUserId.HasValue && eventSystemUser == null + ? await _getOrganizationUsersClaimedStatusQuery.GetUsersOrganizationClaimedStatusAsync(organizationId, filteredUsers.Select(u => u.Id)) : filteredUsers.ToDictionary(u => u.Id, u => false); var result = new List<(OrganizationUser OrganizationUser, string ErrorMessage)>(); foreach (var orgUser in filteredUsers) @@ -232,7 +232,7 @@ public class RemoveOrganizationUserCommand : IRemoveOrganizationUserCommand throw new BadRequestException(RemoveOwnerByNonOwnerErrorMessage); } - if (managementStatus.TryGetValue(orgUser.Id, out var isManaged) && isManaged) + if (claimedStatus.TryGetValue(orgUser.Id, out var isClaimed) && isClaimed) { throw new BadRequestException(RemoveClaimedAccountErrorMessage); } diff --git a/src/Core/Auth/Models/Mail/CannotDeleteManagedAccountViewModel.cs b/src/Core/Auth/Models/Mail/CannotDeleteClaimedAccountViewModel.cs similarity index 53% rename from src/Core/Auth/Models/Mail/CannotDeleteManagedAccountViewModel.cs rename to src/Core/Auth/Models/Mail/CannotDeleteClaimedAccountViewModel.cs index 02549a9595..15fc9fd7f0 100644 --- a/src/Core/Auth/Models/Mail/CannotDeleteManagedAccountViewModel.cs +++ b/src/Core/Auth/Models/Mail/CannotDeleteClaimedAccountViewModel.cs @@ -2,6 +2,6 @@ namespace Bit.Core.Auth.Models.Mail; -public class CannotDeleteManagedAccountViewModel : BaseMailModel +public class CannotDeleteClaimedAccountViewModel : BaseMailModel { } diff --git a/src/Core/Auth/UserFeatures/Registration/Implementations/SendVerificationEmailForRegistrationCommand.cs b/src/Core/Auth/UserFeatures/Registration/Implementations/SendVerificationEmailForRegistrationCommand.cs index 21a421b9d0..3f89e9ad0e 100644 --- a/src/Core/Auth/UserFeatures/Registration/Implementations/SendVerificationEmailForRegistrationCommand.cs +++ b/src/Core/Auth/UserFeatures/Registration/Implementations/SendVerificationEmailForRegistrationCommand.cs @@ -53,23 +53,10 @@ public class SendVerificationEmailForRegistrationCommand : ISendVerificationEmai var user = await _userRepository.GetByEmailAsync(email); var userExists = user != null; - // Delays enabled by default; flag must be enabled to remove the delays. - var delaysEnabled = !_featureService.IsEnabled(FeatureFlagKeys.EmailVerificationDisableTimingDelays); - if (!_globalSettings.EnableEmailVerification) { - if (userExists) { - - if (delaysEnabled) - { - // Add delay to prevent timing attacks - // Note: sub 140 ms feels responsive to users so we are using a random value between 100 - 130 ms - // as it should be long enough to prevent timing attacks but not too long to be noticeable to the user. - await Task.Delay(Random.Shared.Next(100, 130)); - } - throw new BadRequestException($"Email {email} is already taken"); } @@ -87,11 +74,6 @@ public class SendVerificationEmailForRegistrationCommand : ISendVerificationEmai await _mailService.SendRegistrationVerificationEmailAsync(email, token); } - if (delaysEnabled) - { - // Add random delay between 100ms-130ms to prevent timing attacks - await Task.Delay(Random.Shared.Next(100, 130)); - } // User exists but we will return a 200 regardless of whether the email was sent or not; so return null return null; } diff --git a/src/Core/Billing/Services/Implementations/SubscriberService.cs b/src/Core/Billing/Services/Implementations/SubscriberService.cs index e4b0594433..1b0e5b665b 100644 --- a/src/Core/Billing/Services/Implementations/SubscriberService.cs +++ b/src/Core/Billing/Services/Implementations/SubscriberService.cs @@ -622,47 +622,45 @@ public class SubscriberService( await stripeAdapter.TaxIdDeleteAsync(customer.Id, taxId.Id); } - if (string.IsNullOrWhiteSpace(taxInformation.TaxId)) + if (!string.IsNullOrWhiteSpace(taxInformation.TaxId)) { - return; - } - - var taxIdType = taxInformation.TaxIdType; - if (string.IsNullOrWhiteSpace(taxIdType)) - { - taxIdType = taxService.GetStripeTaxCode(taxInformation.Country, - taxInformation.TaxId); - - if (taxIdType == null) + var taxIdType = taxInformation.TaxIdType; + if (string.IsNullOrWhiteSpace(taxIdType)) { - logger.LogWarning("Could not infer tax ID type in country '{Country}' with tax ID '{TaxID}'.", - taxInformation.Country, + taxIdType = taxService.GetStripeTaxCode(taxInformation.Country, taxInformation.TaxId); - throw new Exceptions.BadRequestException("billingTaxIdTypeInferenceError"); - } - } - try - { - await stripeAdapter.TaxIdCreateAsync(customer.Id, - new TaxIdCreateOptions { Type = taxIdType, Value = taxInformation.TaxId }); - } - catch (StripeException e) - { - switch (e.StripeError.Code) - { - case StripeConstants.ErrorCodes.TaxIdInvalid: - logger.LogWarning("Invalid tax ID '{TaxID}' for country '{Country}'.", - taxInformation.TaxId, - taxInformation.Country); - throw new Exceptions.BadRequestException("billingInvalidTaxIdError"); - default: - logger.LogError(e, - "Error creating tax ID '{TaxId}' in country '{Country}' for customer '{CustomerID}'.", - taxInformation.TaxId, + if (taxIdType == null) + { + logger.LogWarning("Could not infer tax ID type in country '{Country}' with tax ID '{TaxID}'.", taxInformation.Country, - customer.Id); - throw new Exceptions.BadRequestException("billingTaxIdCreationError"); + taxInformation.TaxId); + throw new Exceptions.BadRequestException("billingTaxIdTypeInferenceError"); + } + } + + try + { + await stripeAdapter.TaxIdCreateAsync(customer.Id, + new TaxIdCreateOptions { Type = taxIdType, Value = taxInformation.TaxId }); + } + catch (StripeException e) + { + switch (e.StripeError.Code) + { + case StripeConstants.ErrorCodes.TaxIdInvalid: + logger.LogWarning("Invalid tax ID '{TaxID}' for country '{Country}'.", + taxInformation.TaxId, + taxInformation.Country); + throw new Exceptions.BadRequestException("billingInvalidTaxIdError"); + default: + logger.LogError(e, + "Error creating tax ID '{TaxId}' in country '{Country}' for customer '{CustomerID}'.", + taxInformation.TaxId, + taxInformation.Country, + customer.Id); + throw new Exceptions.BadRequestException("billingTaxIdCreationError"); + } } } diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index 9ba30786d1..0eaa6cd85f 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -105,7 +105,6 @@ public static class FeatureFlagKeys public const string AccountDeprovisioning = "pm-10308-account-deprovisioning"; public const string VerifiedSsoDomainEndpoint = "pm-12337-refactor-sso-details-endpoint"; public const string LimitItemDeletion = "pm-15493-restrict-item-deletion-to-can-manage-permission"; - public const string PushSyncOrgKeysOnRevokeRestore = "pm-17168-push-sync-org-keys-on-revoke-restore"; public const string PolicyRequirements = "pm-14439-policy-requirements"; public const string SsoExternalIdVisibility = "pm-18630-sso-external-id-visibility"; public const string ScimInviteUserOptimization = "pm-16811-optimize-invite-user-flow-to-fail-fast"; @@ -115,7 +114,6 @@ public static class FeatureFlagKeys public const string TwoFactorExtensionDataPersistence = "pm-9115-two-factor-extension-data-persistence"; public const string DuoRedirect = "duo-redirect"; public const string EmailVerification = "email-verification"; - public const string EmailVerificationDisableTimingDelays = "email-verification-disable-timing-delays"; public const string DeviceTrustLogging = "pm-8285-device-trust-logging"; public const string AuthenticatorTwoFactorToken = "authenticator-2fa-token"; public const string UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh"; diff --git a/src/Core/Enums/EncryptionType.cs b/src/Core/Enums/EncryptionType.cs index 776ca99a93..52231e047c 100644 --- a/src/Core/Enums/EncryptionType.cs +++ b/src/Core/Enums/EncryptionType.cs @@ -4,9 +4,13 @@ // EncryptedStringAttribute public enum EncryptionType : byte { + // symmetric AesCbc256_B64 = 0, AesCbc128_HmacSha256_B64 = 1, AesCbc256_HmacSha256_B64 = 2, + XChaCha20Poly1305_B64 = 7, + + // asymmetric Rsa2048_OaepSha256_B64 = 3, Rsa2048_OaepSha1_B64 = 4, Rsa2048_OaepSha256_HmacSha256_B64 = 5, diff --git a/src/Core/MailTemplates/Handlebars/AdminConsole/CannotDeleteManagedAccount.html.hbs b/src/Core/MailTemplates/Handlebars/AdminConsole/CannotDeleteClaimedAccount.html.hbs similarity index 100% rename from src/Core/MailTemplates/Handlebars/AdminConsole/CannotDeleteManagedAccount.html.hbs rename to src/Core/MailTemplates/Handlebars/AdminConsole/CannotDeleteClaimedAccount.html.hbs diff --git a/src/Core/MailTemplates/Handlebars/AdminConsole/CannotDeleteManagedAccount.text.hbs b/src/Core/MailTemplates/Handlebars/AdminConsole/CannotDeleteClaimedAccount.text.hbs similarity index 100% rename from src/Core/MailTemplates/Handlebars/AdminConsole/CannotDeleteManagedAccount.text.hbs rename to src/Core/MailTemplates/Handlebars/AdminConsole/CannotDeleteClaimedAccount.text.hbs diff --git a/src/Core/Models/Data/Organizations/ManagedUserDomainClaimedEmails.cs b/src/Core/Models/Data/Organizations/ClaimedUserDomainClaimedEmails.cs similarity index 66% rename from src/Core/Models/Data/Organizations/ManagedUserDomainClaimedEmails.cs rename to src/Core/Models/Data/Organizations/ClaimedUserDomainClaimedEmails.cs index 429257e266..2b73fc1525 100644 --- a/src/Core/Models/Data/Organizations/ManagedUserDomainClaimedEmails.cs +++ b/src/Core/Models/Data/Organizations/ClaimedUserDomainClaimedEmails.cs @@ -2,4 +2,4 @@ namespace Bit.Core.Models.Data.Organizations; -public record ManagedUserDomainClaimedEmails(IEnumerable EmailList, Organization Organization); +public record ClaimedUserDomainClaimedEmails(IEnumerable EmailList, Organization Organization); diff --git a/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs b/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs index c76345972a..96d9095c1a 100644 --- a/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs +++ b/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs @@ -121,7 +121,7 @@ public static class OrganizationServiceCollectionExtensions services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); + services.AddScoped(); services.AddScoped(); } @@ -172,7 +172,7 @@ public static class OrganizationServiceCollectionExtensions services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); + services.AddScoped(); services.AddScoped(); diff --git a/src/Core/Platform/X509ChainCustomization/X509ChainOptions.cs b/src/Core/Platform/X509ChainCustomization/X509ChainOptions.cs index 189a1087f5..6cd06acf3c 100644 --- a/src/Core/Platform/X509ChainCustomization/X509ChainOptions.cs +++ b/src/Core/Platform/X509ChainCustomization/X509ChainOptions.cs @@ -53,6 +53,10 @@ public sealed class X509ChainOptions return false; } + // Do this outside of the callback so that we aren't opening the root store every request. + using var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine, OpenFlags.ReadOnly); + var rootCertificates = store.Certificates; + // Ref: https://github.com/dotnet/runtime/issues/39835#issuecomment-663020581 callback = (certificate, chain, errors) => { @@ -62,6 +66,10 @@ public sealed class X509ChainOptions } chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; + + // We want our additional certificates to be in addition to the machines root store. + chain.ChainPolicy.CustomTrustStore.AddRange(rootCertificates); + foreach (var additionalCertificate in AdditionalCustomTrustCertificates) { chain.ChainPolicy.CustomTrustStore.Add(additionalCertificate); diff --git a/src/Core/Services/IMailService.cs b/src/Core/Services/IMailService.cs index e61127c57a..48e0464905 100644 --- a/src/Core/Services/IMailService.cs +++ b/src/Core/Services/IMailService.cs @@ -21,7 +21,7 @@ public interface IMailService ProductTierType productTier, IEnumerable products); Task SendVerifyDeleteEmailAsync(string email, Guid userId, string token); - Task SendCannotDeleteManagedAccountEmailAsync(string email); + Task SendCannotDeleteClaimedAccountEmailAsync(string email); Task SendChangeEmailAlreadyExistsEmailAsync(string fromEmail, string toEmail); Task SendChangeEmailEmailAsync(string newEmailAddress, string token); Task SendTwoFactorEmailAsync(string email, string accountEmail, string token, string deviceIp, string deviceType, bool authentication = true); @@ -97,7 +97,7 @@ public interface IMailService Task SendRequestSMAccessToAdminEmailAsync(IEnumerable adminEmails, string organizationName, string userRequestingAccess, string emailContent); Task SendFamiliesForEnterpriseRemoveSponsorshipsEmailAsync(string email, string offerAcceptanceDate, string organizationId, string organizationName); - Task SendClaimedDomainUserEmailAsync(ManagedUserDomainClaimedEmails emailList); + Task SendClaimedDomainUserEmailAsync(ClaimedUserDomainClaimedEmails emailList); Task SendDeviceApprovalRequestedNotificationEmailAsync(IEnumerable adminEmails, Guid organizationId, string email, string userName); Task SendBulkSecurityTaskNotificationsAsync(Organization org, IEnumerable securityTaskNotifications, IEnumerable adminOwnerEmails); } diff --git a/src/Core/Services/IUserService.cs b/src/Core/Services/IUserService.cs index b6a1d1f05b..9b12713218 100644 --- a/src/Core/Services/IUserService.cs +++ b/src/Core/Services/IUserService.cs @@ -134,7 +134,7 @@ public interface IUserService /// /// False if the Account Deprovisioning feature flag is disabled. /// - Task IsManagedByAnyOrganizationAsync(Guid userId); + Task IsClaimedByAnyOrganizationAsync(Guid userId); /// /// Verify whether the new email domain meets the requirements for managed users. @@ -142,9 +142,9 @@ public interface IUserService /// /// /// - /// IdentityResult + /// IdentityResult /// - Task ValidateManagedUserDomainAsync(User user, string newEmail); + Task ValidateClaimedUserDomainAsync(User user, string newEmail); /// /// Gets the organizations that manage the user. @@ -152,6 +152,6 @@ public interface IUserService /// /// An empty collection if the Account Deprovisioning feature flag is disabled. /// - /// - Task> GetOrganizationsManagingUserAsync(Guid userId); + /// + Task> GetOrganizationsClaimingUserAsync(Guid userId); } diff --git a/src/Core/Services/Implementations/HandlebarsMailService.cs b/src/Core/Services/Implementations/HandlebarsMailService.cs index a551342324..7bcf2c0ef5 100644 --- a/src/Core/Services/Implementations/HandlebarsMailService.cs +++ b/src/Core/Services/Implementations/HandlebarsMailService.cs @@ -117,16 +117,16 @@ public class HandlebarsMailService : IMailService await _mailDeliveryService.SendEmailAsync(message); } - public async Task SendCannotDeleteManagedAccountEmailAsync(string email) + public async Task SendCannotDeleteClaimedAccountEmailAsync(string email) { var message = CreateDefaultMessage("Delete Your Account", email); - var model = new CannotDeleteManagedAccountViewModel + var model = new CannotDeleteClaimedAccountViewModel { WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash, SiteName = _globalSettings.SiteName, }; - await AddMessageContentAsync(message, "AdminConsole.CannotDeleteManagedAccount", model); - message.Category = "CannotDeleteManagedAccount"; + await AddMessageContentAsync(message, "AdminConsole.CannotDeleteClaimedAccount", model); + message.Category = "CannotDeleteClaimedAccount"; await _mailDeliveryService.SendEmailAsync(message); } @@ -474,7 +474,7 @@ public class HandlebarsMailService : IMailService await _mailDeliveryService.SendEmailAsync(message); } - public async Task SendClaimedDomainUserEmailAsync(ManagedUserDomainClaimedEmails emailList) + public async Task SendClaimedDomainUserEmailAsync(ClaimedUserDomainClaimedEmails emailList) { await EnqueueMailAsync(emailList.EmailList.Select(email => CreateMessage(email, emailList.Organization))); @@ -804,12 +804,10 @@ public class HandlebarsMailService : IMailService return; } - var numeric = parameters[0]; - var singularText = parameters[1].ToString(); - var pluralText = parameters[2].ToString(); - - if (numeric is int number) + if (int.TryParse(parameters[0].ToString(), out var number)) { + var singularText = parameters[1].ToString(); + var pluralText = parameters[2].ToString(); writer.WriteSafeString(number == 1 ? singularText : pluralText); } else diff --git a/src/Core/Services/Implementations/UserService.cs b/src/Core/Services/Implementations/UserService.cs index 5076c8282e..de0fa427ba 100644 --- a/src/Core/Services/Implementations/UserService.cs +++ b/src/Core/Services/Implementations/UserService.cs @@ -314,9 +314,9 @@ public class UserService : UserManager, IUserService, IDisposable return; } - if (await IsManagedByAnyOrganizationAsync(user.Id)) + if (await IsClaimedByAnyOrganizationAsync(user.Id)) { - await _mailService.SendCannotDeleteManagedAccountEmailAsync(user.Email); + await _mailService.SendCannotDeleteClaimedAccountEmailAsync(user.Email); return; } @@ -545,11 +545,11 @@ public class UserService : UserManager, IUserService, IDisposable return IdentityResult.Failed(_identityErrorDescriber.PasswordMismatch()); } - var managedUserValidationResult = await ValidateManagedUserDomainAsync(user, newEmail); + var claimedUserValidationResult = await ValidateClaimedUserDomainAsync(user, newEmail); - if (!managedUserValidationResult.Succeeded) + if (!claimedUserValidationResult.Succeeded) { - return managedUserValidationResult; + return claimedUserValidationResult; } if (!await base.VerifyUserTokenAsync(user, _identityOptions.Tokens.ChangeEmailTokenProvider, @@ -617,18 +617,18 @@ public class UserService : UserManager, IUserService, IDisposable return IdentityResult.Success; } - public async Task ValidateManagedUserDomainAsync(User user, string newEmail) + public async Task ValidateClaimedUserDomainAsync(User user, string newEmail) { - var managingOrganizations = await GetOrganizationsManagingUserAsync(user.Id); + var claimingOrganization = await GetOrganizationsClaimingUserAsync(user.Id); - if (!managingOrganizations.Any()) + if (!claimingOrganization.Any()) { return IdentityResult.Success; } var newDomain = CoreHelpers.GetEmailDomain(newEmail); - var verifiedDomains = await _organizationDomainRepository.GetVerifiedDomainsByOrganizationIdsAsync(managingOrganizations.Select(org => org.Id)); + var verifiedDomains = await _organizationDomainRepository.GetVerifiedDomainsByOrganizationIdsAsync(claimingOrganization.Select(org => org.Id)); if (verifiedDomains.Any(verifiedDomain => verifiedDomain.DomainName == newDomain)) { @@ -1366,13 +1366,13 @@ public class UserService : UserManager, IUserService, IDisposable return IsLegacyUser(user); } - public async Task IsManagedByAnyOrganizationAsync(Guid userId) + public async Task IsClaimedByAnyOrganizationAsync(Guid userId) { - var managingOrganizations = await GetOrganizationsManagingUserAsync(userId); - return managingOrganizations.Any(); + var organizationsClaimingUser = await GetOrganizationsClaimingUserAsync(userId); + return organizationsClaimingUser.Any(); } - public async Task> GetOrganizationsManagingUserAsync(Guid userId) + public async Task> GetOrganizationsClaimingUserAsync(Guid userId) { if (!_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)) { diff --git a/src/Core/Services/NoopImplementations/NoopMailService.cs b/src/Core/Services/NoopImplementations/NoopMailService.cs index d829fbbacb..f6b27b0670 100644 --- a/src/Core/Services/NoopImplementations/NoopMailService.cs +++ b/src/Core/Services/NoopImplementations/NoopMailService.cs @@ -103,7 +103,7 @@ public class NoopMailService : IMailService return Task.FromResult(0); } - public Task SendCannotDeleteManagedAccountEmailAsync(string email) + public Task SendCannotDeleteClaimedAccountEmailAsync(string email) { return Task.FromResult(0); } @@ -317,7 +317,7 @@ public class NoopMailService : IMailService { return Task.FromResult(0); } - public Task SendClaimedDomainUserEmailAsync(ManagedUserDomainClaimedEmails emailList) => Task.CompletedTask; + public Task SendClaimedDomainUserEmailAsync(ClaimedUserDomainClaimedEmails emailList) => Task.CompletedTask; public Task SendDeviceApprovalRequestedNotificationEmailAsync(IEnumerable adminEmails, Guid organizationId, string email, string userName) { diff --git a/src/Core/Utilities/EncryptedStringAttribute.cs b/src/Core/Utilities/EncryptedStringAttribute.cs index 1fe06b4f58..9c59287df6 100644 --- a/src/Core/Utilities/EncryptedStringAttribute.cs +++ b/src/Core/Utilities/EncryptedStringAttribute.cs @@ -16,6 +16,7 @@ public class EncryptedStringAttribute : ValidationAttribute [EncryptionType.AesCbc256_B64] = 2, // iv|ct [EncryptionType.AesCbc128_HmacSha256_B64] = 3, // iv|ct|mac [EncryptionType.AesCbc256_HmacSha256_B64] = 3, // iv|ct|mac + [EncryptionType.XChaCha20Poly1305_B64] = 1, // cose bytes [EncryptionType.Rsa2048_OaepSha256_B64] = 1, // rsaCt [EncryptionType.Rsa2048_OaepSha1_B64] = 1, // rsaCt [EncryptionType.Rsa2048_OaepSha256_HmacSha256_B64] = 2, // rsaCt|mac diff --git a/src/Identity/Controllers/AccountsController.cs b/src/Identity/Controllers/AccountsController.cs index c840a7ddc5..9360da586c 100644 --- a/src/Identity/Controllers/AccountsController.cs +++ b/src/Identity/Controllers/AccountsController.cs @@ -121,8 +121,7 @@ public class AccountsController : Controller var user = model.ToUser(); var identityResult = await _registerUserCommand.RegisterUserViaOrganizationInviteToken(user, model.MasterPasswordHash, model.Token, model.OrganizationUserId); - // delaysEnabled false is only for the new registration with email verification process - return await ProcessRegistrationResult(identityResult, user, delaysEnabled: true); + return ProcessRegistrationResult(identityResult, user); } [HttpPost("register/send-verification-email")] @@ -188,7 +187,6 @@ public class AccountsController : Controller // Users will either have an emailed token or an email verification token - not both. IdentityResult identityResult = null; - var delaysEnabled = !_featureService.IsEnabled(FeatureFlagKeys.EmailVerificationDisableTimingDelays); switch (model.GetTokenType()) { @@ -197,32 +195,32 @@ public class AccountsController : Controller await _registerUserCommand.RegisterUserViaEmailVerificationToken(user, model.MasterPasswordHash, model.EmailVerificationToken); - return await ProcessRegistrationResult(identityResult, user, delaysEnabled); + return ProcessRegistrationResult(identityResult, user); break; case RegisterFinishTokenType.OrganizationInvite: identityResult = await _registerUserCommand.RegisterUserViaOrganizationInviteToken(user, model.MasterPasswordHash, model.OrgInviteToken, model.OrganizationUserId); - return await ProcessRegistrationResult(identityResult, user, delaysEnabled); + return ProcessRegistrationResult(identityResult, user); break; case RegisterFinishTokenType.OrgSponsoredFreeFamilyPlan: identityResult = await _registerUserCommand.RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken(user, model.MasterPasswordHash, model.OrgSponsoredFreeFamilyPlanToken); - return await ProcessRegistrationResult(identityResult, user, delaysEnabled); + return ProcessRegistrationResult(identityResult, user); break; case RegisterFinishTokenType.EmergencyAccessInvite: Debug.Assert(model.AcceptEmergencyAccessId.HasValue); identityResult = await _registerUserCommand.RegisterUserViaAcceptEmergencyAccessInviteToken(user, model.MasterPasswordHash, model.AcceptEmergencyAccessInviteToken, model.AcceptEmergencyAccessId.Value); - return await ProcessRegistrationResult(identityResult, user, delaysEnabled); + return ProcessRegistrationResult(identityResult, user); break; case RegisterFinishTokenType.ProviderInvite: Debug.Assert(model.ProviderUserId.HasValue); identityResult = await _registerUserCommand.RegisterUserViaProviderInviteToken(user, model.MasterPasswordHash, model.ProviderInviteToken, model.ProviderUserId.Value); - return await ProcessRegistrationResult(identityResult, user, delaysEnabled); + return ProcessRegistrationResult(identityResult, user); break; default: @@ -230,7 +228,7 @@ public class AccountsController : Controller } } - private async Task ProcessRegistrationResult(IdentityResult result, User user, bool delaysEnabled) + private RegisterResponseModel ProcessRegistrationResult(IdentityResult result, User user) { if (result.Succeeded) { @@ -243,10 +241,6 @@ public class AccountsController : Controller ModelState.AddModelError(string.Empty, error.Description); } - if (delaysEnabled) - { - await Task.Delay(Random.Shared.Next(100, 130)); - } throw new BadRequestException(ModelState); } diff --git a/test/Api.Test/AdminConsole/Controllers/OrganizationUsersControllerTests.cs b/test/Api.Test/AdminConsole/Controllers/OrganizationUsersControllerTests.cs index a19560ecee..107b9cdfb1 100644 --- a/test/Api.Test/AdminConsole/Controllers/OrganizationUsersControllerTests.cs +++ b/test/Api.Test/AdminConsole/Controllers/OrganizationUsersControllerTests.cs @@ -260,14 +260,15 @@ public class OrganizationUsersControllerTests .GetDetailsByIdWithCollectionsAsync(organizationUser.Id) .Returns((organizationUser, collections)); - sutProvider.GetDependency() - .GetUsersOrganizationManagementStatusAsync(organizationUser.OrganizationId, Arg.Is>(ids => ids.Contains(organizationUser.Id))) + sutProvider.GetDependency() + .GetUsersOrganizationClaimedStatusAsync(organizationUser.OrganizationId, Arg.Is>(ids => ids.Contains(organizationUser.Id))) .Returns(new Dictionary { { organizationUser.Id, true } }); var response = await sutProvider.Sut.Get(organizationUser.Id, false); Assert.Equal(organizationUser.Id, response.Id); Assert.Equal(accountDeprovisioningEnabled, response.ManagedByOrganization); + Assert.Equal(accountDeprovisioningEnabled, response.ClaimedByOrganization); } [Theory] @@ -331,7 +332,7 @@ public class OrganizationUsersControllerTests await sutProvider.Sut.DeleteAccount(orgId, id); - await sutProvider.GetDependency() + await sutProvider.GetDependency() .Received(1) .DeleteUserAsync(orgId, id, currentUser.Id); } @@ -367,7 +368,7 @@ public class OrganizationUsersControllerTests { sutProvider.GetDependency().ManageUsers(orgId).Returns(true); sutProvider.GetDependency().GetUserByPrincipalAsync(default).ReturnsForAnyArgs(currentUser); - sutProvider.GetDependency() + sutProvider.GetDependency() .DeleteManyUsersAsync(orgId, model.Ids, currentUser.Id) .Returns(deleteResults); @@ -375,7 +376,7 @@ public class OrganizationUsersControllerTests Assert.Equal(deleteResults.Count, response.Data.Count()); Assert.True(response.Data.All(r => deleteResults.Any(res => res.Item1 == r.Id && res.Item2 == r.Error))); - await sutProvider.GetDependency() + await sutProvider.GetDependency() .Received(1) .DeleteManyUsersAsync(orgId, model.Ids, currentUser.Id); } diff --git a/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs b/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs index 8e6d2ce27b..3c06c78392 100644 --- a/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs +++ b/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs @@ -138,7 +138,7 @@ public class OrganizationsControllerTests : IDisposable _ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig); _userService.GetUserByPrincipalAsync(Arg.Any()).Returns(user); _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true); - _userService.GetOrganizationsManagingUserAsync(user.Id).Returns(new List { null }); + _userService.GetOrganizationsClaimingUserAsync(user.Id).Returns(new List { null }); var exception = await Assert.ThrowsAsync(() => _sut.Leave(orgId)); Assert.Contains("Your organization's Single Sign-On settings prevent you from leaving.", @@ -168,10 +168,10 @@ public class OrganizationsControllerTests : IDisposable _ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig); _userService.GetUserByPrincipalAsync(Arg.Any()).Returns(user); _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true); - _userService.GetOrganizationsManagingUserAsync(user.Id).Returns(new List { { foundOrg } }); + _userService.GetOrganizationsClaimingUserAsync(user.Id).Returns(new List { { foundOrg } }); var exception = await Assert.ThrowsAsync(() => _sut.Leave(orgId)); - Assert.Contains("Managed user account cannot leave managing organization. Contact your organization administrator for additional details.", + Assert.Contains("Claimed user account cannot leave claiming organization. Contact your organization administrator for additional details.", exception.Message); await _removeOrganizationUserCommand.DidNotReceiveWithAnyArgs().RemoveUserAsync(default, default); @@ -203,7 +203,7 @@ public class OrganizationsControllerTests : IDisposable _ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig); _userService.GetUserByPrincipalAsync(Arg.Any()).Returns(user); _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true); - _userService.GetOrganizationsManagingUserAsync(user.Id).Returns(new List()); + _userService.GetOrganizationsClaimingUserAsync(user.Id).Returns(new List()); await _sut.Leave(orgId); diff --git a/test/Api.Test/AdminConsole/Public/Models/Response/MemberResponseModelTests.cs b/test/Api.Test/AdminConsole/Public/Models/Response/MemberResponseModelTests.cs index a9193258b8..468e7850fb 100644 --- a/test/Api.Test/AdminConsole/Public/Models/Response/MemberResponseModelTests.cs +++ b/test/Api.Test/AdminConsole/Public/Models/Response/MemberResponseModelTests.cs @@ -25,11 +25,16 @@ public class MemberResponseModelTests Assert.True(sut.ResetPasswordEnrolled); } - [Fact] - public void ResetPasswordEnrolled_ShouldBeFalse_WhenUserDoesNotHaveResetPasswordKey() + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void ResetPasswordEnrolled_ShouldBeFalse_WhenResetPasswordKeyIsInvalid(string? resetPasswordKey) { // Arrange var user = Substitute.For(); + user.ResetPasswordKey = resetPasswordKey; + var collections = Substitute.For>(); // Act diff --git a/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs b/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs index 15c7573aca..bd22fd9346 100644 --- a/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs +++ b/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs @@ -120,7 +120,7 @@ public class AccountsControllerTests : IDisposable ConfigureUserServiceToReturnValidPrincipalFor(user); ConfigureUserServiceToAcceptPasswordFor(user); const string newEmail = "example@user.com"; - _userService.ValidateManagedUserDomainAsync(user, newEmail).Returns(IdentityResult.Success); + _userService.ValidateClaimedUserDomainAsync(user, newEmail).Returns(IdentityResult.Success); // Act await _sut.PostEmailToken(new EmailTokenRequestModel { NewEmail = newEmail }); @@ -130,7 +130,7 @@ public class AccountsControllerTests : IDisposable } [Fact] - public async Task PostEmailToken_WhenValidateManagedUserDomainAsyncFails_ShouldReturnError() + public async Task PostEmailToken_WhenValidateClaimedUserDomainAsyncFails_ShouldReturnError() { // Arrange var user = GenerateExampleUser(); @@ -139,7 +139,7 @@ public class AccountsControllerTests : IDisposable const string newEmail = "example@user.com"; - _userService.ValidateManagedUserDomainAsync(user, newEmail) + _userService.ValidateClaimedUserDomainAsync(user, newEmail) .Returns(IdentityResult.Failed(new IdentityError { Code = "TestFailure", @@ -197,7 +197,7 @@ public class AccountsControllerTests : IDisposable _userService.ChangeEmailAsync(user, default, default, default, default, default) .Returns(Task.FromResult(IdentityResult.Success)); _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true); - _userService.IsManagedByAnyOrganizationAsync(user.Id).Returns(false); + _userService.IsClaimedByAnyOrganizationAsync(user.Id).Returns(false); await _sut.PostEmail(new EmailRequestModel()); @@ -539,7 +539,7 @@ public class AccountsControllerTests : IDisposable ConfigureUserServiceToReturnValidPrincipalFor(user); ConfigureUserServiceToAcceptPasswordFor(user); _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true); - _userService.IsManagedByAnyOrganizationAsync(user.Id).Returns(true); + _userService.IsClaimedByAnyOrganizationAsync(user.Id).Returns(true); var result = await Assert.ThrowsAsync(() => _sut.Delete(new SecretVerificationRequestModel())); @@ -553,7 +553,7 @@ public class AccountsControllerTests : IDisposable ConfigureUserServiceToReturnValidPrincipalFor(user); ConfigureUserServiceToAcceptPasswordFor(user); _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true); - _userService.IsManagedByAnyOrganizationAsync(user.Id).Returns(false); + _userService.IsClaimedByAnyOrganizationAsync(user.Id).Returns(false); _userService.DeleteAsync(user).Returns(IdentityResult.Success); await _sut.Delete(new SecretVerificationRequestModel()); diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs index 6c6d0e35f0..daa560f3bc 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationDomains/VerifyOrganizationDomainCommandTests.cs @@ -317,7 +317,7 @@ public class VerifyOrganizationDomainCommandTests _ = await sutProvider.Sut.UserVerifyOrganizationDomainAsync(domain); await sutProvider.GetDependency().Received().SendClaimedDomainUserEmailAsync( - Arg.Is(x => + Arg.Is(x => x.EmailList.Count(e => e.EndsWith(domain.DomainName)) == mockedUsers.Count && x.Organization.Id == organization.Id)); } diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteManagedOrganizationUserAccountCommandTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteClaimedOrganizationUserAccountCommandTests.cs similarity index 91% rename from test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteManagedOrganizationUserAccountCommandTests.cs rename to test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteClaimedOrganizationUserAccountCommandTests.cs index f8f6bdb60d..7f1b101d7a 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteManagedOrganizationUserAccountCommandTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteClaimedOrganizationUserAccountCommandTests.cs @@ -15,12 +15,12 @@ using Xunit; namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers; [SutProviderCustomize] -public class DeleteManagedOrganizationUserAccountCommandTests +public class DeleteClaimedOrganizationUserAccountCommandTests { [Theory] [BitAutoData] public async Task DeleteUserAsync_WithValidUser_DeletesUserAndLogsEvent( - SutProvider sutProvider, User user, Guid deletingUserId, + SutProvider sutProvider, User user, Guid deletingUserId, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser organizationUser) { // Arrange @@ -34,8 +34,8 @@ public class DeleteManagedOrganizationUserAccountCommandTests .GetByIdAsync(organizationUser.Id) .Returns(organizationUser); - sutProvider.GetDependency() - .GetUsersOrganizationManagementStatusAsync( + sutProvider.GetDependency() + .GetUsersOrganizationClaimedStatusAsync( organizationUser.OrganizationId, Arg.Is>(ids => ids.Contains(organizationUser.Id))) .Returns(new Dictionary { { organizationUser.Id, true } }); @@ -59,7 +59,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteUserAsync_WithUserNotFound_ThrowsException( - SutProvider sutProvider, + SutProvider sutProvider, Guid organizationId, Guid organizationUserId) { // Arrange @@ -81,7 +81,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteUserAsync_DeletingYourself_ThrowsException( - SutProvider sutProvider, + SutProvider sutProvider, User user, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser organizationUser, Guid deletingUserId) @@ -110,7 +110,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteUserAsync_WhenUserIsInvited_ThrowsException( - SutProvider sutProvider, + SutProvider sutProvider, [OrganizationUser(OrganizationUserStatusType.Invited, OrganizationUserType.User)] OrganizationUser organizationUser) { // Arrange @@ -134,7 +134,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteUserAsync_WhenCustomUserDeletesAdmin_ThrowsException( - SutProvider sutProvider, User user, + SutProvider sutProvider, User user, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Admin)] OrganizationUser organizationUser, Guid deletingUserId) { @@ -166,7 +166,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteUserAsync_DeletingOwnerWhenNotOwner_ThrowsException( - SutProvider sutProvider, User user, + SutProvider sutProvider, User user, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser organizationUser, Guid deletingUserId) { @@ -198,7 +198,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteUserAsync_DeletingLastConfirmedOwner_ThrowsException( - SutProvider sutProvider, User user, + SutProvider sutProvider, User user, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser organizationUser, Guid deletingUserId) { @@ -237,7 +237,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteUserAsync_WithUserNotManaged_ThrowsException( - SutProvider sutProvider, User user, + SutProvider sutProvider, User user, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser organizationUser) { // Arrange @@ -250,8 +250,8 @@ public class DeleteManagedOrganizationUserAccountCommandTests sutProvider.GetDependency().GetByIdAsync(user.Id) .Returns(user); - sutProvider.GetDependency() - .GetUsersOrganizationManagementStatusAsync(organizationUser.OrganizationId, Arg.Any>()) + sutProvider.GetDependency() + .GetUsersOrganizationClaimedStatusAsync(organizationUser.OrganizationId, Arg.Any>()) .Returns(new Dictionary { { organizationUser.Id, false } }); // Act @@ -259,7 +259,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, null)); // Assert - Assert.Equal("Member is not managed by the organization.", exception.Message); + Assert.Equal("Member is not claimed by the organization.", exception.Message); await sutProvider.GetDependency().Received(0).DeleteAsync(Arg.Any()); await sutProvider.GetDependency().Received(0) .LogOrganizationUserEventAsync(Arg.Any(), Arg.Any(), Arg.Any()); @@ -268,7 +268,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteManyUsersAsync_WithValidUsers_DeletesUsersAndLogsEvents( - SutProvider sutProvider, User user1, User user2, Guid organizationId, + SutProvider sutProvider, User user1, User user2, Guid organizationId, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser1, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser2) { @@ -285,8 +285,8 @@ public class DeleteManagedOrganizationUserAccountCommandTests .GetManyAsync(Arg.Is>(ids => ids.Contains(user1.Id) && ids.Contains(user2.Id))) .Returns(new[] { user1, user2 }); - sutProvider.GetDependency() - .GetUsersOrganizationManagementStatusAsync(organizationId, Arg.Any>()) + sutProvider.GetDependency() + .GetUsersOrganizationClaimedStatusAsync(organizationId, Arg.Any>()) .Returns(new Dictionary { { orgUser1.Id, true }, { orgUser2.Id, true } }); // Act @@ -308,7 +308,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteManyUsersAsync_WhenUserNotFound_ReturnsErrorMessage( - SutProvider sutProvider, + SutProvider sutProvider, Guid organizationId, Guid orgUserId) { @@ -329,7 +329,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteManyUsersAsync_WhenDeletingYourself_ReturnsErrorMessage( - SutProvider sutProvider, + SutProvider sutProvider, User user, [OrganizationUser] OrganizationUser orgUser, Guid deletingUserId) { // Arrange @@ -358,7 +358,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteManyUsersAsync_WhenUserIsInvited_ReturnsErrorMessage( - SutProvider sutProvider, + SutProvider sutProvider, [OrganizationUser(OrganizationUserStatusType.Invited, OrganizationUserType.User)] OrganizationUser orgUser) { // Arrange @@ -383,7 +383,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteManyUsersAsync_WhenDeletingOwnerAsNonOwner_ReturnsErrorMessage( - SutProvider sutProvider, User user, + SutProvider sutProvider, User user, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser orgUser, Guid deletingUserId) { @@ -415,7 +415,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteManyUsersAsync_WhenDeletingLastOwner_ReturnsErrorMessage( - SutProvider sutProvider, User user, + SutProvider sutProvider, User user, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser orgUser, Guid deletingUserId) { @@ -453,7 +453,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteManyUsersAsync_WhenUserNotManaged_ReturnsErrorMessage( - SutProvider sutProvider, User user, + SutProvider sutProvider, User user, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser) { // Arrange @@ -467,8 +467,8 @@ public class DeleteManagedOrganizationUserAccountCommandTests .GetManyAsync(Arg.Is>(ids => ids.Contains(orgUser.UserId.Value))) .Returns(new[] { user }); - sutProvider.GetDependency() - .GetUsersOrganizationManagementStatusAsync(Arg.Any(), Arg.Any>()) + sutProvider.GetDependency() + .GetUsersOrganizationClaimedStatusAsync(Arg.Any(), Arg.Any>()) .Returns(new Dictionary { { orgUser.Id, false } }); // Act @@ -477,7 +477,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests // Assert Assert.Single(result); Assert.Equal(orgUser.Id, result.First().Item1); - Assert.Contains("Member is not managed by the organization.", result.First().Item2); + Assert.Contains("Member is not claimed by the organization.", result.First().Item2); await sutProvider.GetDependency().Received(0).DeleteAsync(Arg.Any()); await sutProvider.GetDependency().Received(0) .LogOrganizationUserEventsAsync(Arg.Any>()); @@ -486,7 +486,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests [Theory] [BitAutoData] public async Task DeleteManyUsersAsync_MixedValidAndInvalidUsers_ReturnsAppropriateResults( - SutProvider sutProvider, User user1, User user3, + SutProvider sutProvider, User user1, User user3, Guid organizationId, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser1, [OrganizationUser(OrganizationUserStatusType.Invited, OrganizationUserType.User)] OrganizationUser orgUser2, @@ -506,8 +506,8 @@ public class DeleteManagedOrganizationUserAccountCommandTests .GetManyAsync(Arg.Is>(ids => ids.Contains(user1.Id) && ids.Contains(user3.Id))) .Returns(new[] { user1, user3 }); - sutProvider.GetDependency() - .GetUsersOrganizationManagementStatusAsync(organizationId, Arg.Any>()) + sutProvider.GetDependency() + .GetUsersOrganizationClaimedStatusAsync(organizationId, Arg.Any>()) .Returns(new Dictionary { { orgUser1.Id, true }, { orgUser3.Id, false } }); // Act @@ -517,7 +517,7 @@ public class DeleteManagedOrganizationUserAccountCommandTests Assert.Equal(3, results.Count()); Assert.Empty(results.First(r => r.Item1 == orgUser1.Id).Item2); Assert.Equal("You cannot delete a member with Invited status.", results.First(r => r.Item1 == orgUser2.Id).Item2); - Assert.Equal("Member is not managed by the organization.", results.First(r => r.Item1 == orgUser3.Id).Item2); + Assert.Equal("Member is not claimed by the organization.", results.First(r => r.Item1 == orgUser3.Id).Item2); await sutProvider.GetDependency().Received(1).LogOrganizationUserEventsAsync( Arg.Is>(events => diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersManagementStatusQueryTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersClaimedStatusQueryTests.cs similarity index 80% rename from test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersManagementStatusQueryTests.cs rename to test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersClaimedStatusQueryTests.cs index dda9867fd2..fd6d827791 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersManagementStatusQueryTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/GetOrganizationUsersClaimedStatusQueryTests.cs @@ -12,14 +12,14 @@ using Xunit; namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers; [SutProviderCustomize] -public class GetOrganizationUsersManagementStatusQueryTests +public class GetOrganizationUsersClaimedStatusQueryTests { [Theory, BitAutoData] public async Task GetUsersOrganizationManagementStatusAsync_WithNoUsers_ReturnsEmpty( Organization organization, - SutProvider sutProvider) + SutProvider sutProvider) { - var result = await sutProvider.Sut.GetUsersOrganizationManagementStatusAsync(organization.Id, new List()); + var result = await sutProvider.Sut.GetUsersOrganizationClaimedStatusAsync(organization.Id, new List()); Assert.Empty(result); } @@ -28,7 +28,7 @@ public class GetOrganizationUsersManagementStatusQueryTests public async Task GetUsersOrganizationManagementStatusAsync_WithUseSsoEnabled_Success( Organization organization, ICollection usersWithClaimedDomain, - SutProvider sutProvider) + SutProvider sutProvider) { organization.Enabled = true; organization.UseSso = true; @@ -44,7 +44,7 @@ public class GetOrganizationUsersManagementStatusQueryTests .GetManyByOrganizationWithClaimedDomainsAsync(organization.Id) .Returns(usersWithClaimedDomain); - var result = await sutProvider.Sut.GetUsersOrganizationManagementStatusAsync(organization.Id, userIdsToCheck); + var result = await sutProvider.Sut.GetUsersOrganizationClaimedStatusAsync(organization.Id, userIdsToCheck); Assert.All(usersWithClaimedDomain, ou => Assert.True(result[ou.Id])); Assert.False(result[userIdWithoutClaimedDomain]); @@ -54,7 +54,7 @@ public class GetOrganizationUsersManagementStatusQueryTests public async Task GetUsersOrganizationManagementStatusAsync_WithUseSsoDisabled_ReturnsAllFalse( Organization organization, ICollection usersWithClaimedDomain, - SutProvider sutProvider) + SutProvider sutProvider) { organization.Enabled = true; organization.UseSso = false; @@ -70,7 +70,7 @@ public class GetOrganizationUsersManagementStatusQueryTests .GetManyByOrganizationWithClaimedDomainsAsync(organization.Id) .Returns(usersWithClaimedDomain); - var result = await sutProvider.Sut.GetUsersOrganizationManagementStatusAsync(organization.Id, userIdsToCheck); + var result = await sutProvider.Sut.GetUsersOrganizationClaimedStatusAsync(organization.Id, userIdsToCheck); Assert.All(result, r => Assert.False(r.Value)); } @@ -79,7 +79,7 @@ public class GetOrganizationUsersManagementStatusQueryTests public async Task GetUsersOrganizationManagementStatusAsync_WithDisabledOrganization_ReturnsAllFalse( Organization organization, ICollection usersWithClaimedDomain, - SutProvider sutProvider) + SutProvider sutProvider) { organization.Enabled = false; @@ -94,7 +94,7 @@ public class GetOrganizationUsersManagementStatusQueryTests .GetManyByOrganizationWithClaimedDomainsAsync(organization.Id) .Returns(usersWithClaimedDomain); - var result = await sutProvider.Sut.GetUsersOrganizationManagementStatusAsync(organization.Id, userIdsToCheck); + var result = await sutProvider.Sut.GetUsersOrganizationClaimedStatusAsync(organization.Id, userIdsToCheck); Assert.All(result, r => Assert.False(r.Value)); } diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/RemoveOrganizationUserCommandTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/RemoveOrganizationUserCommandTests.cs index a60850c5a9..3578706e47 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/RemoveOrganizationUserCommandTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/RemoveOrganizationUserCommandTests.cs @@ -41,9 +41,9 @@ public class RemoveOrganizationUserCommandTests await sutProvider.Sut.RemoveUserAsync(deletingUser.OrganizationId, organizationUser.Id, deletingUser.UserId); // Assert - await sutProvider.GetDependency() + await sutProvider.GetDependency() .DidNotReceiveWithAnyArgs() - .GetUsersOrganizationManagementStatusAsync(default, default); + .GetUsersOrganizationClaimedStatusAsync(default, default); await sutProvider.GetDependency() .Received(1) .DeleteAsync(organizationUser); @@ -78,9 +78,9 @@ public class RemoveOrganizationUserCommandTests await sutProvider.Sut.RemoveUserAsync(deletingUser.OrganizationId, organizationUser.Id, deletingUser.UserId); // Assert - await sutProvider.GetDependency() + await sutProvider.GetDependency() .Received(1) - .GetUsersOrganizationManagementStatusAsync( + .GetUsersOrganizationClaimedStatusAsync( organizationUser.OrganizationId, Arg.Is>(i => i.Contains(organizationUser.Id))); await sutProvider.GetDependency() @@ -247,17 +247,17 @@ public class RemoveOrganizationUserCommandTests sutProvider.GetDependency() .GetByIdAsync(orgUser.Id) .Returns(orgUser); - sutProvider.GetDependency() - .GetUsersOrganizationManagementStatusAsync(orgUser.OrganizationId, Arg.Is>(i => i.Contains(orgUser.Id))) + sutProvider.GetDependency() + .GetUsersOrganizationClaimedStatusAsync(orgUser.OrganizationId, Arg.Is>(i => i.Contains(orgUser.Id))) .Returns(new Dictionary { { orgUser.Id, true } }); // Act & Assert var exception = await Assert.ThrowsAsync( () => sutProvider.Sut.RemoveUserAsync(orgUser.OrganizationId, orgUser.Id, deletingUserId)); Assert.Contains(RemoveOrganizationUserCommand.RemoveClaimedAccountErrorMessage, exception.Message); - await sutProvider.GetDependency() + await sutProvider.GetDependency() .Received(1) - .GetUsersOrganizationManagementStatusAsync(orgUser.OrganizationId, Arg.Is>(i => i.Contains(orgUser.Id))); + .GetUsersOrganizationClaimedStatusAsync(orgUser.OrganizationId, Arg.Is>(i => i.Contains(orgUser.Id))); } [Theory, BitAutoData] @@ -274,9 +274,9 @@ public class RemoveOrganizationUserCommandTests await sutProvider.Sut.RemoveUserAsync(organizationUser.OrganizationId, organizationUser.Id, eventSystemUser); // Assert - await sutProvider.GetDependency() + await sutProvider.GetDependency() .DidNotReceiveWithAnyArgs() - .GetUsersOrganizationManagementStatusAsync(default, default); + .GetUsersOrganizationClaimedStatusAsync(default, default); await sutProvider.GetDependency() .Received(1) .DeleteAsync(organizationUser); @@ -302,9 +302,9 @@ public class RemoveOrganizationUserCommandTests await sutProvider.Sut.RemoveUserAsync(organizationUser.OrganizationId, organizationUser.Id, eventSystemUser); // Assert - await sutProvider.GetDependency() + await sutProvider.GetDependency() .DidNotReceiveWithAnyArgs() - .GetUsersOrganizationManagementStatusAsync(default, default); + .GetUsersOrganizationClaimedStatusAsync(default, default); await sutProvider.GetDependency() .Received(1) .DeleteAsync(organizationUser); @@ -490,8 +490,8 @@ public class RemoveOrganizationUserCommandTests sutProvider.GetDependency() .OrganizationOwner(deletingUser.OrganizationId) .Returns(true); - sutProvider.GetDependency() - .GetUsersOrganizationManagementStatusAsync( + sutProvider.GetDependency() + .GetUsersOrganizationClaimedStatusAsync( deletingUser.OrganizationId, Arg.Is>(i => i.Contains(orgUser1.Id) && i.Contains(orgUser2.Id))) .Returns(new Dictionary { { orgUser1.Id, false }, { orgUser2.Id, false } }); @@ -502,9 +502,9 @@ public class RemoveOrganizationUserCommandTests // Assert Assert.Equal(2, result.Count()); Assert.All(result, r => Assert.Empty(r.ErrorMessage)); - await sutProvider.GetDependency() + await sutProvider.GetDependency() .DidNotReceiveWithAnyArgs() - .GetUsersOrganizationManagementStatusAsync(default, default); + .GetUsersOrganizationClaimedStatusAsync(default, default); await sutProvider.GetDependency() .Received(1) .DeleteManyAsync(Arg.Is>(i => i.Contains(orgUser1.Id) && i.Contains(orgUser2.Id))); @@ -544,8 +544,8 @@ public class RemoveOrganizationUserCommandTests sutProvider.GetDependency() .OrganizationOwner(deletingUser.OrganizationId) .Returns(true); - sutProvider.GetDependency() - .GetUsersOrganizationManagementStatusAsync( + sutProvider.GetDependency() + .GetUsersOrganizationClaimedStatusAsync( deletingUser.OrganizationId, Arg.Is>(i => i.Contains(orgUser1.Id) && i.Contains(orgUser2.Id))) .Returns(new Dictionary { { orgUser1.Id, false }, { orgUser2.Id, false } }); @@ -556,9 +556,9 @@ public class RemoveOrganizationUserCommandTests // Assert Assert.Equal(2, result.Count()); Assert.All(result, r => Assert.Empty(r.ErrorMessage)); - await sutProvider.GetDependency() + await sutProvider.GetDependency() .Received(1) - .GetUsersOrganizationManagementStatusAsync( + .GetUsersOrganizationClaimedStatusAsync( deletingUser.OrganizationId, Arg.Is>(i => i.Contains(orgUser1.Id) && i.Contains(orgUser2.Id))); await sutProvider.GetDependency() @@ -638,7 +638,7 @@ public class RemoveOrganizationUserCommandTests } [Theory, BitAutoData] - public async Task RemoveUsers_WithDeletingUserId_RemovingManagedUser_WithAccountDeprovisioningEnabled_ThrowsException( + public async Task RemoveUsers_WithDeletingUserId_RemovingClaimedUser_WithAccountDeprovisioningEnabled_ThrowsException( [OrganizationUser(status: OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser, OrganizationUser deletingUser, SutProvider sutProvider) @@ -658,8 +658,8 @@ public class RemoveOrganizationUserCommandTests .HasConfirmedOwnersExceptAsync(orgUser.OrganizationId, Arg.Any>()) .Returns(true); - sutProvider.GetDependency() - .GetUsersOrganizationManagementStatusAsync(orgUser.OrganizationId, Arg.Is>(i => i.Contains(orgUser.Id))) + sutProvider.GetDependency() + .GetUsersOrganizationClaimedStatusAsync(orgUser.OrganizationId, Arg.Is>(i => i.Contains(orgUser.Id))) .Returns(new Dictionary { { orgUser.Id, true } }); // Act @@ -723,9 +723,9 @@ public class RemoveOrganizationUserCommandTests // Assert Assert.Equal(2, result.Count()); Assert.All(result, r => Assert.Empty(r.ErrorMessage)); - await sutProvider.GetDependency() + await sutProvider.GetDependency() .DidNotReceiveWithAnyArgs() - .GetUsersOrganizationManagementStatusAsync(default, default); + .GetUsersOrganizationClaimedStatusAsync(default, default); await sutProvider.GetDependency() .Received(1) .DeleteManyAsync(Arg.Is>(i => i.Contains(orgUser1.Id) && i.Contains(orgUser2.Id))); @@ -768,9 +768,9 @@ public class RemoveOrganizationUserCommandTests // Assert Assert.Equal(2, result.Count()); Assert.All(result, r => Assert.Empty(r.ErrorMessage)); - await sutProvider.GetDependency() + await sutProvider.GetDependency() .DidNotReceiveWithAnyArgs() - .GetUsersOrganizationManagementStatusAsync(default, default); + .GetUsersOrganizationClaimedStatusAsync(default, default); await sutProvider.GetDependency() .Received(1) .DeleteManyAsync(Arg.Is>(i => i.Contains(orgUser1.Id) && i.Contains(orgUser2.Id))); diff --git a/test/Core.Test/Platform/X509ChainCustomization/X509ChainCustomizationServiceCollectionExtensionsTests.cs b/test/Core.Test/Platform/X509ChainCustomization/X509ChainCustomizationServiceCollectionExtensionsTests.cs index 2a4ed55489..cec8a2a39d 100644 --- a/test/Core.Test/Platform/X509ChainCustomization/X509ChainCustomizationServiceCollectionExtensionsTests.cs +++ b/test/Core.Test/Platform/X509ChainCustomization/X509ChainCustomizationServiceCollectionExtensionsTests.cs @@ -257,6 +257,41 @@ public class X509ChainCustomizationServiceCollectionExtensionsTests Assert.Equal("Hi", response); } + [Fact] + public async Task CallHttp_ReachingOutToServerTrustedThroughSystemCA() + { + var services = CreateServices((gs, environment, config) => { }, services => + { + services.Configure(options => + { + options.AdditionalCustomTrustCertificates = []; + }); + }); + + var httpClient = services.GetRequiredService().CreateClient(); + + var response = await httpClient.GetAsync("https://example.com"); + response.EnsureSuccessStatusCode(); + } + + [Fact] + public async Task CallHttpWithCustomTrustForSelfSigned_ReachingOutToServerTrustedThroughSystemCA() + { + var selfSignedCertificate = CreateSelfSignedCert("localhost"); + var services = CreateServices((gs, environment, config) => { }, services => + { + services.Configure(options => + { + options.AdditionalCustomTrustCertificates = [selfSignedCertificate]; + }); + }); + + var httpClient = services.GetRequiredService().CreateClient(); + + var response = await httpClient.GetAsync("https://example.com"); + response.EnsureSuccessStatusCode(); + } + private static async Task CreateServerAsync(int port, Action configure) { var builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions()); diff --git a/test/Core.Test/Services/UserServiceTests.cs b/test/Core.Test/Services/UserServiceTests.cs index 3158c1595c..02ff24d9bf 100644 --- a/test/Core.Test/Services/UserServiceTests.cs +++ b/test/Core.Test/Services/UserServiceTests.cs @@ -341,19 +341,19 @@ public class UserServiceTests } [Theory, BitAutoData] - public async Task IsManagedByAnyOrganizationAsync_WithAccountDeprovisioningDisabled_ReturnsFalse( + public async Task IsClaimedByAnyOrganizationAsync_WithAccountDeprovisioningDisabled_ReturnsFalse( SutProvider sutProvider, Guid userId) { sutProvider.GetDependency() .IsEnabled(FeatureFlagKeys.AccountDeprovisioning) .Returns(false); - var result = await sutProvider.Sut.IsManagedByAnyOrganizationAsync(userId); + var result = await sutProvider.Sut.IsClaimedByAnyOrganizationAsync(userId); Assert.False(result); } [Theory, BitAutoData] - public async Task IsManagedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithManagingEnabledOrganization_ReturnsTrue( + public async Task IsClaimedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithManagingEnabledOrganization_ReturnsTrue( SutProvider sutProvider, Guid userId, Organization organization) { organization.Enabled = true; @@ -367,12 +367,12 @@ public class UserServiceTests .GetByVerifiedUserEmailDomainAsync(userId) .Returns(new[] { organization }); - var result = await sutProvider.Sut.IsManagedByAnyOrganizationAsync(userId); + var result = await sutProvider.Sut.IsClaimedByAnyOrganizationAsync(userId); Assert.True(result); } [Theory, BitAutoData] - public async Task IsManagedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithManagingDisabledOrganization_ReturnsFalse( + public async Task IsClaimedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithManagingDisabledOrganization_ReturnsFalse( SutProvider sutProvider, Guid userId, Organization organization) { organization.Enabled = false; @@ -386,12 +386,12 @@ public class UserServiceTests .GetByVerifiedUserEmailDomainAsync(userId) .Returns(new[] { organization }); - var result = await sutProvider.Sut.IsManagedByAnyOrganizationAsync(userId); + var result = await sutProvider.Sut.IsClaimedByAnyOrganizationAsync(userId); Assert.False(result); } [Theory, BitAutoData] - public async Task IsManagedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithOrganizationUseSsoFalse_ReturnsFalse( + public async Task IsClaimedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithOrganizationUseSsoFalse_ReturnsFalse( SutProvider sutProvider, Guid userId, Organization organization) { organization.Enabled = true; @@ -405,7 +405,7 @@ public class UserServiceTests .GetByVerifiedUserEmailDomainAsync(userId) .Returns(new[] { organization }); - var result = await sutProvider.Sut.IsManagedByAnyOrganizationAsync(userId); + var result = await sutProvider.Sut.IsClaimedByAnyOrganizationAsync(userId); Assert.False(result); }