1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-11 21:03:47 -05:00

[PM-15420] Managed to Claimed (#5594)

* Renamed ManagedUserDomainClaimedEmails to ClaimedUserDomainClaimedEmails

* Renamed method to improve clarity and consistency.

Replaced `ValidateManagedUserDomainAsync` with `ValidateClaimedUserDomainAsync`.

* Rename `GetOrganizationsManagingUserAsync` to `GetOrganizationsClaimingUserAsync`.

This renaming clarifies the function's purpose, aligning its name with the concept of "claiming" rather than "managing" user associations.

* Refactor variable naming in ValidateClaimedUserDomainAsync

* Managed to claimed

* Managed to claimed

* Managed to claimed

* Managing to Claiming

* Managing to Claiming

* Managing to Claiming

* Managing to Claiming

* Renamed DeleteManagedOrganizationUserAccountCommand to DeleteClaimedOrganizationUserAccountCommand

* Renamed IDeleteManagedOrganizationUserAccountCommand to IDeleteClaimedOrganizationUserAccountCommand

* Updated variable name

* IsManagedBy to IsClaimedBy

* Created new property. obsoleted old property and wired up for backward compatibility.

* More Managed to Claimed renames.

* Managed to Claimed

* Fixing tests... 🤦

* Got the rest of em

* missed the test 🤦

* fixed test.
This commit is contained in:
Jared McCannon
2025-04-08 14:38:44 -05:00
committed by GitHub
parent f5f8d37d72
commit dcd62f00ba
36 changed files with 245 additions and 222 deletions

View File

@ -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<OrganizationUserBulkResponseModel>(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<IDictionary<Guid, bool>> GetManagedByOrganizationStatusAsync(Guid orgId, IEnumerable<Guid> userIds)
private async Task<IDictionary<Guid, bool>> GetClaimedByOrganizationStatusAsync(Guid orgId, IEnumerable<Guid> 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;
}
}

View File

@ -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<ProfileOrganizationResponseModel>(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);

View File

@ -66,24 +66,30 @@ public class OrganizationUserDetailsResponseModel : OrganizationUserResponseMode
{
public OrganizationUserDetailsResponseModel(
OrganizationUser organizationUser,
bool managedByOrganization,
bool claimedByOrganization,
IEnumerable<CollectionAccessSelection> collections)
: base(organizationUser, "organizationUserDetails")
{
ManagedByOrganization = managedByOrganization;
ClaimedByOrganization = claimedByOrganization;
Collections = collections.Select(c => new SelectionReadOnlyResponseModel(c));
}
public OrganizationUserDetailsResponseModel(OrganizationUserUserDetails organizationUser,
bool managedByOrganization,
bool claimedByOrganization,
IEnumerable<CollectionAccessSelection> 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<SelectionReadOnlyResponseModel> 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;
}
/// <summary>
/// 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.
/// </summary>
public bool ManagedByOrganization { get; set; }
public bool ClaimedByOrganization { get; set; }
public IEnumerable<SelectionReadOnlyResponseModel> Collections { get; set; }
public IEnumerable<Guid> Groups { get; set; }
}

View File

@ -18,7 +18,7 @@ public class ProfileOrganizationResponseModel : ResponseModel
public ProfileOrganizationResponseModel(
OrganizationUserOrganizationDetails organization,
IEnumerable<Guid> organizationIdsManagingUser)
IEnumerable<Guid> organizationIdsClaimingUser)
: this("profileOrganization")
{
Id = organization.OrganizationId;
@ -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; }
/// <summary>
/// Indicates if the organization manages the user.
/// Obsolete.
///
/// See <see cref="UserIsClaimedByOrganization"/>
/// </summary>
[Obsolete("Please use UserIsClaimedByOrganization instead. This property will be removed in a future version.")]
public bool UserIsManagedByOrganization
{
get => UserIsClaimedByOrganization;
set => UserIsClaimedByOrganization = value;
}
/// <summary>
/// Indicates if the organization claims the user.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <returns>
/// False if the Account Deprovisioning feature flag is disabled.
/// </returns>
public bool UserIsManagedByOrganization { get; set; }
public bool UserIsClaimedByOrganization { get; set; }
public bool UseRiskInsights { get; set; }
}