mirror of
https://github.com/bitwarden/server.git
synced 2025-02-23 03:01:23 +01:00
permission checks for cipher crud operations
This commit is contained in:
parent
0dae19bd4f
commit
10c72fafda
@ -127,7 +127,7 @@ namespace Bit.Api.Controllers
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
await _cipherService.DeleteAsync(cipher);
|
await _cipherService.DeleteAsync(cipher, userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ namespace Bit.Api.Controllers
|
|||||||
{
|
{
|
||||||
var userId = _userService.GetProperUserId(User).Value;
|
var userId = _userService.GetProperUserId(User).Value;
|
||||||
var login = model.ToCipherDetails(userId);
|
var login = model.ToCipherDetails(userId);
|
||||||
await _cipherService.SaveAsync(login);
|
await _cipherService.SaveAsync(login, userId);
|
||||||
|
|
||||||
var response = new LoginResponseModel(login);
|
var response = new LoginResponseModel(login);
|
||||||
return response;
|
return response;
|
||||||
@ -76,7 +76,7 @@ namespace Bit.Api.Controllers
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
await _cipherService.SaveAsync(model.ToCipherDetails(login));
|
await _cipherService.SaveAsync(model.ToCipherDetails(login), userId);
|
||||||
|
|
||||||
var response = new LoginResponseModel(login);
|
var response = new LoginResponseModel(login);
|
||||||
return response;
|
return response;
|
||||||
@ -86,13 +86,14 @@ namespace Bit.Api.Controllers
|
|||||||
[HttpPost("{id}/delete")]
|
[HttpPost("{id}/delete")]
|
||||||
public async Task Delete(string id)
|
public async Task Delete(string id)
|
||||||
{
|
{
|
||||||
var login = await _cipherRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value);
|
var userId = _userService.GetProperUserId(User).Value;
|
||||||
|
var login = await _cipherRepository.GetByIdAsync(new Guid(id), userId);
|
||||||
if(login == null || login.Type != Core.Enums.CipherType.Login)
|
if(login == null || login.Type != Core.Enums.CipherType.Login)
|
||||||
{
|
{
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
await _cipherService.DeleteAsync(login);
|
await _cipherService.DeleteAsync(login, userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,5 +12,6 @@ namespace Bit.Core.Repositories
|
|||||||
Task<ICollection<SubvaultUserDetails>> GetManyDetailsByUserIdAsync(Guid userId);
|
Task<ICollection<SubvaultUserDetails>> GetManyDetailsByUserIdAsync(Guid userId);
|
||||||
Task<ICollection<SubvaultUserPermissions>> GetPermissionsByUserIdAsync(Guid userId, IEnumerable<Guid> subvaultIds,
|
Task<ICollection<SubvaultUserPermissions>> GetPermissionsByUserIdAsync(Guid userId, IEnumerable<Guid> subvaultIds,
|
||||||
Guid organizationId);
|
Guid organizationId);
|
||||||
|
Task<bool> GetIsAdminByUserIdCipherIdAsync(Guid userId, Guid cipherId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,5 +60,18 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
return results.ToList();
|
return results.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> GetIsAdminByUserIdCipherIdAsync(Guid userId, Guid cipherId)
|
||||||
|
{
|
||||||
|
using(var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var result = await connection.QueryFirstOrDefaultAsync<bool>(
|
||||||
|
$"[{Schema}].[SubvaultUser_ReadIsAdminByCipherIdUserId]",
|
||||||
|
new { UserId = userId, CipherId = cipherId },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
public interface ICipherService
|
public interface ICipherService
|
||||||
{
|
{
|
||||||
Task SaveAsync(CipherDetails cipher);
|
Task SaveAsync(CipherDetails cipher, Guid savingUserId);
|
||||||
Task DeleteAsync(Cipher cipher);
|
Task DeleteAsync(CipherDetails cipher, Guid deletingUserId);
|
||||||
Task SaveFolderAsync(Folder folder);
|
Task SaveFolderAsync(Folder folder);
|
||||||
Task DeleteFolderAsync(Folder folder);
|
Task DeleteFolderAsync(Folder folder);
|
||||||
Task MoveSubvaultAsync(Cipher cipher, IEnumerable<Guid> subvaultIds, Guid userId);
|
Task MoveSubvaultAsync(Cipher cipher, IEnumerable<Guid> subvaultIds, Guid userId);
|
||||||
|
@ -37,8 +37,14 @@ namespace Bit.Core.Services
|
|||||||
_pushService = pushService;
|
_pushService = pushService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveAsync(CipherDetails cipher)
|
public async Task SaveAsync(CipherDetails cipher, Guid savingUserId)
|
||||||
{
|
{
|
||||||
|
if(!(await UserHasAdminRights(cipher, savingUserId)))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Not an admin.");
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher.UserId = savingUserId;
|
||||||
if(cipher.Id == default(Guid))
|
if(cipher.Id == default(Guid))
|
||||||
{
|
{
|
||||||
await _cipherRepository.CreateAsync(cipher);
|
await _cipherRepository.CreateAsync(cipher);
|
||||||
@ -56,8 +62,13 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteAsync(Cipher cipher)
|
public async Task DeleteAsync(CipherDetails cipher, Guid deletingUserId)
|
||||||
{
|
{
|
||||||
|
if(!(await UserHasAdminRights(cipher, deletingUserId)))
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Not an admin.");
|
||||||
|
}
|
||||||
|
|
||||||
await _cipherRepository.DeleteAsync(cipher);
|
await _cipherRepository.DeleteAsync(cipher);
|
||||||
|
|
||||||
// push
|
// push
|
||||||
@ -151,5 +162,15 @@ namespace Bit.Core.Services
|
|||||||
await _pushService.PushSyncCiphersAsync(userId.Value);
|
await _pushService.PushSyncCiphersAsync(userId.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<bool> UserHasAdminRights(CipherDetails cipher, Guid userId)
|
||||||
|
{
|
||||||
|
if(!cipher.OrganizationId.HasValue && cipher.UserId.HasValue && cipher.UserId.Value == userId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await _subvaultUserRepository.GetIsAdminByUserIdCipherIdAsync(userId, cipher.Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,5 +173,6 @@
|
|||||||
<Build Include="dbo\Stored Procedures\OrganizationUserUserDetails_ReadByOrganizationId.sql" />
|
<Build Include="dbo\Stored Procedures\OrganizationUserUserDetails_ReadByOrganizationId.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\Subvault_ReadByOrganizationIdAdminUserId.sql" />
|
<Build Include="dbo\Stored Procedures\Subvault_ReadByOrganizationIdAdminUserId.sql" />
|
||||||
<Build Include="dbo\User Defined Types\GuidIdArray.sql" />
|
<Build Include="dbo\User Defined Types\GuidIdArray.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\SubvaultUser_ReadIsAdminByCipherIdUserId.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -25,7 +25,7 @@ BEGIN
|
|||||||
VALUES
|
VALUES
|
||||||
(
|
(
|
||||||
@Id,
|
@Id,
|
||||||
@UserId,
|
CASE WHEN @OrganizationId IS NULL THEN @UserId ELSE NULL END,
|
||||||
@OrganizationId,
|
@OrganizationId,
|
||||||
@Type,
|
@Type,
|
||||||
@Data,
|
@Data,
|
||||||
|
@ -15,7 +15,7 @@ BEGIN
|
|||||||
UPDATE
|
UPDATE
|
||||||
[dbo].[Cipher]
|
[dbo].[Cipher]
|
||||||
SET
|
SET
|
||||||
[UserId] = @UserId,
|
[UserId] = CASE WHEN @OrganizationId IS NULL THEN @UserId ELSE NULL END,
|
||||||
[OrganizationId] = @OrganizationId,
|
[OrganizationId] = @OrganizationId,
|
||||||
[Type] = @Type,
|
[Type] = @Type,
|
||||||
[Data] = @Data,
|
[Data] = @Data,
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[SubvaultUser_ReadIsAdminByCipherIdUserId]
|
||||||
|
@UserId UNIQUEIDENTIFIER,
|
||||||
|
@CipherId AS UNIQUEIDENTIFIER
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
;WITH [CTE] AS(
|
||||||
|
SELECT
|
||||||
|
CASE WHEN OU.[Type] = 2 THEN SU.[Admin] ELSE 1 END AS [Admin] -- 2 = Regular User
|
||||||
|
FROM
|
||||||
|
[dbo].[SubvaultUser] SU
|
||||||
|
INNER JOIN
|
||||||
|
[dbo].[SubvaultCipher] SC ON SC.SubvaultId = SU.SubvaultId
|
||||||
|
INNER JOIN
|
||||||
|
[dbo].[Cipher] C ON SC.[CipherId] = C.[Id]
|
||||||
|
INNER JOIN
|
||||||
|
[dbo].[OrganizationUser] OU ON OU.Id = SU.OrganizationUserId AND OU.OrganizationId = C.OrganizationId
|
||||||
|
WHERE
|
||||||
|
C.[Id] = @CipherId
|
||||||
|
AND OU.[UserId] = @UserId
|
||||||
|
AND OU.[Status] = 2 -- 2 = Confirmed
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
CASE WHEN COUNT(1) > 0 THEN 1 ELSE 0 END
|
||||||
|
FROM
|
||||||
|
[CTE]
|
||||||
|
WHERE
|
||||||
|
[Admin] = 1
|
||||||
|
END
|
Loading…
Reference in New Issue
Block a user