Browse Source

SM-1487-AddingBulkEvents

SM-1301-get-by-id-changes-events
cd-bitwarden 6 months ago
parent
commit
acc89a88e9
  1. 6
      src/Api/AdminConsole/Models/Response/EventResponseModel.cs
  2. 7
      src/Api/AdminConsole/Public/Models/Response/EventResponseModel.cs
  3. 4
      src/Api/SecretsManager/Controllers/SecretsController.cs
  4. 2
      src/Core/AdminConsole/Entities/Event.cs
  5. 2
      src/Core/AdminConsole/Enums/EventType.cs
  6. 19
      src/Core/AdminConsole/Models/Data/EventMessage.cs
  7. 18
      src/Core/AdminConsole/Models/Data/EventTableEntity.cs
  8. 1
      src/Core/AdminConsole/Models/Data/IEvent.cs
  9. 111
      src/Core/AdminConsole/Services/Implementations/EventService.cs

6
src/Api/AdminConsole/Models/Response/EventResponseModel.cs

@ -1,4 +1,6 @@
using Bit.Core.Enums; #nullable enable
using Bit.Core.Enums;
using Bit.Core.Models.Api; using Bit.Core.Models.Api;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
@ -34,6 +36,7 @@ public class EventResponseModel : ResponseModel
DomainName = ev.DomainName; DomainName = ev.DomainName;
SecretId = ev.SecretId; SecretId = ev.SecretId;
ServiceAccountId = ev.ServiceAccountId; ServiceAccountId = ev.ServiceAccountId;
SecretIds = ev.SecretIds;
} }
public EventType Type { get; set; } public EventType Type { get; set; }
@ -56,4 +59,5 @@ public class EventResponseModel : ResponseModel
public string DomainName { get; set; } public string DomainName { get; set; }
public Guid? SecretId { get; set; } public Guid? SecretId { get; set; }
public Guid? ServiceAccountId { get; set; } public Guid? ServiceAccountId { get; set; }
public string? SecretIds { get; set; }
} }

7
src/Api/AdminConsole/Public/Models/Response/EventResponseModel.cs

@ -1,4 +1,6 @@
using System.ComponentModel.DataAnnotations; #nullable enable
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
@ -29,6 +31,7 @@ public class EventResponseModel : IResponseModel
InstallationId = ev.InstallationId; InstallationId = ev.InstallationId;
SecretId = ev.SecretId; SecretId = ev.SecretId;
ServiceAccountId = ev.ServiceAccountId; ServiceAccountId = ev.ServiceAccountId;
SecretIds = ev.SecretIds;
} }
/// <summary> /// <summary>
@ -101,4 +104,6 @@ public class EventResponseModel : IResponseModel
/// </summary> /// </summary>
/// <example>e68b8629-85eb-4929-92c0-b84464976ba4</example> /// <example>e68b8629-85eb-4929-92c0-b84464976ba4</example>
public Guid? ServiceAccountId { get; set; } public Guid? ServiceAccountId { get; set; }
public string? SecretIds { get; set; }
} }

4
src/Api/SecretsManager/Controllers/SecretsController.cs

@ -231,7 +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); await LogSecretsEventAsync(secretsToDelete, EventType.Secrets_Deleted_Bulk);
return new ListResponseModel<BulkDeleteResponseModel>(responses); return new ListResponseModel<BulkDeleteResponseModel>(responses);
} }
@ -251,7 +251,7 @@ public class SecretsController : Controller
throw new NotFoundException(); throw new NotFoundException();
} }
await LogSecretsEventAsync(secrets, EventType.Secret_Retrieved); await LogSecretsEventAsync(secrets, EventType.Secrets_Retrieved_Bulk);
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);

2
src/Core/AdminConsole/Entities/Event.cs

@ -33,6 +33,7 @@ public class Event : ITableObject<Guid>, IEvent
DomainName = e.DomainName; DomainName = e.DomainName;
SecretId = e.SecretId; SecretId = e.SecretId;
ServiceAccountId = e.ServiceAccountId; ServiceAccountId = e.ServiceAccountId;
SecretIds = e.SecretIds;
} }
public Guid Id { get; set; } public Guid Id { get; set; }
@ -57,6 +58,7 @@ public class Event : ITableObject<Guid>, IEvent
public string? DomainName { get; set; } public string? DomainName { get; set; }
public Guid? SecretId { get; set; } public Guid? SecretId { get; set; }
public Guid? ServiceAccountId { get; set; } public Guid? ServiceAccountId { get; set; }
public string? SecretIds { get; set; }
public void SetNewId() public void SetNewId()
{ {

2
src/Core/AdminConsole/Enums/EventType.cs

@ -93,4 +93,6 @@ public enum EventType : int
Secret_Created = 2101, Secret_Created = 2101,
Secret_Edited = 2102, Secret_Edited = 2102,
Secret_Deleted = 2103, Secret_Deleted = 2103,
Secrets_Retrieved_Bulk = 2104,
Secrets_Deleted_Bulk = 2105,
} }

19
src/Core/AdminConsole/Models/Data/EventMessage.cs

@ -1,4 +1,7 @@
using Bit.Core.Context; #nullable enable
using System.ComponentModel.DataAnnotations;
using Bit.Core.Context;
using Bit.Core.Enums; using Bit.Core.Enums;
namespace Bit.Core.Models.Data; namespace Bit.Core.Models.Data;
@ -14,8 +17,10 @@ public class EventMessage : IEvent
DeviceType = currentContext.DeviceType; DeviceType = currentContext.DeviceType;
} }
public DateTime Date { get; set; } [Required]
public EventType Type { get; set; } public DateTime Date { get; set; } = DateTime.Now;
[Required]
public EventType Type { get; set; } = EventType.Cipher_Created;
public Guid? UserId { get; set; } public Guid? UserId { get; set; }
public Guid? OrganizationId { get; set; } public Guid? OrganizationId { get; set; }
public Guid? InstallationId { get; set; } public Guid? InstallationId { get; set; }
@ -29,10 +34,14 @@ public class EventMessage : IEvent
public Guid? ProviderOrganizationId { get; set; } public Guid? ProviderOrganizationId { get; set; }
public Guid? ActingUserId { get; set; } public Guid? ActingUserId { get; set; }
public DeviceType? DeviceType { get; set; } public DeviceType? DeviceType { get; set; }
public string IpAddress { get; set; } [Required]
public string IpAddress { get; set; } = string.Empty;
public Guid? IdempotencyId { get; private set; } = Guid.NewGuid(); public Guid? IdempotencyId { get; private set; } = Guid.NewGuid();
public EventSystemUser? SystemUser { get; set; } public EventSystemUser? SystemUser { get; set; }
public string DomainName { get; set; } [Required]
public string DomainName { get; set; } = string.Empty;
public Guid? SecretId { get; set; } public Guid? SecretId { get; set; }
public string? SecretIds { get; set; }
public Guid? ServiceAccountId { get; set; } public Guid? ServiceAccountId { get; set; }
} }

18
src/Core/AdminConsole/Models/Data/EventTableEntity.cs

@ -33,6 +33,7 @@ public class AzureEvent : ITableEntity
public string DomainName { get; set; } public string DomainName { get; set; }
public Guid? SecretId { get; set; } public Guid? SecretId { get; set; }
public Guid? ServiceAccountId { get; set; } public Guid? ServiceAccountId { get; set; }
public string SecretIds { get; set; }
public EventTableEntity ToEventTableEntity() public EventTableEntity ToEventTableEntity()
{ {
@ -62,7 +63,8 @@ public class AzureEvent : ITableEntity
SystemUser = SystemUser.HasValue ? (EventSystemUser)SystemUser.Value : null, SystemUser = SystemUser.HasValue ? (EventSystemUser)SystemUser.Value : null,
DomainName = DomainName, DomainName = DomainName,
SecretId = SecretId, SecretId = SecretId,
ServiceAccountId = ServiceAccountId ServiceAccountId = ServiceAccountId,
SecretIds = SecretIds,
}; };
} }
} }
@ -93,6 +95,7 @@ public class EventTableEntity : IEvent
DomainName = e.DomainName; DomainName = e.DomainName;
SecretId = e.SecretId; SecretId = e.SecretId;
ServiceAccountId = e.ServiceAccountId; ServiceAccountId = e.ServiceAccountId;
SecretIds = e.SecretIds;
} }
public string PartitionKey { get; set; } public string PartitionKey { get; set; }
@ -120,6 +123,7 @@ public class EventTableEntity : IEvent
public string DomainName { get; set; } public string DomainName { get; set; }
public Guid? SecretId { get; set; } public Guid? SecretId { get; set; }
public Guid? ServiceAccountId { get; set; } public Guid? ServiceAccountId { get; set; }
public string SecretIds { get; set; }
public AzureEvent ToAzureEvent() public AzureEvent ToAzureEvent()
{ {
@ -149,7 +153,8 @@ public class EventTableEntity : IEvent
SystemUser = SystemUser.HasValue ? (int)SystemUser.Value : null, SystemUser = SystemUser.HasValue ? (int)SystemUser.Value : null,
DomainName = DomainName, DomainName = DomainName,
SecretId = SecretId, SecretId = SecretId,
ServiceAccountId = ServiceAccountId ServiceAccountId = ServiceAccountId,
SecretIds = SecretIds
}; };
} }
@ -215,6 +220,15 @@ public class EventTableEntity : IEvent
}); });
} }
if (e.SecretIds != null)
{
entities.Add(new EventTableEntity(e)
{
PartitionKey = pKey,
RowKey = $"SecretIds={e.SecretIds}__Date={dateKey}__Uniquifier={uniquifier}"
});
}
return entities; return entities;
} }

1
src/Core/AdminConsole/Models/Data/IEvent.cs

@ -24,4 +24,5 @@ public interface IEvent
string DomainName { get; set; } string DomainName { get; set; }
Guid? SecretId { get; set; } Guid? SecretId { get; set; }
Guid? ServiceAccountId { get; set; } Guid? ServiceAccountId { get; set; }
string SecretIds { get; set; }
} }

111
src/Core/AdminConsole/Services/Implementations/EventService.cs

@ -414,48 +414,111 @@ public class EventService : IEventService
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
var eventMessages = new List<IEvent>(); var eventMessages = new List<IEvent>();
foreach (var secret in secrets) if (IsBulkEventType(type))
{ {
if (!CanUseEvents(orgAbilities, secret.OrganizationId)) var secretsByOrg = secrets.GroupBy(s => s.OrganizationId);
foreach (var group in secretsByOrg)
{ {
continue; var orgId = group.Key;
if (!CanUseEvents(orgAbilities, orgId))
{
continue;
}
IEnumerable<Guid> secretIds = group.Select(s => s.Id);
var e = new EventMessage(_currentContext)
{
OrganizationId = orgId,
Type = type,
SecretIds = string.Join(",", secretIds.Select(id => id.ToString())),
UserId = userId,
Date = date.GetValueOrDefault(DateTime.UtcNow)
};
eventMessages.Add(e);
} }
}
var e = new EventMessage(_currentContext) else
{
foreach (var secret in secrets)
{ {
OrganizationId = secret.OrganizationId, if (!CanUseEvents(orgAbilities, secret.OrganizationId))
Type = type, {
SecretId = secret.Id, continue;
UserId = userId, }
Date = date.GetValueOrDefault(DateTime.UtcNow)
}; var e = new EventMessage(_currentContext)
eventMessages.Add(e); {
OrganizationId = secret.OrganizationId,
Type = type,
SecretId = secret.Id,
UserId = userId,
Date = date.GetValueOrDefault(DateTime.UtcNow)
};
eventMessages.Add(e);
}
} }
await _eventWriteService.CreateManyAsync(eventMessages); await _eventWriteService.CreateManyAsync(eventMessages);
} }
public bool IsBulkEventType(EventType type)
{
return type == EventType.Secrets_Retrieved_Bulk || type == EventType.Secrets_Deleted_Bulk;
}
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)
{ {
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
var eventMessages = new List<IEvent>(); var eventMessages = new List<IEvent>();
foreach (var secret in secrets) if (IsBulkEventType(type))
{ {
if (!CanUseEvents(orgAbilities, secret.OrganizationId)) var secretsByOrg = secrets.GroupBy(s => s.OrganizationId);
foreach (var group in secretsByOrg)
{ {
continue; var orgId = group.Key;
if (!CanUseEvents(orgAbilities, orgId))
{
continue;
}
IEnumerable<Guid> secretIds = group.Select(s => s.Id);
var e = new EventMessage(_currentContext)
{
OrganizationId = orgId,
Type = type,
SecretIds = string.Join(",", secretIds.Select(id => id.ToString())),
UserId = serviceAccountId,
Date = date.GetValueOrDefault(DateTime.UtcNow)
};
eventMessages.Add(e);
} }
}
var e = new EventMessage(_currentContext) else
{
foreach (var secret in secrets)
{ {
OrganizationId = secret.OrganizationId, if (!CanUseEvents(orgAbilities, secret.OrganizationId))
Type = type, {
SecretId = secret.Id, continue;
ServiceAccountId = serviceAccountId, }
Date = date.GetValueOrDefault(DateTime.UtcNow)
}; var e = new EventMessage(_currentContext)
eventMessages.Add(e); {
OrganizationId = secret.OrganizationId,
Type = type,
SecretId = secret.Id,
ServiceAccountId = serviceAccountId,
Date = date.GetValueOrDefault(DateTime.UtcNow)
};
eventMessages.Add(e);
}
} }
await _eventWriteService.CreateManyAsync(eventMessages); await _eventWriteService.CreateManyAsync(eventMessages);

Loading…
Cancel
Save