mirror of
https://github.com/bitwarden/server
synced 2026-01-04 09:33:40 +00:00
[PM-14373] Introduce SecurityTask database table and repository (#5025)
* [PM-14373] Introduce SecurityTask entity and related enums * [PM-14373] Add Dapper SecurityTask repository * [PM-14373] Introduce MSSQL table, view, and stored procedures * [PM-14373] Add EF SecurityTask repository and type configurations * [PM-14373] Add EF Migration * [PM-14373] Add integration tests * [PM-14373] Formatting * Typo Co-authored-by: Matt Bishop <mbishop@bitwarden.com> * Typo Co-authored-by: Matt Bishop <mbishop@bitwarden.com> * [PM-14373] Remove DeleteById sproc * [PM-14373] SQL formatting --------- Co-authored-by: Matt Bishop <mbishop@bitwarden.com>
This commit is contained in:
20
src/Core/Vault/Entities/SecurityTask.cs
Normal file
20
src/Core/Vault/Entities/SecurityTask.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.Vault.Entities;
|
||||
|
||||
public class SecurityTask : ITableObject<Guid>
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid OrganizationId { get; set; }
|
||||
public Guid? CipherId { get; set; }
|
||||
public Enums.SecurityTaskType Type { get; set; }
|
||||
public Enums.SecurityTaskStatus Status { get; set; }
|
||||
public DateTime CreationDate { get; set; } = DateTime.UtcNow;
|
||||
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public void SetNewId()
|
||||
{
|
||||
Id = CoreHelpers.GenerateComb();
|
||||
}
|
||||
}
|
||||
18
src/Core/Vault/Enums/SecurityTaskStatus.cs
Normal file
18
src/Core/Vault/Enums/SecurityTaskStatus.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Bit.Core.Vault.Enums;
|
||||
|
||||
public enum SecurityTaskStatus : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Default status for newly created tasks that have not been completed.
|
||||
/// </summary>
|
||||
[Display(Name = "Pending")]
|
||||
Pending = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Status when a task is considered complete and has no remaining actions
|
||||
/// </summary>
|
||||
[Display(Name = "Completed")]
|
||||
Completed = 1,
|
||||
}
|
||||
12
src/Core/Vault/Enums/SecurityTaskType.cs
Normal file
12
src/Core/Vault/Enums/SecurityTaskType.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Bit.Core.Vault.Enums;
|
||||
|
||||
public enum SecurityTaskType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Task to update a cipher's password that was found to be at-risk by an administrator
|
||||
/// </summary>
|
||||
[Display(Name = "Update at-risk credential")]
|
||||
UpdateAtRiskCredential = 0
|
||||
}
|
||||
9
src/Core/Vault/Repositories/ISecurityTaskRepository.cs
Normal file
9
src/Core/Vault/Repositories/ISecurityTaskRepository.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Vault.Entities;
|
||||
|
||||
namespace Bit.Core.Vault.Repositories;
|
||||
|
||||
public interface ISecurityTaskRepository : IRepository<SecurityTask, Guid>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -59,6 +59,7 @@ public static class DapperServiceCollectionExtensions
|
||||
services
|
||||
.AddSingleton<IClientOrganizationMigrationRecordRepository, ClientOrganizationMigrationRecordRepository>();
|
||||
services.AddSingleton<IPasswordHealthReportApplicationRepository, PasswordHealthReportApplicationRepository>();
|
||||
services.AddSingleton<ISecurityTaskRepository, SecurityTaskRepository>();
|
||||
|
||||
if (selfHosted)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
using Bit.Infrastructure.Dapper.Repositories;
|
||||
|
||||
namespace Bit.Infrastructure.Dapper.Vault.Repositories;
|
||||
|
||||
public class SecurityTaskRepository : Repository<SecurityTask, Guid>, ISecurityTaskRepository
|
||||
{
|
||||
public SecurityTaskRepository(GlobalSettings globalSettings)
|
||||
: this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
|
||||
{ }
|
||||
|
||||
public SecurityTaskRepository(string connectionString, string readOnlyConnectionString)
|
||||
: base(connectionString, readOnlyConnectionString)
|
||||
{ }
|
||||
|
||||
}
|
||||
@@ -96,6 +96,7 @@ public static class EntityFrameworkServiceCollectionExtensions
|
||||
services
|
||||
.AddSingleton<IClientOrganizationMigrationRecordRepository, ClientOrganizationMigrationRecordRepository>();
|
||||
services.AddSingleton<IPasswordHealthReportApplicationRepository, PasswordHealthReportApplicationRepository>();
|
||||
services.AddSingleton<ISecurityTaskRepository, SecurityTaskRepository>();
|
||||
|
||||
if (selfHosted)
|
||||
{
|
||||
|
||||
@@ -77,6 +77,7 @@ public class DatabaseContext : DbContext
|
||||
public DbSet<NotificationStatus> NotificationStatuses { get; set; }
|
||||
public DbSet<ClientOrganizationMigrationRecord> ClientOrganizationMigrationRecords { get; set; }
|
||||
public DbSet<PasswordHealthReportApplication> PasswordHealthReportApplications { get; set; }
|
||||
public DbSet<SecurityTask> SecurityTasks { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Bit.Infrastructure.EntityFramework.Vault.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Vault.Configurations;
|
||||
|
||||
public class SecurityTaskEntityTypeConfiguration : IEntityTypeConfiguration<SecurityTask>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<SecurityTask> builder)
|
||||
{
|
||||
builder
|
||||
.Property(s => s.Id)
|
||||
.ValueGeneratedNever();
|
||||
|
||||
builder
|
||||
.HasKey(s => s.Id)
|
||||
.IsClustered();
|
||||
|
||||
builder
|
||||
.HasIndex(s => s.OrganizationId)
|
||||
.IsClustered(false);
|
||||
|
||||
builder
|
||||
.HasIndex(s => s.CipherId)
|
||||
.IsClustered(false);
|
||||
|
||||
builder
|
||||
.ToTable(nameof(SecurityTask));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using AutoMapper;
|
||||
using Bit.Infrastructure.EntityFramework.AdminConsole.Models;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Vault.Models;
|
||||
|
||||
public class SecurityTask : Core.Vault.Entities.SecurityTask
|
||||
{
|
||||
public virtual Organization Organization { get; set; }
|
||||
public virtual Cipher Cipher { get; set; }
|
||||
}
|
||||
|
||||
public class SecurityTaskMapperProfile : Profile
|
||||
{
|
||||
public SecurityTaskMapperProfile()
|
||||
{
|
||||
CreateMap<Core.Vault.Entities.SecurityTask, SecurityTask>().ReverseMap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using AutoMapper;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Vault.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Vault.Repositories;
|
||||
|
||||
public class SecurityTaskRepository : Repository<Core.Vault.Entities.SecurityTask, SecurityTask, Guid>, ISecurityTaskRepository
|
||||
{
|
||||
public SecurityTaskRepository(IServiceScopeFactory serviceScopeFactory, IMapper mapper)
|
||||
: base(serviceScopeFactory, mapper, (context) => context.SecurityTasks)
|
||||
{ }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
CREATE PROCEDURE [dbo].[SecurityTask_Create]
|
||||
@Id UNIQUEIDENTIFIER OUTPUT,
|
||||
@OrganizationId UNIQUEIDENTIFIER,
|
||||
@CipherId UNIQUEIDENTIFIER,
|
||||
@Type TINYINT,
|
||||
@Status TINYINT,
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7)
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
INSERT INTO [dbo].[SecurityTask]
|
||||
(
|
||||
[Id],
|
||||
[OrganizationId],
|
||||
[CipherId],
|
||||
[Type],
|
||||
[Status],
|
||||
[CreationDate],
|
||||
[RevisionDate]
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@Id,
|
||||
@OrganizationId,
|
||||
@CipherId,
|
||||
@Type,
|
||||
@Status,
|
||||
@CreationDate,
|
||||
@RevisionDate
|
||||
)
|
||||
END
|
||||
@@ -0,0 +1,13 @@
|
||||
CREATE PROCEDURE [dbo].[SecurityTask_ReadById]
|
||||
@Id UNIQUEIDENTIFIER
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
[dbo].[SecurityTaskView]
|
||||
WHERE
|
||||
[Id] = @Id
|
||||
END
|
||||
@@ -0,0 +1,24 @@
|
||||
CREATE PROCEDURE [dbo].[SecurityTask_Update]
|
||||
@Id UNIQUEIDENTIFIER,
|
||||
@OrganizationId UNIQUEIDENTIFIER,
|
||||
@CipherId UNIQUEIDENTIFIER,
|
||||
@Type TINYINT,
|
||||
@Status TINYINT,
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7)
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
UPDATE
|
||||
[dbo].[SecurityTask]
|
||||
SET
|
||||
[OrganizationId] = @OrganizationId,
|
||||
[CipherId] = @CipherId,
|
||||
[Type] = @Type,
|
||||
[Status] = @Status,
|
||||
[CreationDate] = @CreationDate,
|
||||
[RevisionDate] = @RevisionDate
|
||||
WHERE
|
||||
[Id] = @Id
|
||||
END
|
||||
21
src/Sql/Vault/dbo/Tables/SecurityTask.sql
Normal file
21
src/Sql/Vault/dbo/Tables/SecurityTask.sql
Normal file
@@ -0,0 +1,21 @@
|
||||
CREATE TABLE [dbo].[SecurityTask]
|
||||
(
|
||||
[Id] UNIQUEIDENTIFIER NOT NULL,
|
||||
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
|
||||
[CipherId] UNIQUEIDENTIFIER NULL,
|
||||
[Type] TINYINT NOT NULL,
|
||||
[Status] TINYINT NOT NULL,
|
||||
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||
CONSTRAINT [PK_SecurityTask] PRIMARY KEY CLUSTERED ([Id] ASC),
|
||||
CONSTRAINT [FK_SecurityTask_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]) ON DELETE CASCADE,
|
||||
CONSTRAINT [FK_SecurityTask_Cipher] FOREIGN KEY ([CipherId]) REFERENCES [dbo].[Cipher] ([Id]) ON DELETE CASCADE,
|
||||
);
|
||||
|
||||
GO
|
||||
CREATE NONCLUSTERED INDEX [IX_SecurityTask_CipherId]
|
||||
ON [dbo].[SecurityTask]([CipherId] ASC) WHERE CipherId IS NOT NULL;
|
||||
|
||||
GO
|
||||
CREATE NONCLUSTERED INDEX [IX_SecurityTask_OrganizationId]
|
||||
ON [dbo].[SecurityTask]([OrganizationId] ASC) WHERE OrganizationId IS NOT NULL;
|
||||
6
src/Sql/Vault/dbo/Views/SecurityTaskView.sql
Normal file
6
src/Sql/Vault/dbo/Views/SecurityTaskView.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
CREATE VIEW [dbo].[SecurityTaskView]
|
||||
AS
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
[dbo].[SecurityTask]
|
||||
Reference in New Issue
Block a user