1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-04 01:22:50 -05:00

Merge branch 'master' into feature/families-for-enterprise

This commit is contained in:
Justin Baur
2021-11-18 08:32:28 -05:00
59 changed files with 4250 additions and 129 deletions

View File

@ -62,10 +62,15 @@ namespace Bit.Core.Services
public async Task<EmergencyAccess> InviteAsync(User invitingUser, string email, EmergencyAccessType type, int waitTime)
{
if (! await _userService.CanAccessPremium(invitingUser))
if (!await _userService.CanAccessPremium(invitingUser))
{
throw new BadRequestException("Not a premium user.");
}
if (type == EmergencyAccessType.Takeover && invitingUser.UsesKeyConnector)
{
throw new BadRequestException("You cannot use Emergency Access Takeover because you are using Key Connector.");
}
var emergencyAccess = new EmergencyAccess
{
@ -171,6 +176,11 @@ namespace Bit.Core.Services
}
var grantor = await _userRepository.GetByIdAsync(confirmingUserId);
if (emergencyAccess.Type == EmergencyAccessType.Takeover && grantor.UsesKeyConnector)
{
throw new BadRequestException("You cannot use Emergency Access Takeover because you are using Key Connector.");
}
var grantee = await _userRepository.GetByIdAsync(emergencyAccess.GranteeId.Value);
emergencyAccess.Status = EmergencyAccessStatusType.Confirmed;
@ -188,7 +198,16 @@ namespace Bit.Core.Services
{
throw new BadRequestException("Emergency Access not valid.");
}
if (emergencyAccess.Type == EmergencyAccessType.Takeover)
{
var grantor = await _userService.GetUserByIdAsync(emergencyAccess.GrantorId);
if (grantor.UsesKeyConnector)
{
throw new BadRequestException("You cannot use Emergency Access Takeover because you are using Key Connector.");
}
}
await _emergencyAccessRepository.ReplaceAsync(emergencyAccess);
}
@ -202,6 +221,13 @@ namespace Bit.Core.Services
throw new BadRequestException("Emergency Access not valid.");
}
var grantor = await _userRepository.GetByIdAsync(emergencyAccess.GrantorId);
if (emergencyAccess.Type == EmergencyAccessType.Takeover && grantor.UsesKeyConnector)
{
throw new BadRequestException("You cannot takeover an account that is using Key Connector.");
}
var now = DateTime.UtcNow;
emergencyAccess.Status = EmergencyAccessStatusType.RecoveryInitiated;
emergencyAccess.RevisionDate = now;
@ -209,8 +235,6 @@ namespace Bit.Core.Services
emergencyAccess.LastNotificationDate = now;
await _emergencyAccessRepository.ReplaceAsync(emergencyAccess);
var grantor = await _userRepository.GetByIdAsync(emergencyAccess.GrantorId);
await _mailService.SendEmergencyAccessRecoveryInitiated(emergencyAccess, NameOrEmail(initiatingUser), grantor.Email);
}
@ -277,7 +301,12 @@ namespace Bit.Core.Services
}
var grantor = await _userRepository.GetByIdAsync(emergencyAccess.GrantorId);
if (emergencyAccess.Type == EmergencyAccessType.Takeover && grantor.UsesKeyConnector)
{
throw new BadRequestException("You cannot takeover an account that is using Key Connector.");
}
return (emergencyAccess, grantor);
}

View File

@ -247,6 +247,16 @@ namespace Bit.Core.Services
}
}
if (!newPlan.HasKeyConnector && organization.UseKeyConnector)
{
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(organization.Id);
if (ssoConfig != null && ssoConfig.GetData().KeyConnectorEnabled)
{
throw new BadRequestException("Your new plan does not allow the Key Connector feature. " +
"Disable your Key Connector.");
}
}
if (!newPlan.HasResetPassword && organization.UseResetPassword)
{
var resetPasswordPolicy =
@ -295,6 +305,7 @@ namespace Bit.Core.Services
organization.Use2fa = newPlan.Has2fa;
organization.UseApi = newPlan.HasApi;
organization.UseSso = newPlan.HasSso;
organization.UseKeyConnector = newPlan.HasKeyConnector;
organization.UseResetPassword = newPlan.HasResetPassword;
organization.SelfHost = newPlan.HasSelfHost;
organization.UsersGetPremium = newPlan.UsersGetPremium || upgrade.PremiumAccessAddon;
@ -687,6 +698,7 @@ namespace Bit.Core.Services
MaxStorageGb = _globalSettings.SelfHosted ? 10240 : license.MaxStorageGb, // 10 TB
UsePolicies = license.UsePolicies,
UseSso = license.UseSso,
UseKeyConnector = license.UseKeyConnector,
UseGroups = license.UseGroups,
UseDirectory = license.UseDirectory,
UseEvents = license.UseEvents,
@ -865,6 +877,16 @@ namespace Bit.Core.Services
}
}
if (!license.UseKeyConnector && organization.UseKeyConnector)
{
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(organization.Id);
if (ssoConfig != null && ssoConfig.GetData().KeyConnectorEnabled)
{
throw new BadRequestException($"Your organization currently has Key Connector enabled. " +
$"Your new license does not allow for the use of Key Connector. Disable your Key Connector.");
}
}
if (!license.UseResetPassword && organization.UseResetPassword)
{
var resetPasswordPolicy =
@ -895,6 +917,7 @@ namespace Bit.Core.Services
organization.UseApi = license.UseApi;
organization.UsePolicies = license.UsePolicies;
organization.UseSso = license.UseSso;
organization.UseKeyConnector = license.UseKeyConnector;
organization.UseResetPassword = license.UseResetPassword;
organization.SelfHost = license.SelfHost;
organization.UsersGetPremium = license.UsersGetPremium;
@ -2156,7 +2179,7 @@ namespace Bit.Core.Services
private async Task ValidateDeleteOrganizationAsync(Organization organization)
{
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(organization.Id);
if (ssoConfig?.GetData()?.UseKeyConnector == true)
if (ssoConfig?.GetData()?.KeyConnectorEnabled == true)
{
throw new BadRequestException("You cannot delete an Organization that is using Key Connector.");
}

View File

@ -54,37 +54,27 @@ namespace Bit.Core.Services
case PolicyType.SingleOrg:
if (!policy.Enabled)
{
var requireSso =
await _policyRepository.GetByOrganizationIdTypeAsync(org.Id, PolicyType.RequireSso);
if (requireSso?.Enabled == true)
{
throw new BadRequestException("Single Sign-On Authentication policy is enabled.");
}
var vaultTimeout =
await _policyRepository.GetByOrganizationIdTypeAsync(org.Id, PolicyType.MaximumVaultTimeout);
if (vaultTimeout?.Enabled == true)
{
throw new BadRequestException("Maximum Vault Timeout policy is enabled.");
}
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(org.Id);
if (ssoConfig?.GetData()?.UseKeyConnector == true)
{
throw new BadRequestException("KeyConnector is 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)
{
var singleOrg = await _policyRepository.GetByOrganizationIdTypeAsync(org.Id, PolicyType.SingleOrg);
if (singleOrg?.Enabled != true)
{
throw new BadRequestException("Single Organization policy not enabled.");
}
await DependsOnSingleOrgAsync(org);
}
break;
}
@ -144,5 +134,42 @@ namespace Bit.Core.Services
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.");
}
}
}
}

View File

@ -30,7 +30,7 @@ namespace Bit.Core.Services
_eventService = eventService;
}
public async Task SaveAsync(SsoConfig config)
public async Task SaveAsync(SsoConfig config, Organization organization)
{
var now = DateTime.UtcNow;
config.RevisionDate = now;
@ -39,14 +39,14 @@ namespace Bit.Core.Services
config.CreationDate = now;
}
var useKeyConnector = config.GetData().UseKeyConnector;
var useKeyConnector = config.GetData().KeyConnectorEnabled;
if (useKeyConnector)
{
await VerifyDependenciesAsync(config);
await VerifyDependenciesAsync(config, organization);
}
var oldConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(config.OrganizationId);
var disabledKeyConnector = oldConfig?.GetData()?.UseKeyConnector == true && !useKeyConnector;
var disabledKeyConnector = oldConfig?.GetData()?.KeyConnectorEnabled == true && !useKeyConnector;
if (disabledKeyConnector && await AnyOrgUserHasKeyConnectorEnabledAsync(config.OrganizationId))
{
throw new BadRequestException("Key Connector cannot be disabled at this moment.");
@ -63,12 +63,27 @@ namespace Bit.Core.Services
return userDetails.Any(u => u.UsesKeyConnector);
}
private async Task VerifyDependenciesAsync(SsoConfig config)
private async Task VerifyDependenciesAsync(SsoConfig config, Organization organization)
{
var policy = await _policyRepository.GetByOrganizationIdTypeAsync(config.OrganizationId, PolicyType.SingleOrg);
if (policy is not { Enabled: true })
if (!organization.UseKeyConnector)
{
throw new BadRequestException("KeyConnector requires Single Organization to be enabled.");
throw new BadRequestException("Organization cannot use Key Connector.");
}
var singleOrgPolicy = await _policyRepository.GetByOrganizationIdTypeAsync(config.OrganizationId, PolicyType.SingleOrg);
if (singleOrgPolicy is not { Enabled: true })
{
throw new BadRequestException("Key Connector requires the Single Organization policy to be enabled.");
}
var ssoPolicy = await _policyRepository.GetByOrganizationIdTypeAsync(config.OrganizationId, PolicyType.RequireSso);
if (ssoPolicy is not { Enabled: true })
{
throw new BadRequestException("Key Connector requires the Single Sign-On Authentication policy to be enabled.");
}
if (!config.Enabled) {
throw new BadRequestException("You must enable SSO to use Key Connector.");
}
}
@ -81,10 +96,10 @@ namespace Bit.Core.Services
await _eventService.LogOrganizationEventAsync(organization, e);
}
var useKeyConnector = config.GetData().UseKeyConnector;
if (oldConfig?.GetData()?.UseKeyConnector != useKeyConnector)
var keyConnectorEnabled = config.GetData().KeyConnectorEnabled;
if (oldConfig?.GetData()?.KeyConnectorEnabled != keyConnectorEnabled)
{
var e = useKeyConnector
var e = keyConnectorEnabled
? EventType.Organization_EnabledKeyConnector
: EventType.Organization_DisabledKeyConnector;
await _eventService.LogOrganizationEventAsync(organization, e);

View File

@ -646,7 +646,7 @@ namespace Bit.Core.Services
if (user.UsesKeyConnector)
{
Logger.LogWarning("Already uses key connector.");
Logger.LogWarning("Already uses Key Connector.");
return IdentityResult.Failed(_identityErrorDescriber.UserAlreadyHasPassword());
}
@ -671,7 +671,7 @@ namespace Bit.Core.Services
if (user.UsesKeyConnector)
{
Logger.LogWarning("Already uses key connector.");
Logger.LogWarning("Already uses Key Connector.");
return IdentityResult.Failed(_identityErrorDescriber.UserAlreadyHasPassword());
}
@ -740,7 +740,7 @@ namespace Bit.Core.Services
if (user.UsesKeyConnector)
{
throw new BadRequestException("Cannot reset password of a user with key connector.");
throw new BadRequestException("Cannot reset password of a user with Key Connector.");
}
var result = await UpdatePasswordHash(user, newMasterPassword);
@ -1387,7 +1387,7 @@ namespace Bit.Core.Services
if (!user.UsesKeyConnector)
{
throw new BadRequestException("Not using key connector.");
throw new BadRequestException("Not using Key Connector.");
}
var token = await base.GenerateUserTokenAsync(user, TokenOptions.DefaultEmailProvider,