@ -1,6 +1,7 @@
@@ -1,6 +1,7 @@
using System.Linq.Expressions ;
using AutoMapper ;
using Bit.Core.Enums ;
using Bit.Core.SecretsManager.Models.Data ;
using Bit.Core.SecretsManager.Repositories ;
using Bit.Infrastructure.EntityFramework ;
using Bit.Infrastructure.EntityFramework.Repositories ;
@ -35,40 +36,25 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
@@ -35,40 +36,25 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
{
var dbContext = GetDatabaseContext ( scope ) ;
var secrets = await dbContext . Secret
. Where ( c = > ids . Contains ( c . Id ) & & c . DeletedDate = = null )
. Include ( c = > c . Projects )
. ToListAsync ( ) ;
. Where ( c = > ids . Contains ( c . Id ) & & c . DeletedDate = = null )
. Include ( c = > c . Projects )
. ToListAsync ( ) ;
return Mapper . Map < List < Core . SecretsManager . Entities . Secret > > ( secrets ) ;
}
}
private static Expression < Func < Secret , bool > > ServiceAccountHasReadAccessToSecret ( Guid serviceAccountId ) = > s = >
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 . Projects . Any ( p = >
p . UserAccessPolicies . Any ( ap = > ap . OrganizationUser . UserId = = userId & & ap . Read ) | |
p . GroupAccessPolicies . Any ( ap = >
ap . Group . GroupUsers . Any ( gu = > gu . OrganizationUser . UserId = = userId & & ap . Read ) ) ) ;
public async Task < IEnumerable < Core . SecretsManager . Entities . Secret > > GetManyByOrganizationIdAsync ( Guid organizationId , Guid userId , AccessClientType accessType )
public async Task < IEnumerable < SecretPermissionDetails > > GetManyByOrganizationIdAsync ( Guid organizationId , Guid userId , AccessClientType accessType )
{
using var scope = ServiceScopeFactory . CreateScope ( ) ;
var dbContext = GetDatabaseContext ( scope ) ;
var query = dbContext . Secret . Include ( c = > c . Projects ) . Where ( c = > c . OrganizationId = = organizationId & & c . DeletedDate = = null ) ;
var query = dbContext . Secret
. Include ( c = > c . Projects )
. Where ( c = > c . OrganizationId = = organizationId & & c . DeletedDate = = null )
. OrderBy ( s = > s . RevisionDate ) ;
query = accessType switch
{
AccessClientType . NoAccessCheck = > query ,
AccessClientType . User = > query . Where ( UserHasReadAccessToSecret ( userId ) ) ,
AccessClientType . ServiceAccount = > query . Where ( ServiceAccountHasReadAccessToSecret ( userId ) ) ,
_ = > throw new ArgumentOutOfRangeException ( nameof ( accessType ) , accessType , null ) ,
} ;
var secrets = SecretToPermissionDetails ( query , userId , accessType ) ;
var secrets = await query . OrderBy ( c = > c . RevisionDate ) . ToListAsync ( ) ;
return Mapper . Map < List < Core . SecretsManager . Entities . Secret > > ( secrets ) ;
return await secrets . ToListAsync ( ) ;
}
public async Task < IEnumerable < Core . SecretsManager . Entities . Secret > > GetManyByOrganizationIdInTrashByIdsAsync ( Guid organizationId , IEnumerable < Guid > ids )
@ -86,7 +72,7 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
@@ -86,7 +72,7 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
}
}
public async Task < IEnumerable < Core . SecretsManager . Entities . Secret > > GetManyByOrganizationIdInTrashAsync ( Guid organizationId )
public async Task < IEnumerable < SecretPermissionDetails > > GetManyByOrganizationIdInTrashAsync ( Guid organizationId )
{
using ( var scope = ServiceScopeFactory . CreateScope ( ) )
{
@ -97,29 +83,26 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
@@ -97,29 +83,26 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
. OrderBy ( c = > c . RevisionDate )
. ToListAsync ( ) ;
return Mapper . Map < List < Core . SecretsManager . Entities . Secret > > ( secrets ) ;
// This should be changed if/when we allow non admins to access trashed items
return Mapper . Map < List < Core . SecretsManager . Entities . Secret > > ( secrets ) . Select ( s = > new SecretPermissionDetails
{
Secret = s ,
Read = true ,
Write = true ,
} ) ;
}
}
public async Task < IEnumerable < Core . SecretsManager . Entities . Secret > > GetManyByProjectIdAsync ( Guid projectId , Guid userId , AccessClientType accessType )
public async Task < IEnumerable < SecretPermissionDetails > > GetManyByProjectIdAsync ( Guid projectId , Guid userId , AccessClientType accessType )
{
using ( var scope = ServiceScopeFactory . CreateScope ( ) )
{
var dbContext = GetDatabaseContext ( scope ) ;
var query = dbContext . Secret . Include ( s = > s . Projects )
. Where ( s = > s . Projects . Any ( p = > p . Id = = projectId ) & & s . DeletedDate = = null ) ;
using var scope = ServiceScopeFactory . CreateScope ( ) ;
var dbContext = GetDatabaseContext ( scope ) ;
var query = dbContext . Secret . Include ( s = > s . Projects )
. Where ( s = > s . Projects . Any ( p = > p . Id = = projectId ) & & s . DeletedDate = = null ) ;
query = accessType switch
{
AccessClientType . NoAccessCheck = > query ,
AccessClientType . User = > query . Where ( UserHasReadAccessToSecret ( userId ) ) ,
AccessClientType . ServiceAccount = > query . Where ( ServiceAccountHasReadAccessToSecret ( userId ) ) ,
_ = > throw new ArgumentOutOfRangeException ( nameof ( accessType ) , accessType , null ) ,
} ;
var secrets = SecretToPermissionDetails ( query , userId , accessType ) ;
var secrets = await query . OrderBy ( s = > s . RevisionDate ) . ToListAsync ( ) ;
return Mapper . Map < List < Core . SecretsManager . Entities . Secret > > ( secrets ) ;
}
return await secrets . ToListAsync ( ) ;
}
public override async Task < Core . SecretsManager . Entities . Secret > CreateAsync ( Core . SecretsManager . Entities . Secret secret )
@ -272,4 +255,85 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
@@ -272,4 +255,85 @@ public class SecretRepository : Repository<Core.SecretsManager.Entities.Secret,
await dbContext . SaveChangesAsync ( ) ;
}
}
public async Task < ( bool Read , bool Write ) > AccessToSecretAsync ( Guid id , Guid userId , AccessClientType accessType )
{
using var scope = ServiceScopeFactory . CreateScope ( ) ;
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 policy = await query . FirstOrDefaultAsync ( ) ;
return ( policy . Read , policy . Write ) ;
}
private IQueryable < SecretPermissionDetails > SecretToPermissionDetails ( IQueryable < Secret > query , Guid userId , AccessClientType accessType )
{
var secrets = accessType switch
{
AccessClientType . NoAccessCheck = > query . Select ( s = > new SecretPermissionDetails
{
Secret = Mapper . Map < Bit . Core . SecretsManager . Entities . Secret > ( s ) ,
Read = true ,
Write = true ,
} ) ,
AccessClientType . User = > query . Where ( UserHasReadAccessToSecret ( userId ) ) . Select ( SecretToPermissionsUser ( userId , true ) ) ,
AccessClientType . ServiceAccount = > query . Where ( ServiceAccountHasReadAccessToSecret ( userId ) ) . Select ( s = >
new SecretPermissionDetails
{
Secret = Mapper . Map < Bit . Core . SecretsManager . Entities . Secret > ( s ) ,
Read = true ,
Write = false ,
} ) ,
_ = > throw new ArgumentOutOfRangeException ( nameof ( accessType ) , accessType , null ) ,
} ;
return secrets ;
}
private Expression < Func < Secret , SecretPermissionDetails > > SecretToPermissionsUser ( Guid userId , bool read ) = >
s = > new SecretPermissionDetails
{
Secret = Mapper . Map < Bit . 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 ) ) ) ,
} ;
private static Expression < Func < Secret , bool > > ServiceAccountHasReadAccessToSecret ( Guid serviceAccountId ) = > s = >
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 . Projects . Any ( p = >
p . UserAccessPolicies . Any ( ap = > ap . OrganizationUser . UserId = = userId & & ap . Read ) | |
p . GroupAccessPolicies . Any ( ap = >
ap . Group . GroupUsers . Any ( gu = > gu . OrganizationUser . UserId = = userId & & ap . Read ) ) ) ;
}