mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 15:42:48 -05:00
Refactor permission checks in OrganizationsService to use currentContext (#1420)
This commit is contained in:
@ -552,7 +552,7 @@ namespace Bit.Api.Controllers
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
var org = await _organizationService.UpdateOrganizationKeysAsync(user.Id, new Guid(id), model.PublicKey, model.EncryptedPrivateKey);
|
||||
var org = await _organizationService.UpdateOrganizationKeysAsync(new Guid(id), model.PublicKey, model.EncryptedPrivateKey);
|
||||
return new OrganizationKeysResponseModel(org);
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,6 @@ namespace Bit.Core.Services
|
||||
bool overwriteExisting);
|
||||
Task RotateApiKeyAsync(Organization organization);
|
||||
Task DeleteSsoUserAsync(Guid userId, Guid? organizationId);
|
||||
Task<Organization> UpdateOrganizationKeysAsync(Guid userId, Guid orgId, string publicKey, string privateKey);
|
||||
Task<Organization> UpdateOrganizationKeysAsync(Guid orgId, string publicKey, string privateKey);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ using Bit.Core.Settings;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Context;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
@ -42,6 +42,7 @@ namespace Bit.Core.Services
|
||||
private readonly IReferenceEventService _referenceEventService;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ITaxRateRepository _taxRateRepository;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
public OrganizationService(
|
||||
IOrganizationRepository organizationRepository,
|
||||
@ -64,7 +65,8 @@ namespace Bit.Core.Services
|
||||
ISsoUserRepository ssoUserRepository,
|
||||
IReferenceEventService referenceEventService,
|
||||
GlobalSettings globalSettings,
|
||||
ITaxRateRepository taxRateRepository)
|
||||
ITaxRateRepository taxRateRepository,
|
||||
ICurrentContext currentContext)
|
||||
{
|
||||
_organizationRepository = organizationRepository;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
@ -87,6 +89,7 @@ namespace Bit.Core.Services
|
||||
_referenceEventService = referenceEventService;
|
||||
_globalSettings = globalSettings;
|
||||
_taxRateRepository = taxRateRepository;
|
||||
_currentContext = currentContext;
|
||||
}
|
||||
|
||||
public async Task ReplacePaymentMethodAsync(Guid organizationId, string paymentToken,
|
||||
@ -1048,7 +1051,7 @@ namespace Bit.Core.Services
|
||||
{
|
||||
foreach (var type in inviteTypes)
|
||||
{
|
||||
await ValidateOrganizationUserUpdatePermissionsAsync(invitingUserId.Value, organizationId, type, null);
|
||||
ValidateOrganizationUserUpdatePermissions(organizationId, type, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1155,7 +1158,7 @@ namespace Bit.Core.Services
|
||||
|
||||
if (invitingUserId.HasValue && invite.Type.HasValue)
|
||||
{
|
||||
await ValidateOrganizationUserUpdatePermissionsAsync(invitingUserId.Value, organizationId, invite.Type.Value, null);
|
||||
ValidateOrganizationUserUpdatePermissions(organizationId, invite.Type.Value, null);
|
||||
}
|
||||
|
||||
if (organization.Seats.HasValue)
|
||||
@ -1529,7 +1532,7 @@ namespace Bit.Core.Services
|
||||
|
||||
if (savingUserId.HasValue)
|
||||
{
|
||||
await ValidateOrganizationUserUpdatePermissionsAsync(savingUserId.Value, user.OrganizationId, user.Type, originalUser.Type);
|
||||
ValidateOrganizationUserUpdatePermissions(user.OrganizationId, user.Type, originalUser.Type);
|
||||
}
|
||||
|
||||
if (user.Type != OrganizationUserType.Owner &&
|
||||
@ -1561,7 +1564,7 @@ namespace Bit.Core.Services
|
||||
}
|
||||
|
||||
if (orgUser.Type == OrganizationUserType.Owner && deletingUserId.HasValue &&
|
||||
!await UserIsOwnerAsync(organizationId, deletingUserId.Value))
|
||||
!_currentContext.OrganizationOwner(organizationId))
|
||||
{
|
||||
throw new BadRequestException("Only owners can delete other owners.");
|
||||
}
|
||||
@ -1623,7 +1626,7 @@ namespace Bit.Core.Services
|
||||
var deletingUserIsOwner = false;
|
||||
if (deletingUserId.HasValue)
|
||||
{
|
||||
deletingUserIsOwner = await UserIsOwnerAsync(organizationId, deletingUserId.Value);
|
||||
deletingUserIsOwner = _currentContext.OrganizationOwner(organizationId);
|
||||
}
|
||||
|
||||
var result = new List<Tuple<OrganizationUser, string>>();
|
||||
@ -1669,17 +1672,11 @@ namespace Bit.Core.Services
|
||||
return confirmedOwnersIds.Except(organizationUsersId).Any();
|
||||
}
|
||||
|
||||
private async Task<bool> UserIsOwnerAsync(Guid organizationId, Guid deletingUserId)
|
||||
{
|
||||
var deletingUserOrgs = await _organizationUserRepository.GetManyByUserAsync(deletingUserId);
|
||||
return deletingUserOrgs.Any(u => u.OrganizationId == organizationId && u.Type == OrganizationUserType.Owner);
|
||||
}
|
||||
|
||||
public async Task UpdateUserGroupsAsync(OrganizationUser organizationUser, IEnumerable<Guid> groupIds, Guid? loggedInUserId)
|
||||
{
|
||||
if (loggedInUserId.HasValue)
|
||||
{
|
||||
await ValidateOrganizationUserUpdatePermissionsAsync(loggedInUserId.Value, organizationUser.OrganizationId, organizationUser.Type, null);
|
||||
ValidateOrganizationUserUpdatePermissions(organizationUser.OrganizationId, organizationUser.Type, null);
|
||||
}
|
||||
await _organizationUserRepository.UpdateGroupsAsync(organizationUser.Id, groupIds);
|
||||
await _eventService.LogOrganizationUserEventAsync(organizationUser,
|
||||
@ -1962,25 +1959,13 @@ namespace Bit.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Organization> UpdateOrganizationKeysAsync(Guid userId, Guid orgId, string publicKey, string privateKey)
|
||||
public async Task<Organization> UpdateOrganizationKeysAsync(Guid orgId, string publicKey, string privateKey)
|
||||
{
|
||||
// Only Owners/Admins/Custom (w/ ManageResetPassword) can create org keys
|
||||
var orgUser = await _organizationUserRepository.GetDetailsByUserAsync(userId, orgId);
|
||||
if (orgUser == null || orgUser.Type != OrganizationUserType.Admin &&
|
||||
orgUser.Type != OrganizationUserType.Owner && orgUser.Type != OrganizationUserType.Custom)
|
||||
if (_currentContext.ManageResetPassword(orgId))
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
if (orgUser.Type == OrganizationUserType.Custom)
|
||||
{
|
||||
var permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(orgUser.Permissions);
|
||||
if (permissions == null || !permissions.ManageResetPassword)
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
}
|
||||
|
||||
// If the keys already exist, error out
|
||||
var org = await _organizationRepository.GetByIdAsync(orgId);
|
||||
if (org.PublicKey != null && org.PrivateKey != null)
|
||||
@ -2087,56 +2072,35 @@ namespace Bit.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ValidateOrganizationUserUpdatePermissionsAsync(Guid loggedInUserId, Guid organizationId,
|
||||
OrganizationUserType newType, OrganizationUserType? oldType)
|
||||
private void ValidateOrganizationUserUpdatePermissions(Guid organizationId, OrganizationUserType newType,
|
||||
OrganizationUserType? oldType)
|
||||
{
|
||||
var loggedInUserOrgs = await _organizationUserRepository.GetManyByUserAsync(loggedInUserId);
|
||||
var loggedInAsOrgOwner = loggedInUserOrgs
|
||||
.Any(u => u.OrganizationId == organizationId && u.Type == OrganizationUserType.Owner);
|
||||
if (loggedInAsOrgOwner)
|
||||
if (_currentContext.OrganizationOwner(organizationId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var isOwner = oldType == OrganizationUserType.Owner;
|
||||
var nowOwner = newType == OrganizationUserType.Owner;
|
||||
var ownerUserConfigurationAttempt = (isOwner && nowOwner) || !(isOwner.Equals(nowOwner));
|
||||
if (ownerUserConfigurationAttempt)
|
||||
if (oldType == OrganizationUserType.Owner || newType == OrganizationUserType.Owner)
|
||||
{
|
||||
throw new BadRequestException("Only an Owner can configure another Owner's account.");
|
||||
}
|
||||
|
||||
var loggedInAsOrgAdmin = loggedInUserOrgs.Any(u => u.OrganizationId == organizationId && u.Type == OrganizationUserType.Admin);
|
||||
if (loggedInAsOrgAdmin)
|
||||
if (_currentContext.OrganizationAdmin(organizationId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var isCustom = oldType == OrganizationUserType.Custom;
|
||||
var nowCustom = newType == OrganizationUserType.Custom;
|
||||
var customUserConfigurationAttempt = (isCustom && nowCustom) || !(isCustom.Equals(nowCustom));
|
||||
if (customUserConfigurationAttempt)
|
||||
if (oldType == OrganizationUserType.Custom || newType == OrganizationUserType.Custom)
|
||||
{
|
||||
throw new BadRequestException("Only Owners and Admins can configure Custom accounts.");
|
||||
}
|
||||
|
||||
var loggedInAsOrgCustom = loggedInUserOrgs.Any(u => u.OrganizationId == organizationId && u.Type == OrganizationUserType.Custom);
|
||||
if (!loggedInAsOrgCustom)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var loggedInCustomOrgUser = loggedInUserOrgs.First(u => u.OrganizationId == organizationId && u.Type == OrganizationUserType.Custom);
|
||||
var loggedInUserPermissions = CoreHelpers.LoadClassFromJsonData<Permissions>(loggedInCustomOrgUser.Permissions);
|
||||
if (!loggedInUserPermissions.ManageUsers)
|
||||
if (!_currentContext.ManageUsers(organizationId))
|
||||
{
|
||||
throw new BadRequestException("Your account does not have permission to manage users.");
|
||||
}
|
||||
|
||||
var isAdmin = oldType == OrganizationUserType.Admin;
|
||||
var nowAdmin = newType == OrganizationUserType.Admin;
|
||||
var adminUserConfigurationAttempt = (isAdmin && nowAdmin) || !(isAdmin.Equals(nowAdmin));
|
||||
if (adminUserConfigurationAttempt)
|
||||
if (oldType == OrganizationUserType.Admin || newType == OrganizationUserType.Admin)
|
||||
{
|
||||
throw new BadRequestException("Custom users can not manage Admins or Owners.");
|
||||
}
|
||||
|
Reference in New Issue
Block a user