mirror of
https://github.com/bitwarden/server.git
synced 2025-07-04 09:32:48 -05:00
[PM-17733] - [Privilege Escalation] - Unauthorised access allows limited access user to change password of Items (#5452)
* prevent view-only users from updating passwords * revert change to licensing service * add tests * check if organizationId is there * move logic to private method * move logic to private method * move logic into method * revert change to licensing service * throw exception when cipher key is created by hidden password users * fix tests * don't allow totp or passkeys changes from hidden password users * add tests * revert change to licensing service
This commit is contained in:
@ -13,7 +13,9 @@ using Bit.Core.Tools.Models.Business;
|
||||
using Bit.Core.Tools.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Core.Vault.Enums;
|
||||
using Bit.Core.Vault.Models.Data;
|
||||
using Bit.Core.Vault.Queries;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
|
||||
namespace Bit.Core.Vault.Services;
|
||||
@ -38,6 +40,7 @@ public class CipherService : ICipherService
|
||||
private const long _fileSizeLeeway = 1024L * 1024L; // 1MB
|
||||
private readonly IReferenceEventService _referenceEventService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IGetCipherPermissionsForUserQuery _getCipherPermissionsForUserQuery;
|
||||
|
||||
public CipherService(
|
||||
ICipherRepository cipherRepository,
|
||||
@ -54,7 +57,8 @@ public class CipherService : ICipherService
|
||||
IPolicyService policyService,
|
||||
GlobalSettings globalSettings,
|
||||
IReferenceEventService referenceEventService,
|
||||
ICurrentContext currentContext)
|
||||
ICurrentContext currentContext,
|
||||
IGetCipherPermissionsForUserQuery getCipherPermissionsForUserQuery)
|
||||
{
|
||||
_cipherRepository = cipherRepository;
|
||||
_folderRepository = folderRepository;
|
||||
@ -71,6 +75,7 @@ public class CipherService : ICipherService
|
||||
_globalSettings = globalSettings;
|
||||
_referenceEventService = referenceEventService;
|
||||
_currentContext = currentContext;
|
||||
_getCipherPermissionsForUserQuery = getCipherPermissionsForUserQuery;
|
||||
}
|
||||
|
||||
public async Task SaveAsync(Cipher cipher, Guid savingUserId, DateTime? lastKnownRevisionDate,
|
||||
@ -161,6 +166,7 @@ public class CipherService : ICipherService
|
||||
{
|
||||
ValidateCipherLastKnownRevisionDateAsync(cipher, lastKnownRevisionDate);
|
||||
cipher.RevisionDate = DateTime.UtcNow;
|
||||
await ValidateViewPasswordUserAsync(cipher);
|
||||
await _cipherRepository.ReplaceAsync(cipher);
|
||||
await _eventService.LogCipherEventAsync(cipher, Bit.Core.Enums.EventType.Cipher_Updated);
|
||||
|
||||
@ -966,4 +972,32 @@ public class CipherService : ICipherService
|
||||
|
||||
ValidateCipherLastKnownRevisionDateAsync(cipher, lastKnownRevisionDate);
|
||||
}
|
||||
|
||||
private async Task ValidateViewPasswordUserAsync(Cipher cipher)
|
||||
{
|
||||
if (cipher.Type != CipherType.Login || cipher.Data == null || !cipher.OrganizationId.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var existingCipher = await _cipherRepository.GetByIdAsync(cipher.Id);
|
||||
if (existingCipher == null) return;
|
||||
|
||||
var cipherPermissions = await _getCipherPermissionsForUserQuery.GetByOrganization(cipher.OrganizationId.Value);
|
||||
// Check if user is a "hidden password" user
|
||||
if (!cipherPermissions.TryGetValue(cipher.Id, out var permission) || !(permission.ViewPassword && permission.Edit))
|
||||
{
|
||||
// "hidden password" users may not add cipher key encryption
|
||||
if (existingCipher.Key == null && cipher.Key != null)
|
||||
{
|
||||
throw new BadRequestException("You do not have permission to add cipher key encryption.");
|
||||
}
|
||||
// "hidden password" users may not change passwords, TOTP codes, or passkeys, so we need to set them back to the original values
|
||||
var existingCipherData = JsonSerializer.Deserialize<CipherLoginData>(existingCipher.Data);
|
||||
var newCipherData = JsonSerializer.Deserialize<CipherLoginData>(cipher.Data);
|
||||
newCipherData.Fido2Credentials = existingCipherData.Fido2Credentials;
|
||||
newCipherData.Totp = existingCipherData.Totp;
|
||||
newCipherData.Password = existingCipherData.Password;
|
||||
cipher.Data = JsonSerializer.Serialize(newCipherData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user