mirror of
https://github.com/bitwarden/server
synced 2025-12-11 05:43:35 +00:00
[SM-1273] Adding new logging for secrets (#5991)
* Adding new logging for secrets * fixing secrest controller tests * fixing the tests
This commit is contained in:
@@ -109,7 +109,7 @@ public class SecretsController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
var result = await _createSecretCommand.CreateAsync(secret, accessPoliciesUpdates);
|
var result = await _createSecretCommand.CreateAsync(secret, accessPoliciesUpdates);
|
||||||
|
await LogSecretEventAsync(secret, EventType.Secret_Created);
|
||||||
// Creating a secret means you have read & write permission.
|
// Creating a secret means you have read & write permission.
|
||||||
return new SecretResponseModel(result, true, true);
|
return new SecretResponseModel(result, true, true);
|
||||||
}
|
}
|
||||||
@@ -135,10 +135,7 @@ public class SecretsController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentContext.IdentityClientType == IdentityClientType.ServiceAccount)
|
await LogSecretEventAsync(secret, EventType.Secret_Retrieved);
|
||||||
{
|
|
||||||
await _eventService.LogServiceAccountSecretEventAsync(userId, secret, EventType.Secret_Retrieved);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new SecretResponseModel(secret, access.Read, access.Write);
|
return new SecretResponseModel(secret, access.Read, access.Write);
|
||||||
}
|
}
|
||||||
@@ -188,10 +185,10 @@ public class SecretsController : Controller
|
|||||||
{
|
{
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await _updateSecretCommand.UpdateAsync(updatedSecret, accessPoliciesUpdates);
|
var result = await _updateSecretCommand.UpdateAsync(updatedSecret, accessPoliciesUpdates);
|
||||||
|
await LogSecretEventAsync(secret, EventType.Secret_Edited);
|
||||||
|
|
||||||
// Updating a secret means you have read & write permission.
|
// Updating a secret means you have read & write permission.
|
||||||
return new SecretResponseModel(result, true, true);
|
return new SecretResponseModel(result, true, true);
|
||||||
@@ -234,6 +231,7 @@ public class SecretsController : Controller
|
|||||||
|
|
||||||
await _deleteSecretCommand.DeleteSecrets(secretsToDelete);
|
await _deleteSecretCommand.DeleteSecrets(secretsToDelete);
|
||||||
var responses = results.Select(r => new BulkDeleteResponseModel(r.Secret.Id, r.Error));
|
var responses = results.Select(r => new BulkDeleteResponseModel(r.Secret.Id, r.Error));
|
||||||
|
await LogSecretsEventAsync(secretsToDelete, EventType.Secret_Deleted);
|
||||||
return new ListResponseModel<BulkDeleteResponseModel>(responses);
|
return new ListResponseModel<BulkDeleteResponseModel>(responses);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +251,7 @@ public class SecretsController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
await LogSecretsRetrievalAsync(secrets);
|
await LogSecretsEventAsync(secrets, EventType.Secret_Retrieved);
|
||||||
|
|
||||||
var responses = secrets.Select(s => new BaseSecretResponseModel(s));
|
var responses = secrets.Select(s => new BaseSecretResponseModel(s));
|
||||||
return new ListResponseModel<BaseSecretResponseModel>(responses);
|
return new ListResponseModel<BaseSecretResponseModel>(responses);
|
||||||
@@ -290,18 +288,28 @@ public class SecretsController : Controller
|
|||||||
|
|
||||||
if (syncResult.HasChanges)
|
if (syncResult.HasChanges)
|
||||||
{
|
{
|
||||||
await LogSecretsRetrievalAsync(syncResult.Secrets);
|
await LogSecretsEventAsync(syncResult.Secrets, EventType.Secret_Retrieved);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SecretsSyncResponseModel(syncResult.HasChanges, syncResult.Secrets);
|
return new SecretsSyncResponseModel(syncResult.HasChanges, syncResult.Secrets);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LogSecretsRetrievalAsync(IEnumerable<Secret> secrets)
|
private async Task LogSecretsEventAsync(IEnumerable<Secret> secrets, EventType eventType)
|
||||||
{
|
{
|
||||||
if (_currentContext.IdentityClientType == IdentityClientType.ServiceAccount)
|
var userId = _userService.GetProperUserId(User)!.Value;
|
||||||
|
|
||||||
|
switch (_currentContext.IdentityClientType)
|
||||||
{
|
{
|
||||||
var userId = _userService.GetProperUserId(User)!.Value;
|
case IdentityClientType.ServiceAccount:
|
||||||
await _eventService.LogServiceAccountSecretsEventAsync(userId, secrets, EventType.Secret_Retrieved);
|
await _eventService.LogServiceAccountSecretsEventAsync(userId, secrets, eventType);
|
||||||
|
break;
|
||||||
|
case IdentityClientType.User:
|
||||||
|
await _eventService.LogUserSecretsEventAsync(userId, secrets, eventType);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task LogSecretEventAsync(Secret secret, EventType eventType) =>
|
||||||
|
LogSecretsEventAsync(new[] { secret }, eventType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,4 +90,7 @@ public enum EventType : int
|
|||||||
OrganizationDomain_NotVerified = 2003,
|
OrganizationDomain_NotVerified = 2003,
|
||||||
|
|
||||||
Secret_Retrieved = 2100,
|
Secret_Retrieved = 2100,
|
||||||
|
Secret_Created = 2101,
|
||||||
|
Secret_Edited = 2102,
|
||||||
|
Secret_Deleted = 2103,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,6 @@ public interface IEventService
|
|||||||
Task LogProviderOrganizationEventsAsync(IEnumerable<(ProviderOrganization, EventType, DateTime?)> events);
|
Task LogProviderOrganizationEventsAsync(IEnumerable<(ProviderOrganization, EventType, DateTime?)> events);
|
||||||
Task LogOrganizationDomainEventAsync(OrganizationDomain organizationDomain, EventType type, DateTime? date = null);
|
Task LogOrganizationDomainEventAsync(OrganizationDomain organizationDomain, EventType type, DateTime? date = null);
|
||||||
Task LogOrganizationDomainEventAsync(OrganizationDomain organizationDomain, EventType type, EventSystemUser systemUser, DateTime? date = null);
|
Task LogOrganizationDomainEventAsync(OrganizationDomain organizationDomain, EventType type, EventSystemUser systemUser, DateTime? date = null);
|
||||||
Task LogServiceAccountSecretEventAsync(Guid serviceAccountId, Secret secret, EventType type, DateTime? date = null);
|
Task LogUserSecretsEventAsync(Guid userId, IEnumerable<Secret> secrets, EventType type, DateTime? date = null);
|
||||||
Task LogServiceAccountSecretsEventAsync(Guid serviceAccountId, IEnumerable<Secret> secrets, EventType type, DateTime? date = null);
|
Task LogServiceAccountSecretsEventAsync(Guid serviceAccountId, IEnumerable<Secret> secrets, EventType type, DateTime? date = null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -409,9 +409,30 @@ public class EventService : IEventService
|
|||||||
await _eventWriteService.CreateAsync(e);
|
await _eventWriteService.CreateAsync(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task LogServiceAccountSecretEventAsync(Guid serviceAccountId, Secret secret, EventType type, DateTime? date = null)
|
public async Task LogUserSecretsEventAsync(Guid userId, IEnumerable<Secret> secrets, EventType type, DateTime? date = null)
|
||||||
{
|
{
|
||||||
await LogServiceAccountSecretsEventAsync(serviceAccountId, new[] { secret }, type, date);
|
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
|
||||||
|
var eventMessages = new List<IEvent>();
|
||||||
|
|
||||||
|
foreach (var secret in secrets)
|
||||||
|
{
|
||||||
|
if (!CanUseEvents(orgAbilities, secret.OrganizationId))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var e = new EventMessage(_currentContext)
|
||||||
|
{
|
||||||
|
OrganizationId = secret.OrganizationId,
|
||||||
|
Type = type,
|
||||||
|
SecretId = secret.Id,
|
||||||
|
UserId = userId,
|
||||||
|
Date = date.GetValueOrDefault(DateTime.UtcNow)
|
||||||
|
};
|
||||||
|
eventMessages.Add(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _eventWriteService.CreateManyAsync(eventMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task LogServiceAccountSecretsEventAsync(Guid serviceAccountId, IEnumerable<Secret> secrets, EventType type, DateTime? date = null)
|
public async Task LogServiceAccountSecretsEventAsync(Guid serviceAccountId, IEnumerable<Secret> secrets, EventType type, DateTime? date = null)
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ public class NoopEventService : IEventService
|
|||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task LogServiceAccountSecretEventAsync(Guid serviceAccountId, Secret secret, EventType type,
|
public Task LogUserSecretsEventAsync(Guid userId, IEnumerable<Secret> secrets, EventType type,
|
||||||
DateTime? date = null)
|
DateTime? date = null)
|
||||||
{
|
{
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ using Bit.Test.Common.AutoFixture;
|
|||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
using Bit.Test.Common.Helpers;
|
using Bit.Test.Common.Helpers;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@@ -152,6 +153,7 @@ public class SecretsControllerTests
|
|||||||
SecretCreateRequestModel data, Guid organizationId)
|
SecretCreateRequestModel data, Guid organizationId)
|
||||||
{
|
{
|
||||||
data = SetupSecretCreateRequest(sutProvider, data, organizationId);
|
data = SetupSecretCreateRequest(sutProvider, data, organizationId);
|
||||||
|
SetControllerUser(sutProvider, new Guid());
|
||||||
|
|
||||||
await sutProvider.Sut.CreateAsync(organizationId, data);
|
await sutProvider.Sut.CreateAsync(organizationId, data);
|
||||||
|
|
||||||
@@ -186,6 +188,7 @@ public class SecretsControllerTests
|
|||||||
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<SecretAccessPoliciesUpdates>(),
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<SecretAccessPoliciesUpdates>(),
|
||||||
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).Returns(AuthorizationResult.Success());
|
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).Returns(AuthorizationResult.Success());
|
||||||
|
|
||||||
|
SetControllerUser(sutProvider, new Guid());
|
||||||
|
|
||||||
await sutProvider.Sut.CreateAsync(organizationId, data);
|
await sutProvider.Sut.CreateAsync(organizationId, data);
|
||||||
|
|
||||||
@@ -199,6 +202,7 @@ public class SecretsControllerTests
|
|||||||
SecretUpdateRequestModel data, Secret currentSecret)
|
SecretUpdateRequestModel data, Secret currentSecret)
|
||||||
{
|
{
|
||||||
data = SetupSecretUpdateRequest(data);
|
data = SetupSecretUpdateRequest(data);
|
||||||
|
|
||||||
sutProvider.GetDependency<IAuthorizationService>()
|
sutProvider.GetDependency<IAuthorizationService>()
|
||||||
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<Secret>(),
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<Secret>(),
|
||||||
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Failed());
|
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Failed());
|
||||||
@@ -239,7 +243,7 @@ public class SecretsControllerTests
|
|||||||
SecretUpdateRequestModel data, Secret currentSecret)
|
SecretUpdateRequestModel data, Secret currentSecret)
|
||||||
{
|
{
|
||||||
data = SetupSecretUpdateRequest(data);
|
data = SetupSecretUpdateRequest(data);
|
||||||
|
SetControllerUser(sutProvider, new Guid());
|
||||||
sutProvider.GetDependency<IAuthorizationService>()
|
sutProvider.GetDependency<IAuthorizationService>()
|
||||||
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<Secret>(),
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<Secret>(),
|
||||||
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Success());
|
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Success());
|
||||||
@@ -260,7 +264,6 @@ public class SecretsControllerTests
|
|||||||
SecretUpdateRequestModel data, Secret currentSecret, SecretAccessPoliciesUpdates accessPoliciesUpdates)
|
SecretUpdateRequestModel data, Secret currentSecret, SecretAccessPoliciesUpdates accessPoliciesUpdates)
|
||||||
{
|
{
|
||||||
data = SetupSecretUpdateAccessPoliciesRequest(sutProvider, data, currentSecret, accessPoliciesUpdates);
|
data = SetupSecretUpdateAccessPoliciesRequest(sutProvider, data, currentSecret, accessPoliciesUpdates);
|
||||||
|
|
||||||
sutProvider.GetDependency<IAuthorizationService>()
|
sutProvider.GetDependency<IAuthorizationService>()
|
||||||
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<SecretAccessPoliciesUpdates>(),
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<SecretAccessPoliciesUpdates>(),
|
||||||
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).Returns(AuthorizationResult.Failed());
|
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).Returns(AuthorizationResult.Failed());
|
||||||
@@ -339,6 +342,8 @@ public class SecretsControllerTests
|
|||||||
{
|
{
|
||||||
var ids = data.Select(s => s.Id).ToList();
|
var ids = data.Select(s => s.Id).ToList();
|
||||||
var organizationId = data.First().OrganizationId;
|
var organizationId = data.First().OrganizationId;
|
||||||
|
SetControllerUser(sutProvider, new Guid());
|
||||||
|
|
||||||
foreach (var secret in data)
|
foreach (var secret in data)
|
||||||
{
|
{
|
||||||
secret.OrganizationId = organizationId;
|
secret.OrganizationId = organizationId;
|
||||||
@@ -378,7 +383,7 @@ public class SecretsControllerTests
|
|||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(Arg.Is(organizationId)).ReturnsForAnyArgs(true);
|
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(Arg.Is(organizationId)).ReturnsForAnyArgs(true);
|
||||||
sutProvider.GetDependency<ISecretRepository>().GetManyByIds(Arg.Is(ids)).ReturnsForAnyArgs(data);
|
sutProvider.GetDependency<ISecretRepository>().GetManyByIds(Arg.Is(ids)).ReturnsForAnyArgs(data);
|
||||||
|
SetControllerUser(sutProvider, new Guid());
|
||||||
var results = await sutProvider.Sut.BulkDeleteAsync(ids);
|
var results = await sutProvider.Sut.BulkDeleteAsync(ids);
|
||||||
|
|
||||||
await sutProvider.GetDependency<IDeleteSecretCommand>().Received(1)
|
await sutProvider.GetDependency<IDeleteSecretCommand>().Received(1)
|
||||||
@@ -434,7 +439,7 @@ public class SecretsControllerTests
|
|||||||
{
|
{
|
||||||
var (ids, request) = BuildGetSecretsRequestModel(data);
|
var (ids, request) = BuildGetSecretsRequestModel(data);
|
||||||
var organizationId = SetOrganizations(ref data);
|
var organizationId = SetOrganizations(ref data);
|
||||||
|
SetControllerUser(sutProvider, new Guid());
|
||||||
sutProvider.GetDependency<ISecretRepository>().GetManyByIds(Arg.Is(ids)).ReturnsForAnyArgs(data);
|
sutProvider.GetDependency<ISecretRepository>().GetManyByIds(Arg.Is(ids)).ReturnsForAnyArgs(data);
|
||||||
sutProvider.GetDependency<IAuthorizationService>()
|
sutProvider.GetDependency<IAuthorizationService>()
|
||||||
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), data,
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), data,
|
||||||
@@ -507,7 +512,7 @@ public class SecretsControllerTests
|
|||||||
SutProvider<SecretsController> sutProvider, Guid organizationId)
|
SutProvider<SecretsController> sutProvider, Guid organizationId)
|
||||||
{
|
{
|
||||||
var lastSyncedDate = SetupSecretsSyncRequest(nullLastSyncedDate, secrets, sutProvider, organizationId);
|
var lastSyncedDate = SetupSecretsSyncRequest(nullLastSyncedDate, secrets, sutProvider, organizationId);
|
||||||
|
SetControllerUser(sutProvider, new Guid());
|
||||||
var result = await sutProvider.Sut.GetSecretsSyncAsync(organizationId, lastSyncedDate);
|
var result = await sutProvider.Sut.GetSecretsSyncAsync(organizationId, lastSyncedDate);
|
||||||
Assert.True(result.HasChanges);
|
Assert.True(result.HasChanges);
|
||||||
Assert.NotNull(result.Secrets);
|
Assert.NotNull(result.Secrets);
|
||||||
@@ -610,4 +615,19 @@ public class SecretsControllerTests
|
|||||||
.ReturnsForAnyArgs(data.ToSecret(currentSecret));
|
.ReturnsForAnyArgs(data.ToSecret(currentSecret));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void SetControllerUser(SutProvider<SecretsController> sutProvider, Guid userId)
|
||||||
|
{
|
||||||
|
var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, userId.ToString()) };
|
||||||
|
var identity = new ClaimsIdentity(claims, "Test");
|
||||||
|
var principal = new ClaimsPrincipal(identity);
|
||||||
|
|
||||||
|
sutProvider.Sut.ControllerContext = new Microsoft.AspNetCore.Mvc.ControllerContext
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext { User = principal }
|
||||||
|
};
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IUserService>().GetProperUserId(principal).Returns(userId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user