Skip to content

Commit

Permalink
AccessToken security group retrieval strategy.
Browse files Browse the repository at this point in the history
  • Loading branch information
alistar-andrei committed Aug 1, 2024
1 parent ee6d439 commit a3038d8
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace FoundationaLLM.Common.Constants.Authentication
{
/// <summary>
/// Additional claim constants that are not included in <see cref="Microsoft.Identity.Web.ClaimConstants"></see>.
/// </summary>
public static class EntraUserClaimConstants
{
/// <summary>
/// Groups claim.
/// </summary>
public const string Groups = "groups";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@ public static class SecurityGroupRetrievalStrategies
/// Identity management service.
/// </summary>
public const string IdentityManagementService = "IdentityManagementService";

/// <summary>
/// Access token groups claim.
/// </summary>
public const string AccessToken = "AccessToken";
}
}
9 changes: 9 additions & 0 deletions src/dotnet/Common/Interfaces/IUserClaimsProviderService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,14 @@ public interface IUserClaimsProviderService
/// </summary>
/// <param name="userPrincipal">The <see cref="ClaimsPrincipal"/> object providing details about the security principal.</param>
bool IsServicePrincipal(ClaimsPrincipal userPrincipal);

/// <summary>
/// Returns a list of security group identifiers from the provided
/// <see cref="ClaimsPrincipal"/>.
/// </summary>
/// <param name="userPrincipal">The principal that provides multiple
/// claims-based identities.</param>
/// <returns></returns>
List<string>? GetSecurityGroupIds(ClaimsPrincipal? userPrincipal);
}
}
22 changes: 16 additions & 6 deletions src/dotnet/Common/Middleware/CallContextMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,24 @@ public async Task InvokeAsync(
// Extract from ClaimsPrincipal if available:
callContext.CurrentUserIdentity = claimsProviderService.GetUserIdentity(context.User);

// We are only expanding group membership for User objects
// Service Principal permissions must be assigned directly and not over group membership.
if (callContext.CurrentUserIdentity != null
&& !claimsProviderService.IsServicePrincipal(context.User)
&& instanceSettings.Value.SecurityGroupRetrievalStrategy == SecurityGroupRetrievalStrategies.IdentityManagementService)
&& !claimsProviderService.IsServicePrincipal(context.User))
{
// We are only expanding group membership for User objects
// Service Principal permissions must be assigned directly and not over group membership.
callContext.CurrentUserIdentity.GroupIds = await identityManagementService.GetGroupsForPrincipal(
callContext.CurrentUserIdentity.UserId!);
switch(instanceSettings.Value.SecurityGroupRetrievalStrategy)
{
case SecurityGroupRetrievalStrategies.IdentityManagementService:
callContext.CurrentUserIdentity.GroupIds = await identityManagementService.GetGroupsForPrincipal(
callContext.CurrentUserIdentity.UserId!);
break;
case SecurityGroupRetrievalStrategies.AccessToken:
callContext.CurrentUserIdentity.GroupIds = claimsProviderService.GetSecurityGroupIds(context.User) ?? [];
break;
case SecurityGroupRetrievalStrategies.None:
default:
break;
}
}
}
else
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using FoundationaLLM.Common.Interfaces;
using FoundationaLLM.Common.Constants.Authentication;
using FoundationaLLM.Common.Interfaces;
using FoundationaLLM.Common.Models.Authentication;
using Microsoft.Identity.Web;
using System.Security.Claims;
Expand Down Expand Up @@ -27,6 +28,16 @@ public class EntraUserClaimsProviderService : IUserClaimsProviderService
};
}

/// <inheritdoc/>
public List<string>? GetSecurityGroupIds(ClaimsPrincipal? userPrincipal)
{
if (userPrincipal == null)
{
return null;
}
return userPrincipal.Claims.Where(c => c.Type == EntraUserClaimConstants.Groups).Select(x => x?.Value).ToList()!;
}

/// <inheritdoc/>
public bool IsServicePrincipal(ClaimsPrincipal userPrincipal) =>
// Service Principal tokens do not have a "scp" claim
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
using FoundationaLLM.Common.Interfaces;
using FoundationaLLM.Common.Models.Authentication;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace FoundationaLLM.Common.Services.Security
{
Expand All @@ -18,6 +13,9 @@ public class NoOpUserClaimsProviderService : IUserClaimsProviderService
/// <inheritdoc/>
public UnifiedUserIdentity? GetUserIdentity(ClaimsPrincipal? userPrincipal) => null;

/// <inheritdoc/>
public List<string>? GetSecurityGroupIds(ClaimsPrincipal? userPrincipal) => null;

/// <inheritdoc/>
public bool IsServicePrincipal(ClaimsPrincipal userPrincipal) => false;
}
Expand Down

0 comments on commit a3038d8

Please sign in to comment.