mirror of
https://github.com/bitwarden/server.git
synced 2024-11-21 12:05:42 +01:00
[PM-11334] Add managed status to sync data (#4791)
* Refactor UserService to add GetOrganizationManagingUserAsync method to retrive the organization that manages a user * Refactor SyncController and AccountsController to include ManagedByOrganizationId in profile response
This commit is contained in:
parent
2e072aebe3
commit
3f629e0a5a
@ -443,10 +443,11 @@ public class AccountsController : Controller
|
|||||||
|
|
||||||
var twoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
var twoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
||||||
var hasPremiumFromOrg = await _userService.HasPremiumFromOrganization(user);
|
var hasPremiumFromOrg = await _userService.HasPremiumFromOrganization(user);
|
||||||
|
var managedByOrganizationId = await GetManagedByOrganizationIdAsync(user);
|
||||||
|
|
||||||
var response = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
|
var response = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
|
||||||
providerUserOrganizationDetails, twoFactorEnabled,
|
providerUserOrganizationDetails, twoFactorEnabled,
|
||||||
hasPremiumFromOrg);
|
hasPremiumFromOrg, managedByOrganizationId);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,7 +472,12 @@ public class AccountsController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _userService.SaveUserAsync(model.ToUser(user));
|
await _userService.SaveUserAsync(model.ToUser(user));
|
||||||
var response = new ProfileResponseModel(user, null, null, null, await _userService.TwoFactorIsEnabledAsync(user), await _userService.HasPremiumFromOrganization(user));
|
|
||||||
|
var twoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
||||||
|
var hasPremiumFromOrg = await _userService.HasPremiumFromOrganization(user);
|
||||||
|
var managedByOrganizationId = await GetManagedByOrganizationIdAsync(user);
|
||||||
|
|
||||||
|
var response = new ProfileResponseModel(user, null, null, null, twoFactorEnabled, hasPremiumFromOrg, managedByOrganizationId);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,7 +491,12 @@ public class AccountsController : Controller
|
|||||||
throw new UnauthorizedAccessException();
|
throw new UnauthorizedAccessException();
|
||||||
}
|
}
|
||||||
await _userService.SaveUserAsync(model.ToUser(user), true);
|
await _userService.SaveUserAsync(model.ToUser(user), true);
|
||||||
var response = new ProfileResponseModel(user, null, null, null, await _userService.TwoFactorIsEnabledAsync(user), await _userService.HasPremiumFromOrganization(user));
|
|
||||||
|
var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
||||||
|
var userHasPremiumFromOrganization = await _userService.HasPremiumFromOrganization(user);
|
||||||
|
var managedByOrganizationId = await GetManagedByOrganizationIdAsync(user);
|
||||||
|
|
||||||
|
var response = new ProfileResponseModel(user, null, null, null, userTwoFactorEnabled, userHasPremiumFromOrganization, managedByOrganizationId);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,7 +644,12 @@ public class AccountsController : Controller
|
|||||||
BillingAddressCountry = model.Country,
|
BillingAddressCountry = model.Country,
|
||||||
BillingAddressPostalCode = model.PostalCode,
|
BillingAddressPostalCode = model.PostalCode,
|
||||||
});
|
});
|
||||||
var profile = new ProfileResponseModel(user, null, null, null, await _userService.TwoFactorIsEnabledAsync(user), await _userService.HasPremiumFromOrganization(user));
|
|
||||||
|
var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
||||||
|
var userHasPremiumFromOrganization = await _userService.HasPremiumFromOrganization(user);
|
||||||
|
var managedByOrganizationId = await GetManagedByOrganizationIdAsync(user);
|
||||||
|
|
||||||
|
var profile = new ProfileResponseModel(user, null, null, null, userTwoFactorEnabled, userHasPremiumFromOrganization, managedByOrganizationId);
|
||||||
return new PaymentResponseModel
|
return new PaymentResponseModel
|
||||||
{
|
{
|
||||||
UserProfile = profile,
|
UserProfile = profile,
|
||||||
@ -920,4 +936,15 @@ public class AccountsController : Controller
|
|||||||
throw new BadRequestException("Token", "Invalid token");
|
throw new BadRequestException("Token", "Invalid token");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<Guid?> GetManagedByOrganizationIdAsync(User user)
|
||||||
|
{
|
||||||
|
if (!_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var organizationManagingUser = await _userService.GetOrganizationManagingUserAsync(user.Id);
|
||||||
|
return organizationManagingUser?.Id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ public class ProfileResponseModel : ResponseModel
|
|||||||
IEnumerable<ProviderUserProviderDetails> providerUserDetails,
|
IEnumerable<ProviderUserProviderDetails> providerUserDetails,
|
||||||
IEnumerable<ProviderUserOrganizationDetails> providerUserOrganizationDetails,
|
IEnumerable<ProviderUserOrganizationDetails> providerUserOrganizationDetails,
|
||||||
bool twoFactorEnabled,
|
bool twoFactorEnabled,
|
||||||
bool premiumFromOrganization) : base("profile")
|
bool premiumFromOrganization,
|
||||||
|
Guid? managedByOrganizationId) : base("profile")
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
@ -40,6 +41,7 @@ public class ProfileResponseModel : ResponseModel
|
|||||||
Providers = providerUserDetails?.Select(p => new ProfileProviderResponseModel(p));
|
Providers = providerUserDetails?.Select(p => new ProfileProviderResponseModel(p));
|
||||||
ProviderOrganizations =
|
ProviderOrganizations =
|
||||||
providerUserOrganizationDetails?.Select(po => new ProfileProviderOrganizationResponseModel(po));
|
providerUserOrganizationDetails?.Select(po => new ProfileProviderOrganizationResponseModel(po));
|
||||||
|
ManagedByOrganizationId = managedByOrganizationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfileResponseModel() : base("profile")
|
public ProfileResponseModel() : base("profile")
|
||||||
@ -61,6 +63,7 @@ public class ProfileResponseModel : ResponseModel
|
|||||||
public bool UsesKeyConnector { get; set; }
|
public bool UsesKeyConnector { get; set; }
|
||||||
public string AvatarColor { get; set; }
|
public string AvatarColor { get; set; }
|
||||||
public DateTime CreationDate { get; set; }
|
public DateTime CreationDate { get; set; }
|
||||||
|
public Guid? ManagedByOrganizationId { get; set; }
|
||||||
public IEnumerable<ProfileOrganizationResponseModel> Organizations { get; set; }
|
public IEnumerable<ProfileOrganizationResponseModel> Organizations { get; set; }
|
||||||
public IEnumerable<ProfileProviderResponseModel> Providers { get; set; }
|
public IEnumerable<ProfileProviderResponseModel> Providers { get; set; }
|
||||||
public IEnumerable<ProfileProviderOrganizationResponseModel> ProviderOrganizations { get; set; }
|
public IEnumerable<ProfileProviderOrganizationResponseModel> ProviderOrganizations { get; set; }
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Api.Vault.Models.Response;
|
using Bit.Api.Vault.Models.Response;
|
||||||
|
using Bit.Core;
|
||||||
using Bit.Core.AdminConsole.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.AdminConsole.Enums.Provider;
|
using Bit.Core.AdminConsole.Enums.Provider;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
@ -6,6 +7,7 @@ using Bit.Core.Entities;
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
@ -30,6 +32,7 @@ public class SyncController : Controller
|
|||||||
private readonly IPolicyRepository _policyRepository;
|
private readonly IPolicyRepository _policyRepository;
|
||||||
private readonly ISendRepository _sendRepository;
|
private readonly ISendRepository _sendRepository;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
private readonly IFeatureService _featureService;
|
||||||
|
|
||||||
public SyncController(
|
public SyncController(
|
||||||
IUserService userService,
|
IUserService userService,
|
||||||
@ -41,7 +44,8 @@ public class SyncController : Controller
|
|||||||
IProviderUserRepository providerUserRepository,
|
IProviderUserRepository providerUserRepository,
|
||||||
IPolicyRepository policyRepository,
|
IPolicyRepository policyRepository,
|
||||||
ISendRepository sendRepository,
|
ISendRepository sendRepository,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings,
|
||||||
|
IFeatureService featureService)
|
||||||
{
|
{
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
_folderRepository = folderRepository;
|
_folderRepository = folderRepository;
|
||||||
@ -53,6 +57,7 @@ public class SyncController : Controller
|
|||||||
_policyRepository = policyRepository;
|
_policyRepository = policyRepository;
|
||||||
_sendRepository = sendRepository;
|
_sendRepository = sendRepository;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
|
_featureService = featureService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("")]
|
[HttpGet("")]
|
||||||
@ -90,9 +95,23 @@ public class SyncController : Controller
|
|||||||
|
|
||||||
var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
|
||||||
var userHasPremiumFromOrganization = await _userService.HasPremiumFromOrganization(user);
|
var userHasPremiumFromOrganization = await _userService.HasPremiumFromOrganization(user);
|
||||||
var response = new SyncResponseModel(_globalSettings, user, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationUserDetails,
|
var managedByOrganizationId = await GetManagedByOrganizationIdAsync(user, organizationUserDetails);
|
||||||
providerUserDetails, providerUserOrganizationDetails, folders, collections, ciphers,
|
|
||||||
collectionCiphersGroupDict, excludeDomains, policies, sends);
|
var response = new SyncResponseModel(_globalSettings, user, userTwoFactorEnabled, userHasPremiumFromOrganization,
|
||||||
|
managedByOrganizationId, organizationUserDetails, providerUserDetails, providerUserOrganizationDetails,
|
||||||
|
folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains, policies, sends);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<Guid?> GetManagedByOrganizationIdAsync(User user, IEnumerable<OrganizationUserOrganizationDetails> organizationUserDetails)
|
||||||
|
{
|
||||||
|
if (!_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning) ||
|
||||||
|
!organizationUserDetails.Any(o => o.Enabled && o.UseSso))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var organizationManagingUser = await _userService.GetOrganizationManagingUserAsync(user.Id);
|
||||||
|
return organizationManagingUser?.Id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ public class SyncResponseModel : ResponseModel
|
|||||||
User user,
|
User user,
|
||||||
bool userTwoFactorEnabled,
|
bool userTwoFactorEnabled,
|
||||||
bool userHasPremiumFromOrganization,
|
bool userHasPremiumFromOrganization,
|
||||||
|
Guid? managedByOrganizationId,
|
||||||
IEnumerable<OrganizationUserOrganizationDetails> organizationUserDetails,
|
IEnumerable<OrganizationUserOrganizationDetails> organizationUserDetails,
|
||||||
IEnumerable<ProviderUserProviderDetails> providerUserDetails,
|
IEnumerable<ProviderUserProviderDetails> providerUserDetails,
|
||||||
IEnumerable<ProviderUserOrganizationDetails> providerUserOrganizationDetails,
|
IEnumerable<ProviderUserOrganizationDetails> providerUserOrganizationDetails,
|
||||||
@ -34,7 +35,7 @@ public class SyncResponseModel : ResponseModel
|
|||||||
: base("sync")
|
: base("sync")
|
||||||
{
|
{
|
||||||
Profile = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
|
Profile = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
|
||||||
providerUserOrganizationDetails, userTwoFactorEnabled, userHasPremiumFromOrganization);
|
providerUserOrganizationDetails, userTwoFactorEnabled, userHasPremiumFromOrganization, managedByOrganizationId);
|
||||||
Folders = folders.Select(f => new FolderResponseModel(f));
|
Folders = folders.Select(f => new FolderResponseModel(f));
|
||||||
Ciphers = ciphers.Select(c => new CipherDetailsResponseModel(c, globalSettings, collectionCiphersDict));
|
Ciphers = ciphers.Select(c => new CipherDetailsResponseModel(c, globalSettings, collectionCiphersDict));
|
||||||
Collections = collections?.Select(
|
Collections = collections?.Select(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Auth.Enums;
|
using Bit.Core.Auth.Enums;
|
||||||
using Bit.Core.Auth.Models;
|
using Bit.Core.Auth.Models;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
@ -95,4 +96,10 @@ public interface IUserService
|
|||||||
/// The organization must be enabled and be on an Enterprise plan.
|
/// The organization must be enabled and be on an Enterprise plan.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
Task<bool> IsManagedByAnyOrganizationAsync(Guid userId);
|
Task<bool> IsManagedByAnyOrganizationAsync(Guid userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the organization that manages the user.
|
||||||
|
/// </summary>
|
||||||
|
/// <inheritdoc cref="IsManagedByAnyOrganizationAsync(Guid)"/>
|
||||||
|
Task<Organization> GetOrganizationManagingUserAsync(Guid userId);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Enums;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.AdminConsole.Services;
|
using Bit.Core.AdminConsole.Services;
|
||||||
@ -1245,13 +1246,19 @@ public class UserService : UserManager<User>, IUserService, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> IsManagedByAnyOrganizationAsync(Guid userId)
|
public async Task<bool> IsManagedByAnyOrganizationAsync(Guid userId)
|
||||||
|
{
|
||||||
|
var managingOrganization = await GetOrganizationManagingUserAsync(userId);
|
||||||
|
return managingOrganization != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Organization> GetOrganizationManagingUserAsync(Guid userId)
|
||||||
{
|
{
|
||||||
// Users can only be managed by an Organization that is enabled and can have organization domains
|
// Users can only be managed by an Organization that is enabled and can have organization domains
|
||||||
var organization = await _organizationRepository.GetByClaimedUserDomainAsync(userId);
|
var organization = await _organizationRepository.GetByClaimedUserDomainAsync(userId);
|
||||||
|
|
||||||
// TODO: Replace "UseSso" with a new organization ability like "UseOrganizationDomains" (PM-11622).
|
// TODO: Replace "UseSso" with a new organization ability like "UseOrganizationDomains" (PM-11622).
|
||||||
// Verified domains were tied to SSO, so we currently check the "UseSso" organization ability.
|
// Verified domains were tied to SSO, so we currently check the "UseSso" organization ability.
|
||||||
return organization is { Enabled: true, UseSso: true };
|
return (organization is { Enabled: true, UseSso: true }) ? organization : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IsLegacyUser(string)"/>
|
/// <inheritdoc cref="IsLegacyUser(string)"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user