Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SM-713] Add database support for secret access policies #3681

Merged
merged 18 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,22 +84,29 @@ public async Task<bool> UserHasWriteAccessToServiceAccount(Guid id, Guid userId)

public async Task DeleteManyByIdAsync(IEnumerable<Guid> ids)
{
var targetIds = ids.ToList();
using var scope = ServiceScopeFactory.CreateScope();
var dbContext = GetDatabaseContext(scope);

await using var transaction = await dbContext.Database.BeginTransactionAsync();

rkac-bw marked this conversation as resolved.
Show resolved Hide resolved
// Policies can't have a cascade delete, so we need to delete them manually.
var policies = dbContext.AccessPolicies.Where(ap =>
((ServiceAccountProjectAccessPolicy)ap).ServiceAccountId.HasValue && ids.Contains(((ServiceAccountProjectAccessPolicy)ap).ServiceAccountId!.Value) ||
((GroupServiceAccountAccessPolicy)ap).GrantedServiceAccountId.HasValue && ids.Contains(((GroupServiceAccountAccessPolicy)ap).GrantedServiceAccountId!.Value) ||
((UserServiceAccountAccessPolicy)ap).GrantedServiceAccountId.HasValue && ids.Contains(((UserServiceAccountAccessPolicy)ap).GrantedServiceAccountId!.Value));
dbContext.RemoveRange(policies);

var apiKeys = dbContext.ApiKeys.Where(a => a.ServiceAccountId.HasValue && ids.Contains(a.ServiceAccountId!.Value));
dbContext.RemoveRange(apiKeys);

var serviceAccounts = dbContext.ServiceAccount.Where(c => ids.Contains(c.Id));
dbContext.RemoveRange(serviceAccounts);
await dbContext.SaveChangesAsync();
await dbContext.AccessPolicies.Where(ap =>
targetIds.Contains(((ServiceAccountProjectAccessPolicy)ap).ServiceAccountId!.Value) ||
targetIds.Contains(((ServiceAccountSecretAccessPolicy)ap).ServiceAccountId!.Value) ||
targetIds.Contains(((GroupServiceAccountAccessPolicy)ap).GrantedServiceAccountId!.Value) ||
targetIds.Contains(((UserServiceAccountAccessPolicy)ap).GrantedServiceAccountId!.Value))
.ExecuteDeleteAsync();

await dbContext.ApiKeys
.Where(a => targetIds.Contains(a.ServiceAccountId!.Value))
.ExecuteDeleteAsync();

await dbContext.ServiceAccount
.Where(c => targetIds.Contains(c.Id))
.ExecuteDeleteAsync();

await transaction.CommitAsync();
}

public async Task<(bool Read, bool Write)> AccessToServiceAccountAsync(Guid id, Guid userId,
Expand Down
25 changes: 25 additions & 0 deletions src/Core/SecretsManager/Entities/AccessPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@
public ServiceAccount? GrantedServiceAccount { get; set; }
}

public class UserSecretAccessPolicy : BaseAccessPolicy
{
public Guid? OrganizationUserId { get; set; }
public User? User { get; set; }
public Guid? GrantedSecretId { get; set; }
public Secret? GrantedSecret { get; set; }

Check warning on line 46 in src/Core/SecretsManager/Entities/AccessPolicy.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/SecretsManager/Entities/AccessPolicy.cs#L43-L46

Added lines #L43 - L46 were not covered by tests
}

public class GroupProjectAccessPolicy : BaseAccessPolicy
{
public Guid? GroupId { get; set; }
Expand All @@ -56,10 +64,27 @@
public ServiceAccount? GrantedServiceAccount { get; set; }
}

public class GroupSecretAccessPolicy : BaseAccessPolicy
{
public Guid? GroupId { get; set; }
public Group? Group { get; set; }
public bool? CurrentUserInGroup { get; set; }
public Guid? GrantedSecretId { get; set; }
public Secret? GrantedSecret { get; set; }

Check warning on line 73 in src/Core/SecretsManager/Entities/AccessPolicy.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/SecretsManager/Entities/AccessPolicy.cs#L69-L73

Added lines #L69 - L73 were not covered by tests
}

public class ServiceAccountProjectAccessPolicy : BaseAccessPolicy
{
public Guid? ServiceAccountId { get; set; }
public ServiceAccount? ServiceAccount { get; set; }
public Guid? GrantedProjectId { get; set; }
public Project? GrantedProject { get; set; }
}

public class ServiceAccountSecretAccessPolicy : BaseAccessPolicy
{
public Guid? ServiceAccountId { get; set; }
public ServiceAccount? ServiceAccount { get; set; }
public Guid? GrantedSecretId { get; set; }
public Secret? GrantedSecret { get; set; }

Check warning on line 89 in src/Core/SecretsManager/Entities/AccessPolicy.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/SecretsManager/Entities/AccessPolicy.cs#L86-L89

Added lines #L86 - L89 were not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@
.ExecuteDeleteAsync();
await dbContext.UserServiceAccountAccessPolicy.Where(ap => ap.OrganizationUser.OrganizationId == organization.Id)
.ExecuteDeleteAsync();
await dbContext.UserSecretAccessPolicy.Where(ap => ap.OrganizationUser.OrganizationId == organization.Id)
.ExecuteDeleteAsync();

Check warning on line 184 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs#L183-L184

Added lines #L183 - L184 were not covered by tests
await dbContext.OrganizationUsers.Where(ou => ou.OrganizationId == organization.Id)
.ExecuteDeleteAsync();
await dbContext.ProviderOrganizations.Where(po => po.OrganizationId == organization.Id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
dbContext.UserProjectAccessPolicy.Where(ap => ap.OrganizationUserId == organizationUserId));
dbContext.UserServiceAccountAccessPolicy.RemoveRange(
dbContext.UserServiceAccountAccessPolicy.Where(ap => ap.OrganizationUserId == organizationUserId));
dbContext.UserSecretAccessPolicy.RemoveRange(
dbContext.UserSecretAccessPolicy.Where(ap => ap.OrganizationUserId == organizationUserId));

var orgSponsorships = await dbContext.OrganizationSponsorships
.Where(os => os.SponsoringOrganizationUserId == organizationUserId)
Expand All @@ -117,18 +119,36 @@

public async Task DeleteManyAsync(IEnumerable<Guid> organizationUserIds)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var dbContext = GetDatabaseContext(scope);
await dbContext.UserBumpAccountRevisionDateByOrganizationUserIdsAsync(organizationUserIds);
var entities = await dbContext.OrganizationUsers
// TODO: Does this work?
.Where(ou => organizationUserIds.Contains(ou.Id))
.ToListAsync();
var targetOrganizationUserIds = organizationUserIds.ToList();
using var scope = ServiceScopeFactory.CreateScope();
var dbContext = GetDatabaseContext(scope);

Check warning on line 124 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs#L122-L124

Added lines #L122 - L124 were not covered by tests

dbContext.OrganizationUsers.RemoveRange(entities);
await dbContext.SaveChangesAsync();
}
var transaction = await dbContext.Database.BeginTransactionAsync();
await dbContext.UserBumpAccountRevisionDateByOrganizationUserIdsAsync(targetOrganizationUserIds);

Check warning on line 127 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs#L126-L127

Added lines #L126 - L127 were not covered by tests

await dbContext.CollectionUsers
.Where(cu => targetOrganizationUserIds.Contains(cu.OrganizationUserId))
.ExecuteDeleteAsync();

Check warning on line 131 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs#L129-L131

Added lines #L129 - L131 were not covered by tests

await dbContext.GroupUsers
.Where(gu => targetOrganizationUserIds.Contains(gu.OrganizationUserId))
.ExecuteDeleteAsync();

Check warning on line 135 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs#L133-L135

Added lines #L133 - L135 were not covered by tests

await dbContext.UserProjectAccessPolicy
.Where(ap => targetOrganizationUserIds.Contains(ap.OrganizationUserId!.Value))
.ExecuteDeleteAsync();
await dbContext.UserServiceAccountAccessPolicy
.Where(ap => targetOrganizationUserIds.Contains(ap.OrganizationUserId!.Value))
.ExecuteDeleteAsync();
await dbContext.UserSecretAccessPolicy
.Where(ap => targetOrganizationUserIds.Contains(ap.OrganizationUserId!.Value))
.ExecuteDeleteAsync();

Check warning on line 145 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs#L137-L145

Added lines #L137 - L145 were not covered by tests

await dbContext.OrganizationUsers
.Where(ou => targetOrganizationUserIds.Contains(ou.Id)).ExecuteDeleteAsync();

Check warning on line 148 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs#L147-L148

Added lines #L147 - L148 were not covered by tests

await dbContext.SaveChangesAsync();
await transaction.CommitAsync();

Check warning on line 151 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs#L150-L151

Added lines #L150 - L151 were not covered by tests
}

public async Task<Tuple<Core.Entities.OrganizationUser, ICollection<CollectionAccessSelection>>> GetByIdWithCollectionsAsync(Guid id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public DatabaseContext(DbContextOptions<DatabaseContext> options)
public DbSet<ServiceAccountProjectAccessPolicy> ServiceAccountProjectAccessPolicy { get; set; }
public DbSet<UserServiceAccountAccessPolicy> UserServiceAccountAccessPolicy { get; set; }
public DbSet<GroupServiceAccountAccessPolicy> GroupServiceAccountAccessPolicy { get; set; }
public DbSet<UserSecretAccessPolicy> UserSecretAccessPolicy { get; set; }
public DbSet<GroupSecretAccessPolicy> GroupSecretAccessPolicy { get; set; }
public DbSet<ServiceAccountSecretAccessPolicy> ServiceAccountSecretAccessPolicy { get; set; }
public DbSet<ApiKey> ApiKeys { get; set; }
public DbSet<Cipher> Ciphers { get; set; }
public DbSet<Collection> Collections { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ public void Configure(EntityTypeBuilder<AccessPolicy> builder)
.HasDiscriminator<string>("Discriminator")
.HasValue<UserProjectAccessPolicy>(AccessPolicyDiscriminator.UserProject)
.HasValue<UserServiceAccountAccessPolicy>(AccessPolicyDiscriminator.UserServiceAccount)
.HasValue<UserSecretAccessPolicy>(AccessPolicyDiscriminator.UserSecret)
.HasValue<GroupProjectAccessPolicy>(AccessPolicyDiscriminator.GroupProject)
.HasValue<GroupServiceAccountAccessPolicy>(AccessPolicyDiscriminator.GroupServiceAccount)
.HasValue<ServiceAccountProjectAccessPolicy>(AccessPolicyDiscriminator.ServiceAccountProject);
.HasValue<GroupSecretAccessPolicy>(AccessPolicyDiscriminator.GroupSecret)
.HasValue<ServiceAccountProjectAccessPolicy>(AccessPolicyDiscriminator.ServiceAccountProject)
.HasValue<ServiceAccountSecretAccessPolicy>(AccessPolicyDiscriminator.ServiceAccountSecret);

builder
.Property(s => s.Id)
Expand Down Expand Up @@ -63,6 +66,26 @@ public void Configure(EntityTypeBuilder<UserServiceAccountAccessPolicy> builder)
}
}

public class UserSecretAccessPolicyEntityTypeConfiguration : IEntityTypeConfiguration<UserSecretAccessPolicy>
{
public void Configure(EntityTypeBuilder<UserSecretAccessPolicy> builder)
{
builder
.Property(e => e.OrganizationUserId)
.HasColumnName(nameof(UserSecretAccessPolicy.OrganizationUserId));

builder
.Property(e => e.GrantedSecretId)
.HasColumnName(nameof(UserSecretAccessPolicy.GrantedSecretId));

builder
.HasOne(e => e.GrantedSecret)
.WithMany(e => e.UserAccessPolicies)
.HasForeignKey(nameof(UserSecretAccessPolicy.GrantedSecretId))
.OnDelete(DeleteBehavior.Cascade);
}
}

public class GroupProjectAccessPolicyEntityTypeConfiguration : IEntityTypeConfiguration<GroupProjectAccessPolicy>
{
public void Configure(EntityTypeBuilder<GroupProjectAccessPolicy> builder)
Expand Down Expand Up @@ -109,6 +132,32 @@ public void Configure(EntityTypeBuilder<GroupServiceAccountAccessPolicy> builder
}
}

public class GroupSecretAccessPolicyEntityTypeConfiguration : IEntityTypeConfiguration<GroupSecretAccessPolicy>
{
public void Configure(EntityTypeBuilder<GroupSecretAccessPolicy> builder)
{
builder
.Property(e => e.GroupId)
.HasColumnName(nameof(GroupSecretAccessPolicy.GroupId));

builder
.Property(e => e.GrantedSecretId)
.HasColumnName(nameof(GroupSecretAccessPolicy.GrantedSecretId));

builder
.HasOne(e => e.GrantedSecret)
.WithMany(e => e.GroupAccessPolicies)
.HasForeignKey(nameof(GroupSecretAccessPolicy.GrantedSecretId))
.OnDelete(DeleteBehavior.Cascade);

builder
.HasOne(e => e.Group)
.WithMany()
.HasForeignKey(nameof(GroupSecretAccessPolicy.GroupId))
.OnDelete(DeleteBehavior.Cascade);
}
}

public class ServiceAccountProjectAccessPolicyEntityTypeConfiguration : IEntityTypeConfiguration<ServiceAccountProjectAccessPolicy>
{
public void Configure(EntityTypeBuilder<ServiceAccountProjectAccessPolicy> builder)
Expand All @@ -128,3 +177,23 @@ public void Configure(EntityTypeBuilder<ServiceAccountProjectAccessPolicy> build
.OnDelete(DeleteBehavior.Cascade);
}
}

public class ServiceAccountSecretAccessPolicyEntityTypeConfiguration : IEntityTypeConfiguration<ServiceAccountSecretAccessPolicy>
{
public void Configure(EntityTypeBuilder<ServiceAccountSecretAccessPolicy> builder)
{
builder
.Property(e => e.ServiceAccountId)
.HasColumnName(nameof(ServiceAccountSecretAccessPolicy.ServiceAccountId));

builder
.Property(e => e.GrantedSecretId)
.HasColumnName(nameof(ServiceAccountSecretAccessPolicy.GrantedSecretId));

builder
.HasOne(e => e.GrantedSecret)
.WithMany(e => e.ServiceAccountAccessPolicies)
.HasForeignKey(nameof(ServiceAccountSecretAccessPolicy.GrantedSecretId))
.OnDelete(DeleteBehavior.Cascade);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ public static class AccessPolicyDiscriminator
{
public const string UserProject = "user_project";
public const string UserServiceAccount = "user_service_account";
public const string UserSecret = "user_secret";
public const string GroupProject = "group_project";
public const string GroupServiceAccount = "group_service_account";
public const string GroupSecret = "group_secret";
public const string ServiceAccountProject = "service_account_project";

public const string ServiceAccountSecret = "service_account_secret";
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
.ReverseMap()
.ForMember(dst => dst.User, opt => opt.MapFrom(src => src.OrganizationUser.User));

CreateMap<Core.SecretsManager.Entities.UserSecretAccessPolicy, UserSecretAccessPolicy>()
.ForMember(dst => dst.GrantedSecret, opt => opt.Ignore())
.ForMember(dst => dst.OrganizationUser, opt => opt.Ignore())
.ReverseMap()
.ForMember(dst => dst.User, opt => opt.MapFrom(src => src.OrganizationUser.User));

CreateMap<Core.SecretsManager.Entities.GroupProjectAccessPolicy, GroupProjectAccessPolicy>()
.ForMember(dst => dst.GrantedProject, opt => opt.Ignore())
.ForMember(dst => dst.Group, opt => opt.Ignore())
Expand All @@ -34,10 +40,20 @@
.ForMember(dst => dst.Group, opt => opt.Ignore())
.ReverseMap();

CreateMap<Core.SecretsManager.Entities.GroupSecretAccessPolicy, GroupSecretAccessPolicy>()
.ForMember(dst => dst.GrantedSecret, opt => opt.Ignore())
.ForMember(dst => dst.Group, opt => opt.Ignore())
.ReverseMap();

CreateMap<Core.SecretsManager.Entities.ServiceAccountProjectAccessPolicy, ServiceAccountProjectAccessPolicy>()
.ForMember(dst => dst.GrantedProject, opt => opt.Ignore())
.ForMember(dst => dst.ServiceAccount, opt => opt.Ignore())
.ReverseMap();

CreateMap<Core.SecretsManager.Entities.ServiceAccountSecretAccessPolicy, ServiceAccountSecretAccessPolicy>()
.ForMember(dst => dst.GrantedSecret, opt => opt.Ignore())
.ForMember(dst => dst.ServiceAccount, opt => opt.Ignore())
.ReverseMap();
}
}

Expand All @@ -61,6 +77,14 @@
public virtual ServiceAccount GrantedServiceAccount { get; set; }
}

public class UserSecretAccessPolicy : AccessPolicy
{
public Guid? OrganizationUserId { get; set; }
public virtual OrganizationUser OrganizationUser { get; set; }
public Guid? GrantedSecretId { get; set; }
public virtual Secret GrantedSecret { get; set; }

Check warning on line 85 in src/Infrastructure.EntityFramework/SecretsManager/Models/AccessPolicy.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/SecretsManager/Models/AccessPolicy.cs#L82-L85

Added lines #L82 - L85 were not covered by tests
}

public class GroupProjectAccessPolicy : AccessPolicy
{
public Guid? GroupId { get; set; }
Expand All @@ -77,10 +101,27 @@
public virtual ServiceAccount GrantedServiceAccount { get; set; }
}

public class GroupSecretAccessPolicy : AccessPolicy
{
public Guid? GroupId { get; set; }
public virtual Group Group { get; set; }
public Guid? GrantedSecretId { get; set; }
public virtual Secret GrantedSecret { get; set; }

Check warning on line 109 in src/Infrastructure.EntityFramework/SecretsManager/Models/AccessPolicy.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/SecretsManager/Models/AccessPolicy.cs#L106-L109

Added lines #L106 - L109 were not covered by tests
}

public class ServiceAccountProjectAccessPolicy : AccessPolicy
{
public Guid? ServiceAccountId { get; set; }
public virtual ServiceAccount ServiceAccount { get; set; }
public Guid? GrantedProjectId { get; set; }
public virtual Project GrantedProject { get; set; }
}

public class ServiceAccountSecretAccessPolicy : AccessPolicy
{
public Guid? ServiceAccountId { get; set; }
public virtual ServiceAccount ServiceAccount { get; set; }
public Guid? GrantedSecretId { get; set; }
public virtual Secret GrantedSecret { get; set; }

Check warning on line 125 in src/Infrastructure.EntityFramework/SecretsManager/Models/AccessPolicy.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/SecretsManager/Models/AccessPolicy.cs#L122-L125

Added lines #L122 - L125 were not covered by tests
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@

public class Secret : Core.SecretsManager.Entities.Secret
{
public virtual new ICollection<Project> Projects { get; set; }
public new virtual ICollection<Project> Projects { get; set; }
public virtual Organization Organization { get; set; }
public virtual ICollection<UserSecretAccessPolicy> UserAccessPolicies { get; set; }
public virtual ICollection<GroupSecretAccessPolicy> GroupAccessPolicies { get; set; }
public virtual ICollection<ServiceAccountSecretAccessPolicy> ServiceAccountAccessPolicies { get; set; }

Check warning on line 12 in src/Infrastructure.EntityFramework/SecretsManager/Models/Secret.cs

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure.EntityFramework/SecretsManager/Models/Secret.cs#L10-L12

Added lines #L10 - L12 were not covered by tests
}

public class SecretMapperProfile : Profile
Expand Down
Loading
Loading