mirror of
https://github.com/bitwarden/server.git
synced 2025-01-21 21:41:21 +01:00
[SM-654] Add support for direct secret permissions at the repo layer (#4156)
* calculate direct secret permissions at the repo layer * Add integration tests for service account secret access count
This commit is contained in:
parent
7f496e7399
commit
0e6e461602
@ -289,35 +289,13 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
|
||||
|
||||
public async Task<(bool Read, bool Write)> AccessToSecretAsync(Guid id, Guid userId, AccessClientType accessType)
|
||||
{
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
await using var scope = ServiceScopeFactory.CreateAsyncScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
|
||||
var secret = dbContext.Secret
|
||||
.Where(s => s.Id == id);
|
||||
|
||||
var query = accessType switch
|
||||
{
|
||||
AccessClientType.NoAccessCheck => secret.Select(_ => new { Read = true, Write = true }),
|
||||
AccessClientType.User => secret.Select(s => new
|
||||
{
|
||||
Read = s.Projects.Any(p =>
|
||||
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Read) ||
|
||||
p.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Read))),
|
||||
Write = s.Projects.Any(p =>
|
||||
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Write) ||
|
||||
p.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Write))),
|
||||
}),
|
||||
AccessClientType.ServiceAccount => secret.Select(s => new
|
||||
{
|
||||
Read = s.Projects.Any(p =>
|
||||
p.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccountId == userId && ap.Read)),
|
||||
Write = s.Projects.Any(p =>
|
||||
p.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccountId == userId && ap.Write)),
|
||||
}),
|
||||
_ => secret.Select(_ => new { Read = false, Write = false }),
|
||||
};
|
||||
var query = BuildSecretAccessQuery(secret, userId, accessType);
|
||||
|
||||
var policy = await query.FirstOrDefaultAsync();
|
||||
|
||||
@ -361,19 +339,27 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
|
||||
private Expression<Func<Secret, SecretPermissionDetails>> SecretToPermissionsUser(Guid userId, bool read) =>
|
||||
s => new SecretPermissionDetails
|
||||
{
|
||||
Secret = Mapper.Map<Bit.Core.SecretsManager.Entities.Secret>(s),
|
||||
Secret = Mapper.Map<Core.SecretsManager.Entities.Secret>(s),
|
||||
Read = read,
|
||||
Write = s.Projects.Any(p =>
|
||||
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Write) ||
|
||||
p.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Write))),
|
||||
Write =
|
||||
s.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Write) ||
|
||||
s.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Write)) ||
|
||||
s.Projects.Any(p =>
|
||||
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Write) ||
|
||||
p.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Write)))
|
||||
};
|
||||
|
||||
private static Expression<Func<Secret, bool>> ServiceAccountHasReadAccessToSecret(Guid serviceAccountId) => s =>
|
||||
s.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccountId == serviceAccountId && ap.Read) ||
|
||||
s.Projects.Any(p =>
|
||||
p.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccount.Id == serviceAccountId && ap.Read));
|
||||
|
||||
private static Expression<Func<Secret, bool>> UserHasReadAccessToSecret(Guid userId) => s =>
|
||||
s.UserAccessPolicies.Any(ap => ap.OrganizationUser.UserId == userId && ap.Read) ||
|
||||
s.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.UserId == userId && ap.Read)) ||
|
||||
s.Projects.Any(p =>
|
||||
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.UserId == userId && ap.Read) ||
|
||||
p.GroupAccessPolicies.Any(ap =>
|
||||
@ -434,4 +420,40 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
|
||||
.ExecuteUpdateAsync(setters => setters.SetProperty(b => b.RevisionDate, utcNow));
|
||||
}
|
||||
}
|
||||
|
||||
private static IQueryable<SecretAccess> BuildSecretAccessQuery(IQueryable<Secret> secrets, Guid accessClientId,
|
||||
AccessClientType accessType) =>
|
||||
accessType switch
|
||||
{
|
||||
AccessClientType.NoAccessCheck => secrets.Select(s => new SecretAccess(s.Id, true, true)),
|
||||
AccessClientType.User => secrets.Select(s => new SecretAccess(
|
||||
s.Id,
|
||||
s.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == accessClientId && ap.Read) ||
|
||||
s.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == accessClientId && ap.Read)) ||
|
||||
s.Projects.Any(p =>
|
||||
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == accessClientId && ap.Read) ||
|
||||
p.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == accessClientId && ap.Read))),
|
||||
s.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == accessClientId && ap.Write) ||
|
||||
s.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == accessClientId && ap.Write)) ||
|
||||
s.Projects.Any(p =>
|
||||
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == accessClientId && ap.Write) ||
|
||||
p.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == accessClientId && ap.Write)))
|
||||
)),
|
||||
AccessClientType.ServiceAccount => secrets.Select(s => new SecretAccess(
|
||||
s.Id,
|
||||
s.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccountId == accessClientId && ap.Read) ||
|
||||
s.Projects.Any(p =>
|
||||
p.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccountId == accessClientId && ap.Read)),
|
||||
s.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccountId == accessClientId && ap.Write) ||
|
||||
s.Projects.Any(p =>
|
||||
p.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccountId == accessClientId && ap.Write))
|
||||
)),
|
||||
_ => secrets.Select(s => new SecretAccess(s.Id, false, false))
|
||||
};
|
||||
|
||||
private record SecretAccess(Guid Id, bool Read, bool Write);
|
||||
}
|
||||
|
@ -135,38 +135,37 @@ public class ServiceAccountRepository : Repository<Core.SecretsManager.Entities.
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ServiceAccountSecretsDetails>> GetManyByOrganizationIdWithSecretsDetailsAsync(
|
||||
Guid organizationId, Guid userId, AccessClientType accessType)
|
||||
Guid organizationId, Guid userId, AccessClientType accessType)
|
||||
{
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
await using var scope = ServiceScopeFactory.CreateAsyncScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var query = from sa in dbContext.ServiceAccount
|
||||
join ap in dbContext.ServiceAccountProjectAccessPolicy
|
||||
on sa.Id equals ap.ServiceAccountId into grouping
|
||||
from ap in grouping.DefaultIfEmpty()
|
||||
where sa.OrganizationId == organizationId
|
||||
select new
|
||||
{
|
||||
ServiceAccount = sa,
|
||||
AccessToSecrets = ap.GrantedProject.Secrets.Count(s => s.DeletedDate == null)
|
||||
};
|
||||
|
||||
query = accessType switch
|
||||
var serviceAccountQuery = dbContext.ServiceAccount.Where(c => c.OrganizationId == organizationId);
|
||||
serviceAccountQuery = accessType switch
|
||||
{
|
||||
AccessClientType.NoAccessCheck => query,
|
||||
AccessClientType.User => query.Where(c =>
|
||||
c.ServiceAccount.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Read) ||
|
||||
c.ServiceAccount.GroupAccessPolicies.Any(ap =>
|
||||
AccessClientType.NoAccessCheck => serviceAccountQuery,
|
||||
AccessClientType.User => serviceAccountQuery.Where(c =>
|
||||
c.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Read) ||
|
||||
c.GroupAccessPolicies.Any(ap =>
|
||||
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Read))),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(accessType), accessType, null),
|
||||
};
|
||||
|
||||
var results = (await query.ToListAsync())
|
||||
var projectSecretsAccessQuery = BuildProjectSecretsAccessQuery(dbContext, serviceAccountQuery);
|
||||
var directSecretAccessQuery = BuildDirectSecretAccessQuery(dbContext, serviceAccountQuery);
|
||||
|
||||
var projectSecretsAccessResults = await projectSecretsAccessQuery.ToListAsync();
|
||||
var directSecretAccessResults = await directSecretAccessQuery.ToListAsync();
|
||||
|
||||
var applicableDirectSecretAccessResults = FilterDirectSecretAccessResults(projectSecretsAccessResults, directSecretAccessResults);
|
||||
|
||||
var results = projectSecretsAccessResults.Concat(applicableDirectSecretAccessResults)
|
||||
.GroupBy(g => g.ServiceAccount)
|
||||
.Select(g =>
|
||||
new ServiceAccountSecretsDetails
|
||||
{
|
||||
ServiceAccount = Mapper.Map<Core.SecretsManager.Entities.ServiceAccount>(g.Key),
|
||||
AccessToSecrets = g.Sum(x => x.AccessToSecrets),
|
||||
AccessToSecrets = g.Sum(x => x.SecretIds.Count())
|
||||
}).OrderBy(c => c.ServiceAccount.RevisionDate).ToList();
|
||||
|
||||
return results;
|
||||
@ -200,4 +199,46 @@ public class ServiceAccountRepository : Repository<Core.SecretsManager.Entities.
|
||||
private static Expression<Func<ServiceAccount, bool>> UserHasWriteAccessToServiceAccount(Guid userId) => sa =>
|
||||
sa.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Write) ||
|
||||
sa.GroupAccessPolicies.Any(ap => ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Write));
|
||||
|
||||
private static IQueryable<ServiceAccountSecretsAccess> BuildProjectSecretsAccessQuery(DatabaseContext dbContext,
|
||||
IQueryable<ServiceAccount> serviceAccountQuery) =>
|
||||
from sa in serviceAccountQuery
|
||||
join ap in dbContext.ServiceAccountProjectAccessPolicy
|
||||
on sa.Id equals ap.ServiceAccountId into grouping
|
||||
from ap in grouping.DefaultIfEmpty()
|
||||
select new ServiceAccountSecretsAccess
|
||||
(
|
||||
sa, ap.GrantedProject.Secrets.Where(s => s.DeletedDate == null).Select(s => s.Id)
|
||||
);
|
||||
|
||||
private static IQueryable<ServiceAccountSecretsAccess> BuildDirectSecretAccessQuery(
|
||||
DatabaseContext dbContext,
|
||||
IQueryable<ServiceAccount> serviceAccountQuery) =>
|
||||
from sa in serviceAccountQuery
|
||||
join ap in dbContext.ServiceAccountSecretAccessPolicy
|
||||
on sa.Id equals ap.ServiceAccountId into grouping
|
||||
from ap in grouping.DefaultIfEmpty()
|
||||
where ap.GrantedSecret.DeletedDate == null &&
|
||||
ap.GrantedSecretId != null
|
||||
select new ServiceAccountSecretsAccess(sa,
|
||||
new List<Guid> { ap.GrantedSecretId.Value });
|
||||
|
||||
private static List<ServiceAccountSecretsAccess> FilterDirectSecretAccessResults(
|
||||
List<ServiceAccountSecretsAccess> projectSecretsAccessResults,
|
||||
List<ServiceAccountSecretsAccess> directSecretAccessResults) =>
|
||||
directSecretAccessResults.Where(directSecretAccessResult =>
|
||||
{
|
||||
var serviceAccountId = directSecretAccessResult.ServiceAccount.Id;
|
||||
var secretId = directSecretAccessResult.SecretIds.FirstOrDefault();
|
||||
if (secretId == Guid.Empty)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !projectSecretsAccessResults
|
||||
.Where(x => x.ServiceAccount.Id == serviceAccountId)
|
||||
.Any(x => x.SecretIds.Contains(secretId));
|
||||
}).ToList();
|
||||
|
||||
private record ServiceAccountSecretsAccess(ServiceAccount ServiceAccount, IEnumerable<Guid> SecretIds);
|
||||
}
|
||||
|
@ -49,5 +49,9 @@ public class ServiceAccountSecretsDetailsResponseModel : ServiceAccountResponseM
|
||||
AccessToSecrets = serviceAccountDetails.AccessToSecrets;
|
||||
}
|
||||
|
||||
public ServiceAccountSecretsDetailsResponseModel() : base(new ServiceAccount())
|
||||
{
|
||||
}
|
||||
|
||||
public int AccessToSecrets { get; set; }
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ public class ServiceAccountsControllerTests : IClassFixture<ApiApplicationFactor
|
||||
private readonly IAccessPolicyRepository _accessPolicyRepository;
|
||||
private readonly IApiKeyRepository _apiKeyRepository;
|
||||
private readonly IServiceAccountRepository _serviceAccountRepository;
|
||||
private readonly IProjectRepository _projectRepository;
|
||||
private readonly ISecretRepository _secretRepository;
|
||||
|
||||
private string _email = null!;
|
||||
private SecretsManagerOrganizationHelper _organizationHelper = null!;
|
||||
@ -40,6 +42,8 @@ public class ServiceAccountsControllerTests : IClassFixture<ApiApplicationFactor
|
||||
_serviceAccountRepository = _factory.GetService<IServiceAccountRepository>();
|
||||
_accessPolicyRepository = _factory.GetService<IAccessPolicyRepository>();
|
||||
_apiKeyRepository = _factory.GetService<IApiKeyRepository>();
|
||||
_secretRepository = _factory.GetService<ISecretRepository>();
|
||||
_projectRepository = _factory.GetService<IProjectRepository>();
|
||||
_loginHelper = new LoginHelper(_factory, _client);
|
||||
}
|
||||
|
||||
@ -73,51 +77,90 @@ public class ServiceAccountsControllerTests : IClassFixture<ApiApplicationFactor
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListByOrganization_Admin_Success()
|
||||
[Theory]
|
||||
[InlineData(PermissionType.RunAsAdmin)]
|
||||
[InlineData(PermissionType.RunAsUserWithPermission)]
|
||||
public async Task ListByOrganization_NoSecretAccess_Success(PermissionType permissionType)
|
||||
{
|
||||
var (org, _) = await _organizationHelper.Initialize(true, true, true);
|
||||
await _loginHelper.LoginAsync(_email);
|
||||
var (orgId, serviceAccountIds) = await SetupListByOrganizationRequestAsync(permissionType);
|
||||
|
||||
var serviceAccountIds = await SetupGetServiceAccountsByOrganizationAsync(org);
|
||||
|
||||
var response = await _client.GetAsync($"/organizations/{org.Id}/service-accounts");
|
||||
var response = await _client.GetAsync($"/organizations/{orgId}/service-accounts");
|
||||
response.EnsureSuccessStatusCode();
|
||||
var result = await response.Content.ReadFromJsonAsync<ListResponseModel<ServiceAccountResponseModel>>();
|
||||
var result = await response.Content
|
||||
.ReadFromJsonAsync<ListResponseModel<ServiceAccountSecretsDetailsResponseModel>>();
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result.Data);
|
||||
Assert.Equal(serviceAccountIds.Count, result.Data.Count());
|
||||
Assert.DoesNotContain(result.Data, x => x.AccessToSecrets != 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListByOrganization_User_Success()
|
||||
[Theory]
|
||||
[InlineData(PermissionType.RunAsAdmin)]
|
||||
[InlineData(PermissionType.RunAsUserWithPermission)]
|
||||
public async Task ListByOrganization_SecretAccess_Success(PermissionType permissionType)
|
||||
{
|
||||
var (org, _) = await _organizationHelper.Initialize(true, true, true);
|
||||
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
|
||||
await _loginHelper.LoginAsync(email);
|
||||
var (orgId, serviceAccountIds) = await SetupListByOrganizationRequestAsync(permissionType);
|
||||
var expectedAccess = await SetupServiceAccountSecretAccessAsync(serviceAccountIds, orgId);
|
||||
|
||||
var serviceAccountIds = await SetupGetServiceAccountsByOrganizationAsync(org);
|
||||
|
||||
// Setup access for two
|
||||
var accessPolicies = serviceAccountIds.Take(2).Select(
|
||||
id => new UserServiceAccountAccessPolicy
|
||||
{
|
||||
OrganizationUserId = orgUser.Id,
|
||||
GrantedServiceAccountId = id,
|
||||
Read = true,
|
||||
Write = false,
|
||||
}).Cast<BaseAccessPolicy>().ToList();
|
||||
|
||||
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
|
||||
|
||||
var response = await _client.GetAsync($"/organizations/{org.Id}/service-accounts");
|
||||
var response = await _client.GetAsync($"/organizations/{orgId}/service-accounts?includeAccessToSecrets=true");
|
||||
response.EnsureSuccessStatusCode();
|
||||
var result = await response.Content.ReadFromJsonAsync<ListResponseModel<ServiceAccountResponseModel>>();
|
||||
var result = await response.Content
|
||||
.ReadFromJsonAsync<ListResponseModel<ServiceAccountSecretsDetailsResponseModel>>();
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result.Data);
|
||||
Assert.Equal(2, result.Data.Count());
|
||||
Assert.Equal(serviceAccountIds.Count, result.Data.Count());
|
||||
|
||||
foreach (var item in expectedAccess)
|
||||
{
|
||||
var serviceAccountResult = result.Data.FirstOrDefault(x => x.Id == item.Key);
|
||||
Assert.NotNull(serviceAccountResult);
|
||||
Assert.Equal(item.Value, serviceAccountResult.AccessToSecrets);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async Task ListByOrganization_UserPartialAccess_ReturnsServiceAccountsUserHasAccessTo(
|
||||
bool includeAccessToSecrets)
|
||||
{
|
||||
var (orgId, serviceAccountIds) =
|
||||
await SetupListByOrganizationRequestAsync(PermissionType.RunAsUserWithPermission);
|
||||
var expectedAccess = await SetupServiceAccountSecretAccessAsync(serviceAccountIds, orgId);
|
||||
|
||||
var serviceAccountWithoutAccess = await _serviceAccountRepository.CreateAsync(new ServiceAccount
|
||||
{
|
||||
OrganizationId = orgId,
|
||||
Name = _mockEncryptedString
|
||||
});
|
||||
|
||||
var response =
|
||||
await _client.GetAsync(
|
||||
$"/organizations/{orgId}/service-accounts?includeAccessToSecrets={includeAccessToSecrets}");
|
||||
response.EnsureSuccessStatusCode();
|
||||
var result = await response.Content
|
||||
.ReadFromJsonAsync<ListResponseModel<ServiceAccountSecretsDetailsResponseModel>>();
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result.Data);
|
||||
Assert.Equal(serviceAccountIds.Count, result.Data.Count());
|
||||
Assert.DoesNotContain(result.Data, x => x.Id == serviceAccountWithoutAccess.Id);
|
||||
|
||||
if (includeAccessToSecrets)
|
||||
{
|
||||
foreach (var item in expectedAccess)
|
||||
{
|
||||
var serviceAccountResult = result.Data.FirstOrDefault(x => x.Id == item.Key);
|
||||
Assert.NotNull(serviceAccountResult);
|
||||
Assert.Equal(item.Value, serviceAccountResult.AccessToSecrets);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Contains(result.Data, x => x.AccessToSecrets == 0);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@ -824,10 +867,10 @@ public class ServiceAccountsControllerTests : IClassFixture<ApiApplicationFactor
|
||||
await _accessPolicyRepository.CreateManyAsync(new List<BaseAccessPolicy> { policy });
|
||||
}
|
||||
|
||||
private async Task<List<Guid>> SetupGetServiceAccountsByOrganizationAsync(Organization org)
|
||||
private async Task<List<Guid>> CreateServiceAccountsInOrganizationAsync(Organization org)
|
||||
{
|
||||
var serviceAccountIds = new List<Guid>();
|
||||
for (var i = 0; i < 3; i++)
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
var serviceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount
|
||||
{
|
||||
@ -870,4 +913,109 @@ public class ServiceAccountsControllerTests : IClassFixture<ApiApplicationFactor
|
||||
|
||||
return initialServiceAccount;
|
||||
}
|
||||
|
||||
private async Task<(Guid OrganizationId, List<Guid> ServiceAccountIds)> SetupListByOrganizationRequestAsync(PermissionType permissionType)
|
||||
{
|
||||
var (org, _) = await _organizationHelper.Initialize(true, true, true);
|
||||
await _loginHelper.LoginAsync(_email);
|
||||
|
||||
var serviceAccountIds = await CreateServiceAccountsInOrganizationAsync(org);
|
||||
|
||||
if (permissionType == PermissionType.RunAsAdmin)
|
||||
{
|
||||
return (org.Id, serviceAccountIds);
|
||||
}
|
||||
|
||||
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
|
||||
await _loginHelper.LoginAsync(email);
|
||||
|
||||
var accessPolicies = serviceAccountIds.Select(
|
||||
id => new UserServiceAccountAccessPolicy
|
||||
{
|
||||
OrganizationUserId = orgUser.Id,
|
||||
GrantedServiceAccountId = id,
|
||||
Read = true,
|
||||
Write = false,
|
||||
}).Cast<BaseAccessPolicy>().ToList();
|
||||
|
||||
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
|
||||
|
||||
return (org.Id, serviceAccountIds);
|
||||
}
|
||||
|
||||
private async Task<Dictionary<Guid, int>> SetupServiceAccountSecretAccessAsync(List<Guid> serviceAccountIds,
|
||||
Guid organizationId)
|
||||
{
|
||||
var project =
|
||||
await _projectRepository.CreateAsync(new Project
|
||||
{
|
||||
Name = _mockEncryptedString,
|
||||
OrganizationId = organizationId
|
||||
});
|
||||
|
||||
var secret = await _secretRepository.CreateAsync(new Secret
|
||||
{
|
||||
Key = _mockEncryptedString,
|
||||
Value = _mockEncryptedString,
|
||||
OrganizationId = organizationId,
|
||||
Projects = [project]
|
||||
});
|
||||
|
||||
var secretNoProject = await _secretRepository.CreateAsync(new Secret
|
||||
{
|
||||
Key = _mockEncryptedString,
|
||||
Value = _mockEncryptedString,
|
||||
OrganizationId = organizationId
|
||||
});
|
||||
|
||||
var serviceAccountWithProjectAccess = serviceAccountIds[0];
|
||||
var serviceAccountWithProjectAndSecretAccess = serviceAccountIds[1];
|
||||
var serviceAccountWithSecretAccess = serviceAccountIds[2];
|
||||
var serviceAccountWithNoAccess = serviceAccountIds[3];
|
||||
await _accessPolicyRepository.CreateManyAsync([
|
||||
new ServiceAccountProjectAccessPolicy
|
||||
{
|
||||
ServiceAccountId = serviceAccountWithProjectAccess,
|
||||
GrantedProjectId = project.Id,
|
||||
Read = true,
|
||||
Write = true
|
||||
},
|
||||
new ServiceAccountProjectAccessPolicy
|
||||
{
|
||||
ServiceAccountId = serviceAccountWithProjectAndSecretAccess,
|
||||
GrantedProjectId = project.Id,
|
||||
Read = true,
|
||||
Write = true
|
||||
},
|
||||
new ServiceAccountSecretAccessPolicy
|
||||
{
|
||||
ServiceAccountId = serviceAccountWithProjectAndSecretAccess,
|
||||
GrantedSecretId = secret.Id,
|
||||
Read = true,
|
||||
Write = true
|
||||
},
|
||||
new ServiceAccountSecretAccessPolicy
|
||||
{
|
||||
ServiceAccountId = serviceAccountWithProjectAndSecretAccess,
|
||||
GrantedSecretId = secretNoProject.Id,
|
||||
Read = true,
|
||||
Write = true
|
||||
},
|
||||
new ServiceAccountSecretAccessPolicy
|
||||
{
|
||||
ServiceAccountId = serviceAccountWithSecretAccess,
|
||||
GrantedSecretId = secretNoProject.Id,
|
||||
Read = true,
|
||||
Write = true
|
||||
}
|
||||
]);
|
||||
|
||||
return new Dictionary<Guid, int>
|
||||
{
|
||||
{ serviceAccountWithProjectAccess, 1 },
|
||||
{ serviceAccountWithProjectAndSecretAccess, 2 },
|
||||
{ serviceAccountWithSecretAccess, 1 },
|
||||
{ serviceAccountWithNoAccess, 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user