1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-04 20:50:21 -05:00

WIP: parsing claims from context

This commit is contained in:
Thomas Rittson 2025-04-01 11:10:23 +10:00
parent 3ec9e318b1
commit ef30805d0e
No known key found for this signature in database
GPG Key ID: CDDDA03861C35E27
4 changed files with 82 additions and 8 deletions

View File

@ -0,0 +1,76 @@
#nullable enable
using System.Security.Claims;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Identity;
namespace Bit.Api.AdminConsole.Authorization;
public static class ClaimsExtensions
{
public static CurrentContextOrganization? GetCurrentContextOrganization(this ClaimsPrincipal user, Guid organizationId)
{
var claimsDict = user.Claims
.GroupBy(c => c.Type)
.ToDictionary(c => c.Key, c => c.Select(v => v));
var accessSecretsManager = claimsDict.TryGetValue(Claims.SecretsManagerAccess, out var value)
? value
.Where(s => Guid.TryParse(s.Value, out _))
.Select(s => new Guid(s.Value))
.ToHashSet()
: [];
var role = claimsDict.GetRoleForOrganizationId(organizationId);
if (!role.HasValue)
{
// Not an organization member
return null;
}
return new CurrentContextOrganization
{
Id = organizationId,
Type = role.Value,
AccessSecretsManager = accessSecretsManager.Contains(organizationId),
Permissions = role == OrganizationUserType.Custom
? CurrentContext.SetOrganizationPermissionsFromClaims(organizationId.ToString(), claimsDict)
: null
};
}
private static bool ContainsOrganizationId(this Dictionary<string, IEnumerable<Claim>> claimsDict, string claimType,
Guid organizationId)
=> claimsDict.TryGetValue(claimType, out var claimValue) &&
claimValue.Any(c => c.Value.EqualsGuid(organizationId));
private static OrganizationUserType? GetRoleForOrganizationId(this Dictionary<string, IEnumerable<Claim>> claimsDict,
Guid organizationId)
{
if (claimsDict.ContainsOrganizationId(Claims.OrganizationOwner, organizationId))
{
return OrganizationUserType.Owner;
}
if (claimsDict.ContainsOrganizationId(Claims.OrganizationAdmin, organizationId))
{
return OrganizationUserType.Admin;
}
if (claimsDict.ContainsOrganizationId(Claims.OrganizationCustom, organizationId))
{
return OrganizationUserType.Custom;
}
if (claimsDict.ContainsOrganizationId(Claims.OrganizationUser, organizationId))
{
return OrganizationUserType.User;
}
return null;
}
private static bool EqualsGuid(this string value, Guid guid)
=> Guid.TryParse(value, out var parsedValue) && parsedValue == guid;
}

View File

@ -1,7 +1,5 @@
#nullable enable
using Bit.Api.AdminConsole.Context;
using Bit.Core.Context;
using Microsoft.AspNetCore.Authorization;
namespace Bit.Api.AdminConsole.Authorization;
@ -12,8 +10,6 @@ namespace Bit.Api.AdminConsole.Authorization;
/// determine whether the action is authorized.
/// </summary>
public class OrganizationRequirementHandler(
ICurrentContext currentContext,
IProviderOrganizationContext providerOrganizationContext,
IHttpContextAccessor httpContextAccessor)
: AuthorizationHandler<IOrganizationRequirement>
{
@ -25,7 +21,8 @@ public class OrganizationRequirementHandler(
throw new Exception("No organizationId found in route. IOrganizationRequirement cannot be used on this endpoint.");
}
var organizationClaims = currentContext.GetOrganization(organizationId.Value);
var organizationClaims = context.User.GetCurrentContextOrganization(organizationId.Value);
var providerOrganizationContext = null; // TODO
var authorized = await requirement.AuthorizeAsync(organizationId.Value, organizationClaims, providerOrganizationContext);

View File

@ -257,10 +257,11 @@ public class Startup
// Add authentication and authorization to the request pipeline.
app.UseAuthentication();
// Note: ICurrentContext is used in authorization middleware so it must be registered first
app.UseMiddleware<CurrentContextMiddleware>();
app.UseAuthorization();
// Add current context
app.UseMiddleware<CurrentContextMiddleware>();
// Add endpoints to the request pipeline.
app.UseEndpoints(endpoints =>
{

View File

@ -512,7 +512,7 @@ public class CurrentContext : ICurrentContext
return claims[type].FirstOrDefault()?.Value;
}
private Permissions SetOrganizationPermissionsFromClaims(string organizationId, Dictionary<string, IEnumerable<Claim>> claimsDict)
public static Permissions SetOrganizationPermissionsFromClaims(string organizationId, Dictionary<string, IEnumerable<Claim>> claimsDict)
{
bool hasClaim(string claimKey)
{