1
0
mirror of https://github.com/bitwarden/server.git synced 2024-12-10 15:13:29 +01:00

Add remaining PolicyDefinitions

This commit is contained in:
Thomas Rittson 2024-10-07 11:20:20 +10:00
parent 22500e4222
commit ed9ee20dc4
No known key found for this signature in database
GPG Key ID: CDDDA03861C35E27
15 changed files with 227 additions and 3 deletions

View File

@ -15,7 +15,7 @@ public interface IPolicyDefinition
/// <summary>
/// PolicyTypes that must be enabled before this policy can be enabled, if any.
/// </summary>
public IEnumerable<PolicyType> RequiredPolicies { get; }
public IEnumerable<PolicyType> RequiredPolicies => [];
/// <summary>
/// Validates a policy before saving it.

View File

@ -0,0 +1,8 @@
using Bit.Core.AdminConsole.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class ActivateAutofillPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.ActivateAutofill;
}

View File

@ -0,0 +1,8 @@
using Bit.Core.AdminConsole.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class AutomaticAppLogInPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.AutomaticAppLogIn;
}

View File

@ -0,0 +1,8 @@
using Bit.Core.AdminConsole.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class DisablePersonalVaultExportPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.DisablePersonalVaultExport;
}

View File

@ -0,0 +1,10 @@
#nullable enable
using Bit.Core.AdminConsole.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class DisableSendPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.DisableSend;
}

View File

@ -0,0 +1,10 @@
#nullable enable
using Bit.Core.AdminConsole.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class MasterPasswordPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.MasterPassword;
}

View File

@ -0,0 +1,9 @@
using Bit.Core.AdminConsole.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class MaximumVaultTimeoutPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.MaximumVaultTimeout;
public IEnumerable<PolicyType> RequiredPolicies => [PolicyType.SingleOrg];
}

View File

@ -0,0 +1,10 @@
#nullable enable
using Bit.Core.AdminConsole.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class PasswordGeneratorPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.PasswordGenerator;
}

View File

@ -0,0 +1,10 @@
#nullable enable
using Bit.Core.AdminConsole.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class PersonalOwnershipPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.PersonalOwnership;
}

View File

@ -0,0 +1,11 @@
#nullable enable
using Bit.Core.AdminConsole.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class RequireSsoPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.RequireSso;
public IEnumerable<PolicyType> RequiredPolicies => [PolicyType.SingleOrg];
}

View File

@ -0,0 +1,36 @@
#nullable enable
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Repositories;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class ResetPasswordPolicyDefinition : IPolicyDefinition
{
private readonly ISsoConfigRepository _ssoConfigRepository;
public PolicyType Type => PolicyType.ResetPassword;
public IEnumerable<PolicyType> RequiredPolicies => [PolicyType.SingleOrg];
ResetPasswordPolicyDefinition(ISsoConfigRepository ssoConfigRepository)
{
_ssoConfigRepository = ssoConfigRepository;
}
public async Task<string?> ValidateAsync(Policy? currentPolicy, Policy modifiedPolicy)
{
if (modifiedPolicy is not { Enabled:true } ||
modifiedPolicy.GetDataModel<ResetPasswordDataModel>()?.AutoEnrollEnabled == false)
{
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(modifiedPolicy.OrganizationId);
if (ssoConfig?.GetData()?.MemberDecryptionType == MemberDecryptionType.TrustedDeviceEncryption)
{
return "Trusted device encryption is on and requires this policy.";
}
}
return null;
}
}

View File

@ -0,0 +1,10 @@
#nullable enable
using Bit.Core.AdminConsole.Enums;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class SendOptionsPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.SendOptions;
}

View File

@ -15,7 +15,6 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class SingleOrgPolicyDefinition : IPolicyDefinition
{
public PolicyType Type => PolicyType.SingleOrg;
public IEnumerable<PolicyType> RequiredPolicies => Array.Empty<PolicyType>();
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IMailService _mailService;
@ -39,7 +38,7 @@ public class SingleOrgPolicyDefinition : IPolicyDefinition
public async Task OnSaveSideEffectsAsync(Policy? currentPolicy, Policy modifiedPolicy)
{
if (currentPolicy is null or { Enabled: false } && modifiedPolicy is { Enabled: true })
if (currentPolicy is not { Enabled: true } && modifiedPolicy is { Enabled: true })
{
await RemoveNonCompliantUsersAsync(modifiedPolicy.OrganizationId);
}

View File

@ -0,0 +1,82 @@
#nullable enable
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Services;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
public class TwoFactorAuthenticationPolicyDefinition : IPolicyDefinition
{
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IMailService _mailService;
private readonly IOrganizationRepository _organizationRepository;
private readonly ICurrentContext _currentContext;
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
private readonly IRemoveOrganizationUserCommand _removeOrganizationUserCommand;
public PolicyType Type => PolicyType.TwoFactorAuthentication;
public TwoFactorAuthenticationPolicyDefinition(
IOrganizationUserRepository organizationUserRepository,
IMailService mailService,
IOrganizationRepository organizationRepository,
ICurrentContext currentContext,
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
IRemoveOrganizationUserCommand removeOrganizationUserCommand)
{
_organizationUserRepository = organizationUserRepository;
_mailService = mailService;
_organizationRepository = organizationRepository;
_currentContext = currentContext;
_twoFactorIsEnabledQuery = twoFactorIsEnabledQuery;
_removeOrganizationUserCommand = removeOrganizationUserCommand;
}
public async Task OnSaveSideEffectsAsync(Policy? currentPolicy, Policy modifiedPolicy)
{
if (currentPolicy is not { Enabled: true } && modifiedPolicy is { Enabled: true })
{
await RemoveNonCompliantUsersAsync(modifiedPolicy.OrganizationId);
}
}
private async Task RemoveNonCompliantUsersAsync(Guid organizationId)
{
var org = await _organizationRepository.GetByIdAsync(organizationId);
var savingUserId = _currentContext.UserId;
var orgUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId);
var organizationUsersTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(orgUsers);
var removableOrgUsers = orgUsers.Where(ou =>
ou.Status != OrganizationUserStatusType.Invited && ou.Status != OrganizationUserStatusType.Revoked &&
ou.Type != OrganizationUserType.Owner && ou.Type != OrganizationUserType.Admin &&
ou.UserId != savingUserId);
// Reorder by HasMasterPassword to prioritize checking users without a master if they have 2FA enabled
foreach (var orgUser in removableOrgUsers.OrderBy(ou => ou.HasMasterPassword))
{
var userTwoFactorEnabled = organizationUsersTwoFactorEnabled.FirstOrDefault(u => u.user.Id == orgUser.Id)
.twoFactorIsEnabled;
if (!userTwoFactorEnabled)
{
if (!orgUser.HasMasterPassword)
{
throw new BadRequestException(
"Policy could not be enabled. Non-compliant members will lose access to their accounts. Identify members without two-step login from the policies column in the members page.");
}
await _removeOrganizationUserCommand.RemoveUserAsync(organizationId, orgUser.Id,
savingUserId);
await _mailService.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(
org!.DisplayName(), orgUser.Email);
}
}
}
}

View File

@ -11,6 +11,19 @@ public static class PolicyServiceCollectionExtensions
{
services.AddScoped<IPolicyService, PolicyService>();
services.AddScoped<IPolicyServicevNext, PolicyServicevNext>();
services.AddScoped<IPolicyDefinition, TwoFactorAuthenticationPolicyDefinition>();
services.AddScoped<IPolicyDefinition, MasterPasswordPolicyDefinition>();
services.AddScoped<IPolicyDefinition, PasswordGeneratorPolicyDefinition>();
services.AddScoped<IPolicyDefinition, SingleOrgPolicyDefinition>();
services.AddScoped<IPolicyDefinition, RequireSsoPolicyDefinition>();
services.AddScoped<IPolicyDefinition, PersonalOwnershipPolicyDefinition>();
services.AddScoped<IPolicyDefinition, DisableSendPolicyDefinition>();
services.AddScoped<IPolicyDefinition, SendOptionsPolicyDefinition>();
services.AddScoped<IPolicyDefinition, ResetPasswordPolicyDefinition>();
services.AddScoped<IPolicyDefinition, MaximumVaultTimeoutPolicyDefinition>();
services.AddScoped<IPolicyDefinition, DisablePersonalVaultExportPolicyDefinition>();
services.AddScoped<IPolicyDefinition, ActivateAutofillPolicyDefinition>();
services.AddScoped<IPolicyDefinition, AutomaticAppLogInPolicyDefinition>();
}
}