1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 15:42:48 -05:00

[SM-378] Enable SM on a user basis (#2590)

* Add support for giving individual users access to secrets manager
This commit is contained in:
Oscar Hinton
2023-01-31 18:38:53 +01:00
committed by GitHub
parent 54353f8b6c
commit cf25d55090
57 changed files with 1419 additions and 400 deletions

View File

@ -1,6 +1,6 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Utilities;
namespace Bit.Core.Context;
@ -9,14 +9,16 @@ public class CurrentContentOrganization
{
public CurrentContentOrganization() { }
public CurrentContentOrganization(OrganizationUser orgUser)
public CurrentContentOrganization(OrganizationUserOrganizationDetails orgUser)
{
Id = orgUser.OrganizationId;
Type = orgUser.Type;
Permissions = CoreHelpers.LoadClassFromJsonData<Permissions>(orgUser.Permissions);
AccessSecretsManager = orgUser.AccessSecretsManager && orgUser.UseSecretsManager;
}
public Guid Id { get; set; }
public OrganizationUserType Type { get; set; }
public Permissions Permissions { get; set; }
public bool AccessSecretsManager { get; set; }
}

View File

@ -157,6 +157,10 @@ public class CurrentContext : ICurrentContext
private List<CurrentContentOrganization> GetOrganizations(Dictionary<string, IEnumerable<Claim>> claimsDict, bool orgApi)
{
var accessSecretsManager = claimsDict.ContainsKey(Claims.SecretsManagerAccess)
? claimsDict[Claims.SecretsManagerAccess].ToDictionary(s => s.Value, _ => true)
: new Dictionary<string, bool>();
var organizations = new List<CurrentContentOrganization>();
if (claimsDict.ContainsKey(Claims.OrganizationOwner))
{
@ -164,7 +168,8 @@ public class CurrentContext : ICurrentContext
new CurrentContentOrganization
{
Id = new Guid(c.Value),
Type = OrganizationUserType.Owner
Type = OrganizationUserType.Owner,
AccessSecretsManager = accessSecretsManager.ContainsKey(c.Value),
}));
}
else if (orgApi && OrganizationId.HasValue)
@ -172,7 +177,7 @@ public class CurrentContext : ICurrentContext
organizations.Add(new CurrentContentOrganization
{
Id = OrganizationId.Value,
Type = OrganizationUserType.Owner
Type = OrganizationUserType.Owner,
});
}
@ -182,7 +187,8 @@ public class CurrentContext : ICurrentContext
new CurrentContentOrganization
{
Id = new Guid(c.Value),
Type = OrganizationUserType.Admin
Type = OrganizationUserType.Admin,
AccessSecretsManager = accessSecretsManager.ContainsKey(c.Value),
}));
}
@ -192,7 +198,8 @@ public class CurrentContext : ICurrentContext
new CurrentContentOrganization
{
Id = new Guid(c.Value),
Type = OrganizationUserType.User
Type = OrganizationUserType.User,
AccessSecretsManager = accessSecretsManager.ContainsKey(c.Value),
}));
}
@ -202,7 +209,8 @@ public class CurrentContext : ICurrentContext
new CurrentContentOrganization
{
Id = new Guid(c.Value),
Type = OrganizationUserType.Manager
Type = OrganizationUserType.Manager,
AccessSecretsManager = accessSecretsManager.ContainsKey(c.Value),
}));
}
@ -213,7 +221,8 @@ public class CurrentContext : ICurrentContext
{
Id = new Guid(c.Value),
Type = OrganizationUserType.Custom,
Permissions = SetOrganizationPermissionsFromClaims(c.Value, claimsDict)
Permissions = SetOrganizationPermissionsFromClaims(c.Value, claimsDict),
AccessSecretsManager = accessSecretsManager.ContainsKey(c.Value),
}));
}
@ -434,12 +443,17 @@ public class CurrentContext : ICurrentContext
return po?.ProviderId;
}
public bool AccessSecretsManager(Guid orgId)
{
return Organizations?.Any(o => o.Id == orgId && o.AccessSecretsManager) ?? false;
}
public async Task<ICollection<CurrentContentOrganization>> OrganizationMembershipAsync(
IOrganizationUserRepository organizationUserRepository, Guid userId)
{
if (Organizations == null)
{
var userOrgs = await organizationUserRepository.GetManyByUserAsync(userId);
var userOrgs = await organizationUserRepository.GetManyDetailsByUserAsync(userId);
Organizations = userOrgs.Where(ou => ou.Status == OrganizationUserStatusType.Confirmed)
.Select(ou => new CurrentContentOrganization(ou)).ToList();
}

View File

@ -68,4 +68,5 @@ public interface ICurrentContext
IProviderUserRepository providerUserRepository, Guid userId);
Task<Guid?> ProviderIdForOrg(Guid orgId);
bool AccessSecretsManager(Guid organizationId);
}

View File

@ -22,6 +22,7 @@ public class OrganizationUser : ITableObject<Guid>, IExternal
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
public string Permissions { get; set; }
public bool AccessSecretsManager { get; set; }
public void SetNewId()
{

View File

@ -6,6 +6,7 @@ public static class Claims
public const string SecurityStamp = "sstamp";
public const string Premium = "premium";
public const string Device = "device";
public const string OrganizationOwner = "orgowner";
public const string OrganizationAdmin = "orgadmin";
public const string OrganizationManager = "orgmanager";
@ -14,6 +15,8 @@ public static class Claims
public const string ProviderAdmin = "providerprovideradmin";
public const string ProviderServiceUser = "providerserviceuser";
public const string SecretsManagerAccess = "accesssecretsmanager";
// Service Account
public const string Organization = "organization";

View File

@ -8,6 +8,7 @@ public class OrganizationUserInvite
public IEnumerable<string> Emails { get; set; }
public Enums.OrganizationUserType? Type { get; set; }
public bool AccessAll { get; set; }
public bool AccessSecretsManager { get; set; }
public Permissions Permissions { get; set; }
public IEnumerable<CollectionAccessSelection> Collections { get; set; }
public IEnumerable<Guid> Groups { get; set; }
@ -19,6 +20,7 @@ public class OrganizationUserInvite
Emails = requestModel.Emails;
Type = requestModel.Type;
AccessAll = requestModel.AccessAll;
AccessSecretsManager = requestModel.AccessSecretsManager;
Collections = requestModel.Collections;
Groups = requestModel.Groups;
Permissions = requestModel.Permissions;

View File

@ -7,6 +7,7 @@ public class OrganizationUserInviteData
public IEnumerable<string> Emails { get; set; }
public OrganizationUserType? Type { get; set; }
public bool AccessAll { get; set; }
public bool AccessSecretsManager { get; set; }
public IEnumerable<CollectionAccessSelection> Collections { get; set; }
public IEnumerable<Guid> Groups { get; set; }
public Permissions Permissions { get; set; }

View File

@ -41,4 +41,5 @@ public class OrganizationUserOrganizationDetails
public DateTime? FamilySponsorshipLastSyncDate { get; set; }
public DateTime? FamilySponsorshipValidUntil { get; set; }
public bool? FamilySponsorshipToDelete { get; set; }
public bool AccessSecretsManager { get; set; }
}

View File

@ -17,6 +17,7 @@ public class OrganizationUserUserDetails : IExternal, ITwoFactorProvidersUser
public OrganizationUserStatusType Status { get; set; }
public OrganizationUserType Type { get; set; }
public bool AccessAll { get; set; }
public bool AccessSecretsManager { get; set; }
public string ExternalId { get; set; }
public string SsoExternalId { get; set; }
public string Permissions { get; set; }

View File

@ -1241,6 +1241,7 @@ public class OrganizationService : IOrganizationService
Type = invite.Type.Value,
Status = OrganizationUserStatusType.Invited,
AccessAll = invite.AccessAll,
AccessSecretsManager = invite.AccessSecretsManager,
ExternalId = externalId,
CreationDate = DateTime.UtcNow,
RevisionDate = DateTime.UtcNow,

View File

@ -692,6 +692,15 @@ public static class CoreHelpers
default:
break;
}
// Secrets Manager
foreach (var org in group)
{
if (org.AccessSecretsManager)
{
claims.Add(new KeyValuePair<string, string>(Claims.SecretsManagerAccess, org.Id.ToString()));
}
}
}
}