1
0
mirror of https://github.com/bitwarden/server.git synced 2025-02-12 01:11:22 +01:00

Merge branch 'main' into km/userkey-rotation-v2

This commit is contained in:
Bernd Schoolmann 2025-01-30 16:01:14 +01:00 committed by GitHub
commit 8f9252decb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 140 additions and 20 deletions

View File

@ -309,7 +309,7 @@ public class OrganizationsController : Controller
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
[RequirePermission(Permission.Org_Delete)] [RequirePermission(Permission.Org_RequestDelete)]
public async Task<IActionResult> DeleteInitiation(Guid id, OrganizationInitiateDeleteModel model) public async Task<IActionResult> DeleteInitiation(Guid id, OrganizationInitiateDeleteModel model)
{ {
if (!ModelState.IsValid) if (!ModelState.IsValid)

View File

@ -311,10 +311,8 @@ public class OrganizationUsersController : Controller
throw new UnauthorizedAccessException(); throw new UnauthorizedAccessException();
} }
var masterPasswordPolicy = await _policyRepository.GetByOrganizationIdTypeAsync(orgId, PolicyType.ResetPassword); var useMasterPasswordPolicy = await ShouldHandleResetPasswordAsync(orgId);
var useMasterPasswordPolicy = masterPasswordPolicy != null &&
masterPasswordPolicy.Enabled &&
masterPasswordPolicy.GetDataModel<ResetPasswordDataModel>().AutoEnrollEnabled;
if (useMasterPasswordPolicy && string.IsNullOrWhiteSpace(model.ResetPasswordKey)) if (useMasterPasswordPolicy && string.IsNullOrWhiteSpace(model.ResetPasswordKey))
{ {
throw new BadRequestException(string.Empty, "Master Password reset is required, but not provided."); throw new BadRequestException(string.Empty, "Master Password reset is required, but not provided.");
@ -328,6 +326,23 @@ public class OrganizationUsersController : Controller
} }
} }
private async Task<bool> ShouldHandleResetPasswordAsync(Guid orgId)
{
var organizationAbility = await _applicationCacheService.GetOrganizationAbilityAsync(orgId);
if (organizationAbility is not { UsePolicies: true })
{
return false;
}
var masterPasswordPolicy = await _policyRepository.GetByOrganizationIdTypeAsync(orgId, PolicyType.ResetPassword);
var useMasterPasswordPolicy = masterPasswordPolicy != null &&
masterPasswordPolicy.Enabled &&
masterPasswordPolicy.GetDataModel<ResetPasswordDataModel>().AutoEnrollEnabled;
return useMasterPasswordPolicy;
}
[HttpPost("{id}/confirm")] [HttpPost("{id}/confirm")]
public async Task Confirm(string orgId, string id, [FromBody] OrganizationUserConfirmRequestModel model) public async Task Confirm(string orgId, string id, [FromBody] OrganizationUserConfirmRequestModel model)
{ {

View File

@ -57,6 +57,7 @@ public class OrganizationResponseModel : ResponseModel
MaxAutoscaleSmServiceAccounts = organization.MaxAutoscaleSmServiceAccounts; MaxAutoscaleSmServiceAccounts = organization.MaxAutoscaleSmServiceAccounts;
LimitCollectionCreation = organization.LimitCollectionCreation; LimitCollectionCreation = organization.LimitCollectionCreation;
LimitCollectionDeletion = organization.LimitCollectionDeletion; LimitCollectionDeletion = organization.LimitCollectionDeletion;
LimitItemDeletion = organization.LimitItemDeletion;
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems; AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
UseRiskInsights = organization.UseRiskInsights; UseRiskInsights = organization.UseRiskInsights;
} }
@ -102,6 +103,7 @@ public class OrganizationResponseModel : ResponseModel
public int? MaxAutoscaleSmServiceAccounts { get; set; } public int? MaxAutoscaleSmServiceAccounts { get; set; }
public bool LimitCollectionCreation { get; set; } public bool LimitCollectionCreation { get; set; }
public bool LimitCollectionDeletion { get; set; } public bool LimitCollectionDeletion { get; set; }
public bool LimitItemDeletion { get; set; }
public bool AllowAdminAccessToAllCollectionItems { get; set; } public bool AllowAdminAccessToAllCollectionItems { get; set; }
public bool UseRiskInsights { get; set; } public bool UseRiskInsights { get; set; }
} }

View File

@ -67,6 +67,7 @@ public class ProfileOrganizationResponseModel : ResponseModel
AccessSecretsManager = organization.AccessSecretsManager; AccessSecretsManager = organization.AccessSecretsManager;
LimitCollectionCreation = organization.LimitCollectionCreation; LimitCollectionCreation = organization.LimitCollectionCreation;
LimitCollectionDeletion = organization.LimitCollectionDeletion; LimitCollectionDeletion = organization.LimitCollectionDeletion;
LimitItemDeletion = organization.LimitItemDeletion;
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems; AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
UserIsManagedByOrganization = organizationIdsManagingUser.Contains(organization.OrganizationId); UserIsManagedByOrganization = organizationIdsManagingUser.Contains(organization.OrganizationId);
UseRiskInsights = organization.UseRiskInsights; UseRiskInsights = organization.UseRiskInsights;
@ -128,6 +129,7 @@ public class ProfileOrganizationResponseModel : ResponseModel
public bool AccessSecretsManager { get; set; } public bool AccessSecretsManager { get; set; }
public bool LimitCollectionCreation { get; set; } public bool LimitCollectionCreation { get; set; }
public bool LimitCollectionDeletion { get; set; } public bool LimitCollectionDeletion { get; set; }
public bool LimitItemDeletion { get; set; }
public bool AllowAdminAccessToAllCollectionItems { get; set; } public bool AllowAdminAccessToAllCollectionItems { get; set; }
/// <summary> /// <summary>
/// Indicates if the organization manages the user. /// Indicates if the organization manages the user.

View File

@ -47,6 +47,7 @@ public class ProfileProviderOrganizationResponseModel : ProfileOrganizationRespo
ProductTierType = StaticStore.GetPlan(organization.PlanType).ProductTier; ProductTierType = StaticStore.GetPlan(organization.PlanType).ProductTier;
LimitCollectionCreation = organization.LimitCollectionCreation; LimitCollectionCreation = organization.LimitCollectionCreation;
LimitCollectionDeletion = organization.LimitCollectionDeletion; LimitCollectionDeletion = organization.LimitCollectionDeletion;
LimitItemDeletion = organization.LimitItemDeletion;
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems; AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
UseRiskInsights = organization.UseRiskInsights; UseRiskInsights = organization.UseRiskInsights;
} }

View File

@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Reflection; using System.Reflection;
using Bit.Core.Auth.Entities; using Bit.Core.Auth.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api; using Bit.Core.Models.Api;
namespace Bit.Api.Auth.Models.Response; namespace Bit.Api.Auth.Models.Response;
@ -17,6 +18,7 @@ public class AuthRequestResponseModel : ResponseModel
Id = authRequest.Id; Id = authRequest.Id;
PublicKey = authRequest.PublicKey; PublicKey = authRequest.PublicKey;
RequestDeviceTypeValue = authRequest.RequestDeviceType;
RequestDeviceType = authRequest.RequestDeviceType.GetType().GetMember(authRequest.RequestDeviceType.ToString()) RequestDeviceType = authRequest.RequestDeviceType.GetType().GetMember(authRequest.RequestDeviceType.ToString())
.FirstOrDefault()?.GetCustomAttribute<DisplayAttribute>()?.GetName(); .FirstOrDefault()?.GetCustomAttribute<DisplayAttribute>()?.GetName();
RequestIpAddress = authRequest.RequestIpAddress; RequestIpAddress = authRequest.RequestIpAddress;
@ -30,6 +32,7 @@ public class AuthRequestResponseModel : ResponseModel
public Guid Id { get; set; } public Guid Id { get; set; }
public string PublicKey { get; set; } public string PublicKey { get; set; }
public DeviceType RequestDeviceTypeValue { get; set; }
public string RequestDeviceType { get; set; } public string RequestDeviceType { get; set; }
public string RequestIpAddress { get; set; } public string RequestIpAddress { get; set; }
public string Key { get; set; } public string Key { get; set; }

View File

@ -7,12 +7,14 @@ public class OrganizationCollectionManagementUpdateRequestModel
{ {
public bool LimitCollectionCreation { get; set; } public bool LimitCollectionCreation { get; set; }
public bool LimitCollectionDeletion { get; set; } public bool LimitCollectionDeletion { get; set; }
public bool LimitItemDeletion { get; set; }
public bool AllowAdminAccessToAllCollectionItems { get; set; } public bool AllowAdminAccessToAllCollectionItems { get; set; }
public virtual Organization ToOrganization(Organization existingOrganization, IFeatureService featureService) public virtual Organization ToOrganization(Organization existingOrganization, IFeatureService featureService)
{ {
existingOrganization.LimitCollectionCreation = LimitCollectionCreation; existingOrganization.LimitCollectionCreation = LimitCollectionCreation;
existingOrganization.LimitCollectionDeletion = LimitCollectionDeletion; existingOrganization.LimitCollectionDeletion = LimitCollectionDeletion;
existingOrganization.LimitItemDeletion = LimitItemDeletion;
existingOrganization.AllowAdminAccessToAllCollectionItems = AllowAdminAccessToAllCollectionItems; existingOrganization.AllowAdminAccessToAllCollectionItems = AllowAdminAccessToAllCollectionItems;
return existingOrganization; return existingOrganization;
} }

View File

@ -1097,7 +1097,7 @@ public class CiphersController : Controller
[HttpDelete("{id}/attachment/{attachmentId}")] [HttpDelete("{id}/attachment/{attachmentId}")]
[HttpPost("{id}/attachment/{attachmentId}/delete")] [HttpPost("{id}/attachment/{attachmentId}/delete")]
public async Task DeleteAttachment(Guid id, string attachmentId) public async Task<DeleteAttachmentResponseData> DeleteAttachment(Guid id, string attachmentId)
{ {
var userId = _userService.GetProperUserId(User).Value; var userId = _userService.GetProperUserId(User).Value;
var cipher = await GetByIdAsync(id, userId); var cipher = await GetByIdAsync(id, userId);
@ -1106,7 +1106,7 @@ public class CiphersController : Controller
throw new NotFoundException(); throw new NotFoundException();
} }
await _cipherService.DeleteAttachmentAsync(cipher, attachmentId, userId, false); return await _cipherService.DeleteAttachmentAsync(cipher, attachmentId, userId, false);
} }
[HttpDelete("{id}/attachment/{attachmentId}/admin")] [HttpDelete("{id}/attachment/{attachmentId}/admin")]

View File

@ -23,6 +23,7 @@ public class OrganizationAbility
UsePolicies = organization.UsePolicies; UsePolicies = organization.UsePolicies;
LimitCollectionCreation = organization.LimitCollectionCreation; LimitCollectionCreation = organization.LimitCollectionCreation;
LimitCollectionDeletion = organization.LimitCollectionDeletion; LimitCollectionDeletion = organization.LimitCollectionDeletion;
LimitItemDeletion = organization.LimitItemDeletion;
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems; AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
UseRiskInsights = organization.UseRiskInsights; UseRiskInsights = organization.UseRiskInsights;
} }
@ -41,6 +42,7 @@ public class OrganizationAbility
public bool UsePolicies { get; set; } public bool UsePolicies { get; set; }
public bool LimitCollectionCreation { get; set; } public bool LimitCollectionCreation { get; set; }
public bool LimitCollectionDeletion { get; set; } public bool LimitCollectionDeletion { get; set; }
public bool LimitItemDeletion { get; set; }
public bool AllowAdminAccessToAllCollectionItems { get; set; } public bool AllowAdminAccessToAllCollectionItems { get; set; }
public bool UseRiskInsights { get; set; } public bool UseRiskInsights { get; set; }
} }

View File

@ -56,6 +56,7 @@ public class OrganizationUserOrganizationDetails
public int? SmServiceAccounts { get; set; } public int? SmServiceAccounts { get; set; }
public bool LimitCollectionCreation { get; set; } public bool LimitCollectionCreation { get; set; }
public bool LimitCollectionDeletion { get; set; } public bool LimitCollectionDeletion { get; set; }
public bool LimitItemDeletion { get; set; }
public bool AllowAdminAccessToAllCollectionItems { get; set; } public bool AllowAdminAccessToAllCollectionItems { get; set; }
public bool UseRiskInsights { get; set; } public bool UseRiskInsights { get; set; }
} }

View File

@ -146,6 +146,7 @@ public class SelfHostedOrganizationDetails : Organization
OwnersNotifiedOfAutoscaling = OwnersNotifiedOfAutoscaling, OwnersNotifiedOfAutoscaling = OwnersNotifiedOfAutoscaling,
LimitCollectionCreation = LimitCollectionCreation, LimitCollectionCreation = LimitCollectionCreation,
LimitCollectionDeletion = LimitCollectionDeletion, LimitCollectionDeletion = LimitCollectionDeletion,
LimitItemDeletion = LimitItemDeletion,
AllowAdminAccessToAllCollectionItems = AllowAdminAccessToAllCollectionItems, AllowAdminAccessToAllCollectionItems = AllowAdminAccessToAllCollectionItems,
Status = Status Status = Status
}; };

View File

@ -42,6 +42,7 @@ public class ProviderUserOrganizationDetails
public PlanType PlanType { get; set; } public PlanType PlanType { get; set; }
public bool LimitCollectionCreation { get; set; } public bool LimitCollectionCreation { get; set; }
public bool LimitCollectionDeletion { get; set; } public bool LimitCollectionDeletion { get; set; }
public bool LimitItemDeletion { get; set; }
public bool AllowAdminAccessToAllCollectionItems { get; set; } public bool AllowAdminAccessToAllCollectionItems { get; set; }
public bool UseRiskInsights { get; set; } public bool UseRiskInsights { get; set; }
public ProviderType ProviderType { get; set; } public ProviderType ProviderType { get; set; }

View File

@ -168,6 +168,9 @@ public static class FeatureFlagKeys
public const string EnablePasswordManagerSyncAndroid = "enable-password-manager-sync-android"; public const string EnablePasswordManagerSyncAndroid = "enable-password-manager-sync-android";
public const string EnablePasswordManagerSynciOS = "enable-password-manager-sync-ios"; public const string EnablePasswordManagerSynciOS = "enable-password-manager-sync-ios";
public const string AccountDeprovisioningBanner = "pm-17120-account-deprovisioning-admin-console-banner"; public const string AccountDeprovisioningBanner = "pm-17120-account-deprovisioning-admin-console-banner";
public const string SingleTapPasskeyCreation = "single-tap-passkey-creation";
public const string SingleTapPasskeyAuthentication = "single-tap-passkey-authentication";
public const string EnableRiskInsightsNotifications = "enable-risk-insights-notifications";
public static List<string> GetAllKeys() public static List<string> GetAllKeys()
{ {

View File

@ -62,4 +62,5 @@ public class OrganizationCollectionManagementPushNotification
public Guid OrganizationId { get; init; } public Guid OrganizationId { get; init; }
public bool LimitCollectionCreation { get; init; } public bool LimitCollectionCreation { get; init; }
public bool LimitCollectionDeletion { get; init; } public bool LimitCollectionDeletion { get; init; }
public bool LimitItemDeletion { get; init; }
} }

View File

@ -246,7 +246,8 @@ public class NotificationHubPushNotificationService : IPushNotificationService
{ {
OrganizationId = organization.Id, OrganizationId = organization.Id,
LimitCollectionCreation = organization.LimitCollectionCreation, LimitCollectionCreation = organization.LimitCollectionCreation,
LimitCollectionDeletion = organization.LimitCollectionDeletion LimitCollectionDeletion = organization.LimitCollectionDeletion,
LimitItemDeletion = organization.LimitItemDeletion
}, },
false false
); );

View File

@ -239,6 +239,7 @@ public class AzureQueuePushNotificationService : IPushNotificationService
{ {
OrganizationId = organization.Id, OrganizationId = organization.Id,
LimitCollectionCreation = organization.LimitCollectionCreation, LimitCollectionCreation = organization.LimitCollectionCreation,
LimitCollectionDeletion = organization.LimitCollectionDeletion LimitCollectionDeletion = organization.LimitCollectionDeletion,
LimitItemDeletion = organization.LimitItemDeletion
}, false); }, false);
} }

View File

@ -248,6 +248,7 @@ public class NotificationsApiPushNotificationService : BaseIdentityClientService
{ {
OrganizationId = organization.Id, OrganizationId = organization.Id,
LimitCollectionCreation = organization.LimitCollectionCreation, LimitCollectionCreation = organization.LimitCollectionCreation,
LimitCollectionDeletion = organization.LimitCollectionDeletion LimitCollectionDeletion = organization.LimitCollectionDeletion,
LimitItemDeletion = organization.LimitItemDeletion
}, false); }, false);
} }

View File

@ -273,7 +273,8 @@ public class RelayPushNotificationService : BaseIdentityClientService, IPushNoti
{ {
OrganizationId = organization.Id, OrganizationId = organization.Id,
LimitCollectionCreation = organization.LimitCollectionCreation, LimitCollectionCreation = organization.LimitCollectionCreation,
LimitCollectionDeletion = organization.LimitCollectionDeletion LimitCollectionDeletion = organization.LimitCollectionDeletion,
LimitItemDeletion = organization.LimitItemDeletion
}, },
false false
); );

View File

@ -0,0 +1,13 @@
using Bit.Core.Vault.Entities;
namespace Bit.Core.Vault.Models.Data;
public class DeleteAttachmentResponseData
{
public Cipher Cipher { get; set; }
public DeleteAttachmentResponseData(Cipher cipher)
{
Cipher = cipher;
}
}

View File

@ -17,7 +17,7 @@ public interface ICipherService
string attachmentId, Guid organizationShareId); string attachmentId, Guid organizationShareId);
Task DeleteAsync(Cipher cipher, Guid deletingUserId, bool orgAdmin = false); Task DeleteAsync(Cipher cipher, Guid deletingUserId, bool orgAdmin = false);
Task DeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId, Guid? organizationId = null, bool orgAdmin = false); Task DeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId, Guid? organizationId = null, bool orgAdmin = false);
Task DeleteAttachmentAsync(Cipher cipher, string attachmentId, Guid deletingUserId, bool orgAdmin = false); Task<DeleteAttachmentResponseData> DeleteAttachmentAsync(Cipher cipher, string attachmentId, Guid deletingUserId, bool orgAdmin = false);
Task PurgeAsync(Guid organizationId); Task PurgeAsync(Guid organizationId);
Task MoveManyAsync(IEnumerable<Guid> cipherIds, Guid? destinationFolderId, Guid movingUserId); Task MoveManyAsync(IEnumerable<Guid> cipherIds, Guid? destinationFolderId, Guid movingUserId);
Task SaveFolderAsync(Folder folder); Task SaveFolderAsync(Folder folder);

View File

@ -210,6 +210,11 @@ public class CipherService : ICipherService
AttachmentData = JsonSerializer.Serialize(data) AttachmentData = JsonSerializer.Serialize(data)
}); });
cipher.AddAttachment(attachmentId, data); cipher.AddAttachment(attachmentId, data);
// Update the revision date when an attachment is added
cipher.RevisionDate = DateTime.UtcNow;
await _cipherRepository.ReplaceAsync((CipherDetails)cipher);
await _pushService.PushSyncCipherUpdateAsync(cipher, null); await _pushService.PushSyncCipherUpdateAsync(cipher, null);
return (attachmentId, uploadUrl); return (attachmentId, uploadUrl);
@ -259,6 +264,10 @@ public class CipherService : ICipherService
throw; throw;
} }
// Update the revision date when an attachment is added
cipher.RevisionDate = DateTime.UtcNow;
await _cipherRepository.ReplaceAsync((CipherDetails)cipher);
// push // push
await _pushService.PushSyncCipherUpdateAsync(cipher, null); await _pushService.PushSyncCipherUpdateAsync(cipher, null);
} }
@ -441,7 +450,7 @@ public class CipherService : ICipherService
await _pushService.PushSyncCiphersAsync(deletingUserId); await _pushService.PushSyncCiphersAsync(deletingUserId);
} }
public async Task DeleteAttachmentAsync(Cipher cipher, string attachmentId, Guid deletingUserId, public async Task<DeleteAttachmentResponseData> DeleteAttachmentAsync(Cipher cipher, string attachmentId, Guid deletingUserId,
bool orgAdmin = false) bool orgAdmin = false)
{ {
if (!orgAdmin && !(await UserCanEditAsync(cipher, deletingUserId))) if (!orgAdmin && !(await UserCanEditAsync(cipher, deletingUserId)))
@ -454,7 +463,7 @@ public class CipherService : ICipherService
throw new NotFoundException(); throw new NotFoundException();
} }
await DeleteAttachmentAsync(cipher, cipher.GetAttachments()[attachmentId]); return await DeleteAttachmentAsync(cipher, cipher.GetAttachments()[attachmentId]);
} }
public async Task PurgeAsync(Guid organizationId) public async Task PurgeAsync(Guid organizationId)
@ -834,11 +843,11 @@ public class CipherService : ICipherService
} }
} }
private async Task DeleteAttachmentAsync(Cipher cipher, CipherAttachment.MetaData attachmentData) private async Task<DeleteAttachmentResponseData> DeleteAttachmentAsync(Cipher cipher, CipherAttachment.MetaData attachmentData)
{ {
if (attachmentData == null || string.IsNullOrWhiteSpace(attachmentData.AttachmentId)) if (attachmentData == null || string.IsNullOrWhiteSpace(attachmentData.AttachmentId))
{ {
return; return null;
} }
await _cipherRepository.DeleteAttachmentAsync(cipher.Id, attachmentData.AttachmentId); await _cipherRepository.DeleteAttachmentAsync(cipher.Id, attachmentData.AttachmentId);
@ -846,8 +855,14 @@ public class CipherService : ICipherService
await _attachmentStorageService.DeleteAttachmentAsync(cipher.Id, attachmentData); await _attachmentStorageService.DeleteAttachmentAsync(cipher.Id, attachmentData);
await _eventService.LogCipherEventAsync(cipher, Bit.Core.Enums.EventType.Cipher_AttachmentDeleted); await _eventService.LogCipherEventAsync(cipher, Bit.Core.Enums.EventType.Cipher_AttachmentDeleted);
// Update the revision date when an attachment is deleted
cipher.RevisionDate = DateTime.UtcNow;
await _cipherRepository.ReplaceAsync((CipherDetails)cipher);
// push // push
await _pushService.PushSyncCipherUpdateAsync(cipher, null); await _pushService.PushSyncCipherUpdateAsync(cipher, null);
return new DeleteAttachmentResponseData(cipher);
} }
private async Task ValidateCipherEditForAttachmentAsync(Cipher cipher, Guid savingUserId, bool orgAdmin, private async Task ValidateCipherEditForAttachmentAsync(Cipher cipher, Guid savingUserId, bool orgAdmin,

View File

@ -20,5 +20,6 @@ public static class VaultServiceCollectionExtensions
services.AddScoped<IGetTaskDetailsForUserQuery, GetTaskDetailsForUserQuery>(); services.AddScoped<IGetTaskDetailsForUserQuery, GetTaskDetailsForUserQuery>();
services.AddScoped<IMarkTaskAsCompleteCommand, MarkTaskAsCompletedCommand>(); services.AddScoped<IMarkTaskAsCompleteCommand, MarkTaskAsCompletedCommand>();
services.AddScoped<IGetCipherPermissionsForUserQuery, GetCipherPermissionsForUserQuery>(); services.AddScoped<IGetCipherPermissionsForUserQuery, GetCipherPermissionsForUserQuery>();
services.AddScoped<IGetTasksForOrganizationQuery, GetTasksForOrganizationQuery>();
} }
} }

View File

@ -101,6 +101,7 @@ public class OrganizationRepository : Repository<Core.AdminConsole.Entities.Orga
UsePolicies = e.UsePolicies, UsePolicies = e.UsePolicies,
LimitCollectionCreation = e.LimitCollectionCreation, LimitCollectionCreation = e.LimitCollectionCreation,
LimitCollectionDeletion = e.LimitCollectionDeletion, LimitCollectionDeletion = e.LimitCollectionDeletion,
LimitItemDeletion = e.LimitItemDeletion,
AllowAdminAccessToAllCollectionItems = e.AllowAdminAccessToAllCollectionItems, AllowAdminAccessToAllCollectionItems = e.AllowAdminAccessToAllCollectionItems,
UseRiskInsights = e.UseRiskInsights UseRiskInsights = e.UseRiskInsights
}).ToListAsync(); }).ToListAsync();

View File

@ -68,6 +68,7 @@ public class OrganizationUserOrganizationDetailsViewQuery : IQuery<OrganizationU
SmServiceAccounts = o.SmServiceAccounts, SmServiceAccounts = o.SmServiceAccounts,
LimitCollectionCreation = o.LimitCollectionCreation, LimitCollectionCreation = o.LimitCollectionCreation,
LimitCollectionDeletion = o.LimitCollectionDeletion, LimitCollectionDeletion = o.LimitCollectionDeletion,
LimitItemDeletion = o.LimitItemDeletion,
AllowAdminAccessToAllCollectionItems = o.AllowAdminAccessToAllCollectionItems, AllowAdminAccessToAllCollectionItems = o.AllowAdminAccessToAllCollectionItems,
UseRiskInsights = o.UseRiskInsights, UseRiskInsights = o.UseRiskInsights,
}; };

View File

@ -46,6 +46,7 @@ public class ProviderUserOrganizationDetailsViewQuery : IQuery<ProviderUserOrgan
PlanType = x.o.PlanType, PlanType = x.o.PlanType,
LimitCollectionCreation = x.o.LimitCollectionCreation, LimitCollectionCreation = x.o.LimitCollectionCreation,
LimitCollectionDeletion = x.o.LimitCollectionDeletion, LimitCollectionDeletion = x.o.LimitCollectionDeletion,
LimitItemDeletion = x.o.LimitItemDeletion,
AllowAdminAccessToAllCollectionItems = x.o.AllowAdminAccessToAllCollectionItems, AllowAdminAccessToAllCollectionItems = x.o.AllowAdminAccessToAllCollectionItems,
UseRiskInsights = x.o.UseRiskInsights, UseRiskInsights = x.o.UseRiskInsights,
ProviderType = x.p.Type ProviderType = x.p.Type

View File

@ -123,24 +123,74 @@ public class OrganizationUsersControllerTests
[Theory] [Theory]
[BitAutoData] [BitAutoData]
public async Task Accept_RequireMasterPasswordReset(Guid orgId, Guid orgUserId, public async Task Accept_WhenOrganizationUsePoliciesIsEnabledAndResetPolicyIsEnabled_ShouldHandleResetPassword(Guid orgId, Guid orgUserId,
OrganizationUserAcceptRequestModel model, User user, SutProvider<OrganizationUsersController> sutProvider) OrganizationUserAcceptRequestModel model, User user, SutProvider<OrganizationUsersController> sutProvider)
{ {
// Arrange
var applicationCacheService = sutProvider.GetDependency<IApplicationCacheService>();
applicationCacheService.GetOrganizationAbilityAsync(orgId).Returns(new OrganizationAbility { UsePolicies = true });
var policy = new Policy var policy = new Policy
{ {
Enabled = true, Enabled = true,
Data = CoreHelpers.ClassToJsonData(new ResetPasswordDataModel { AutoEnrollEnabled = true, }), Data = CoreHelpers.ClassToJsonData(new ResetPasswordDataModel { AutoEnrollEnabled = true, }),
}; };
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(default).ReturnsForAnyArgs(user); var userService = sutProvider.GetDependency<IUserService>();
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(orgId, userService.GetUserByPrincipalAsync(default).ReturnsForAnyArgs(user);
var policyRepository = sutProvider.GetDependency<IPolicyRepository>();
policyRepository.GetByOrganizationIdTypeAsync(orgId,
PolicyType.ResetPassword).Returns(policy); PolicyType.ResetPassword).Returns(policy);
// Act
await sutProvider.Sut.Accept(orgId, orgUserId, model); await sutProvider.Sut.Accept(orgId, orgUserId, model);
// Assert
await sutProvider.GetDependency<IAcceptOrgUserCommand>().Received(1) await sutProvider.GetDependency<IAcceptOrgUserCommand>().Received(1)
.AcceptOrgUserByEmailTokenAsync(orgUserId, user, model.Token, sutProvider.GetDependency<IUserService>()); .AcceptOrgUserByEmailTokenAsync(orgUserId, user, model.Token, userService);
await sutProvider.GetDependency<IOrganizationService>().Received(1) await sutProvider.GetDependency<IOrganizationService>().Received(1)
.UpdateUserResetPasswordEnrollmentAsync(orgId, user.Id, model.ResetPasswordKey, user.Id); .UpdateUserResetPasswordEnrollmentAsync(orgId, user.Id, model.ResetPasswordKey, user.Id);
await userService.Received(1).GetUserByPrincipalAsync(default);
await applicationCacheService.Received(1).GetOrganizationAbilityAsync(orgId);
await policyRepository.Received(1).GetByOrganizationIdTypeAsync(orgId, PolicyType.ResetPassword);
}
[Theory]
[BitAutoData]
public async Task Accept_WhenOrganizationUsePoliciesIsDisabled_ShouldNotHandleResetPassword(Guid orgId, Guid orgUserId,
OrganizationUserAcceptRequestModel model, User user, SutProvider<OrganizationUsersController> sutProvider)
{
// Arrange
var applicationCacheService = sutProvider.GetDependency<IApplicationCacheService>();
applicationCacheService.GetOrganizationAbilityAsync(orgId).Returns(new OrganizationAbility { UsePolicies = false });
var policy = new Policy
{
Enabled = true,
Data = CoreHelpers.ClassToJsonData(new ResetPasswordDataModel { AutoEnrollEnabled = true, }),
};
var userService = sutProvider.GetDependency<IUserService>();
userService.GetUserByPrincipalAsync(default).ReturnsForAnyArgs(user);
var policyRepository = sutProvider.GetDependency<IPolicyRepository>();
policyRepository.GetByOrganizationIdTypeAsync(orgId,
PolicyType.ResetPassword).Returns(policy);
// Act
await sutProvider.Sut.Accept(orgId, orgUserId, model);
// Assert
await userService.Received(1).GetUserByPrincipalAsync(default);
await sutProvider.GetDependency<IAcceptOrgUserCommand>().Received(1)
.AcceptOrgUserByEmailTokenAsync(orgUserId, user, model.Token, userService);
await sutProvider.GetDependency<IOrganizationService>().Received(0)
.UpdateUserResetPasswordEnrollmentAsync(orgId, user.Id, model.ResetPasswordKey, user.Id);
await policyRepository.Received(0).GetByOrganizationIdTypeAsync(orgId, PolicyType.ResetPassword);
await applicationCacheService.Received(1).GetOrganizationAbilityAsync(orgId);
} }
[Theory] [Theory]