1
0
mirror of https://github.com/bitwarden/server synced 2025-12-14 23:33:41 +00:00
Files
server/src/Core/Services/Implementations/PolicyService.cs
Jake Fink 88dd745070 [PM-1188] Server owner auth migration (#2825)
* [PM-1188] add sso project to auth

* [PM-1188] move sso api models to auth

* [PM-1188] fix sso api model namespace & imports

* [PM-1188] move core files to auth

* [PM-1188] fix core sso namespace & models

* [PM-1188] move sso repository files to auth

* [PM-1188] fix sso repo files namespace & imports

* [PM-1188] move sso sql files to auth folder

* [PM-1188] move sso test files to auth folders

* [PM-1188] fix sso tests namespace & imports

* [PM-1188] move auth api files to auth folder

* [PM-1188] fix auth api files namespace & imports

* [PM-1188] move auth core files to auth folder

* [PM-1188] fix auth core files namespace & imports

* [PM-1188] move auth email templates to auth folder

* [PM-1188] move auth email folder back into shared directory

* [PM-1188] fix auth email names

* [PM-1188] move auth core models to auth folder

* [PM-1188] fix auth model namespace & imports

* [PM-1188] add entire Identity project to auth codeowners

* [PM-1188] fix auth orm files namespace & imports

* [PM-1188] move auth orm files to auth folder

* [PM-1188] move auth sql files to auth folder

* [PM-1188] move auth tests to auth folder

* [PM-1188] fix auth test files namespace & imports

* [PM-1188] move emergency access api files to auth folder

* [PM-1188] fix emergencyaccess api files namespace & imports

* [PM-1188] move emergency access core files to auth folder

* [PM-1188] fix emergency access core files namespace & imports

* [PM-1188] move emergency access orm files to auth folder

* [PM-1188] fix emergency access orm files namespace & imports

* [PM-1188] move emergency access sql files to auth folder

* [PM-1188] move emergencyaccess test files to auth folder

* [PM-1188] fix emergency access test files namespace & imports

* [PM-1188] move captcha files to auth folder

* [PM-1188] fix captcha files namespace & imports

* [PM-1188] move auth admin files into auth folder

* [PM-1188] fix admin auth files namespace & imports
- configure mvc to look in auth folders for views

* [PM-1188] remove extra imports and formatting

* [PM-1188] fix ef auth model imports

* [PM-1188] fix DatabaseContextModelSnapshot paths

* [PM-1188] fix grant import in ef

* [PM-1188] update sqlproj

* [PM-1188] move missed sqlproj files

* [PM-1188] move auth ef models out of auth folder

* [PM-1188] fix auth ef models namespace

* [PM-1188] remove auth ef models unused imports

* [PM-1188] fix imports for auth ef models

* [PM-1188] fix more ef model imports

* [PM-1188] fix file encodings
2023-04-14 13:25:56 -04:00

189 lines
7.2 KiB
C#

using Bit.Core.Auth.Repositories;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
namespace Bit.Core.Services;
public class PolicyService : IPolicyService
{
private readonly IEventService _eventService;
private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IPolicyRepository _policyRepository;
private readonly ISsoConfigRepository _ssoConfigRepository;
private readonly IMailService _mailService;
public PolicyService(
IEventService eventService,
IOrganizationRepository organizationRepository,
IOrganizationUserRepository organizationUserRepository,
IPolicyRepository policyRepository,
ISsoConfigRepository ssoConfigRepository,
IMailService mailService)
{
_eventService = eventService;
_organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository;
_policyRepository = policyRepository;
_ssoConfigRepository = ssoConfigRepository;
_mailService = mailService;
}
public async Task SaveAsync(Policy policy, IUserService userService, IOrganizationService organizationService,
Guid? savingUserId)
{
var org = await _organizationRepository.GetByIdAsync(policy.OrganizationId);
if (org == null)
{
throw new BadRequestException("Organization not found");
}
if (!org.UsePolicies)
{
throw new BadRequestException("This organization cannot use policies.");
}
// Handle dependent policy checks
switch (policy.Type)
{
case PolicyType.SingleOrg:
if (!policy.Enabled)
{
await RequiredBySsoAsync(org);
await RequiredByVaultTimeoutAsync(org);
await RequiredByKeyConnectorAsync(org);
}
break;
case PolicyType.RequireSso:
if (policy.Enabled)
{
await DependsOnSingleOrgAsync(org);
}
else
{
await RequiredByKeyConnectorAsync(org);
}
break;
case PolicyType.MaximumVaultTimeout:
if (policy.Enabled)
{
await DependsOnSingleOrgAsync(org);
}
break;
// Activate Autofill is only available to Enterprise 2020-current plans
case PolicyType.ActivateAutofill:
if (policy.Enabled)
{
LockedTo2020Plan(org);
}
break;
}
var now = DateTime.UtcNow;
if (policy.Id == default(Guid))
{
policy.CreationDate = now;
}
if (policy.Enabled)
{
var currentPolicy = await _policyRepository.GetByIdAsync(policy.Id);
if (!currentPolicy?.Enabled ?? true)
{
var orgUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(
policy.OrganizationId);
var removableOrgUsers = orgUsers.Where(ou =>
ou.Status != Enums.OrganizationUserStatusType.Invited && ou.Status != Enums.OrganizationUserStatusType.Revoked &&
ou.Type != Enums.OrganizationUserType.Owner && ou.Type != Enums.OrganizationUserType.Admin &&
ou.UserId != savingUserId);
switch (policy.Type)
{
case Enums.PolicyType.TwoFactorAuthentication:
foreach (var orgUser in removableOrgUsers)
{
if (!await userService.TwoFactorIsEnabledAsync(orgUser))
{
await organizationService.DeleteUserAsync(policy.OrganizationId, orgUser.Id,
savingUserId);
await _mailService.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(
org.Name, orgUser.Email);
}
}
break;
case Enums.PolicyType.SingleOrg:
var userOrgs = await _organizationUserRepository.GetManyByManyUsersAsync(
removableOrgUsers.Select(ou => ou.UserId.Value));
foreach (var orgUser in removableOrgUsers)
{
if (userOrgs.Any(ou => ou.UserId == orgUser.UserId
&& ou.OrganizationId != org.Id
&& ou.Status != OrganizationUserStatusType.Invited))
{
await organizationService.DeleteUserAsync(policy.OrganizationId, orgUser.Id,
savingUserId);
await _mailService.SendOrganizationUserRemovedForPolicySingleOrgEmailAsync(
org.Name, orgUser.Email);
}
}
break;
default:
break;
}
}
}
policy.RevisionDate = now;
await _policyRepository.UpsertAsync(policy);
await _eventService.LogPolicyEventAsync(policy, Enums.EventType.Policy_Updated);
}
private async Task DependsOnSingleOrgAsync(Organization org)
{
var singleOrg = await _policyRepository.GetByOrganizationIdTypeAsync(org.Id, PolicyType.SingleOrg);
if (singleOrg?.Enabled != true)
{
throw new BadRequestException("Single Organization policy not enabled.");
}
}
private async Task RequiredBySsoAsync(Organization org)
{
var requireSso = await _policyRepository.GetByOrganizationIdTypeAsync(org.Id, PolicyType.RequireSso);
if (requireSso?.Enabled == true)
{
throw new BadRequestException("Single Sign-On Authentication policy is enabled.");
}
}
private async Task RequiredByKeyConnectorAsync(Organization org)
{
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(org.Id);
if (ssoConfig?.GetData()?.KeyConnectorEnabled == true)
{
throw new BadRequestException("Key Connector is enabled.");
}
}
private async Task RequiredByVaultTimeoutAsync(Organization org)
{
var vaultTimeout = await _policyRepository.GetByOrganizationIdTypeAsync(org.Id, PolicyType.MaximumVaultTimeout);
if (vaultTimeout?.Enabled == true)
{
throw new BadRequestException("Maximum Vault Timeout policy is enabled.");
}
}
private void LockedTo2020Plan(Organization org)
{
if (org.PlanType != PlanType.EnterpriseAnnually && org.PlanType != PlanType.EnterpriseMonthly)
{
throw new BadRequestException("This policy is only available to 2020 Enterprise plans.");
}
}
}