Skip to content

Commit

Permalink
fix: added support to create access groups
Browse files Browse the repository at this point in the history
  • Loading branch information
pksorensen committed Nov 12, 2024
1 parent 2a413ca commit ed0ab48
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace EAVFW.Extensions.EasyAuth.MicrosoftEntraId
public interface IEntraIDSecurityGroup
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid? EntraIdGroupId { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security.AccessControl;
using System.Security.Claims;
using System.Threading.Tasks;
using static IdentityModel.OidcConstants;
Expand All @@ -26,21 +27,24 @@ namespace EAVFW.Extensions.EasyAuth.MicrosoftEntraId

public class MicrosoftEntraEasyAuthProvider<TContext,TSecurityGroup, TSecurityGroupMember,TIdentity> : DefaultAuthProvider
where TContext : DynamicContext
where TSecurityGroup : DynamicEntity, IEntraIDSecurityGroup
where TSecurityGroup : DynamicEntity, IEntraIDSecurityGroup,new()
where TSecurityGroupMember : DynamicEntity, ISecurityGroupMember, new()
where TIdentity : DynamicEntity, IIdentity
{
private readonly IOptions<MicrosoftEntraIdEasyAuthOptions> _options;
private readonly IOptions<EAVFrameworkOptions> _frameworkOptions;
private readonly IHttpClientFactory _clientFactory;


public MicrosoftEntraEasyAuthProvider() :base("MicrosoftEntraId", HttpMethod.Post) { }

public MicrosoftEntraEasyAuthProvider(
IOptions<MicrosoftEntraIdEasyAuthOptions> options,
IOptions<EAVFrameworkOptions> frameworkOptions,
IHttpClientFactory clientFactory) : this()
{
_options = options ?? throw new System.ArgumentNullException(nameof(options));
_frameworkOptions = frameworkOptions;
_clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory));
}

Expand Down Expand Up @@ -169,13 +173,18 @@ private async Task SyncUserGroup(ClaimsPrincipal identity, List<Guid> groupIds,
// Fetch in memory
var groupMembersDict = await groupMembersQuery.ToDictionaryAsync(sgm => sgm.Id);

await EnsureAccessGroupsCreated(db);


// Fetch all security groups
var groupsDict = await db.Set<TSecurityGroup>()
.Where(sg => groupMembersQuery.Any(sgm => sgm.SecurityGroupId == sg.Id) ||
(sg.EntraIdGroupId != null && groupIds.Contains(sg.EntraIdGroupId.Value)))
.ToDictionaryAsync(sg => sg.Id);




// Fetch specific security group and group members
var sgGroupSpecific = groupsDict.Values.Where(sg => sg.EntraIdGroupId != null && groupIds.Contains(sg.EntraIdGroupId.Value)).ToDictionary(sg => sg.Id);
var sgmGroupSpecific = groupMembersDict.Values.Where(sgm => sgm.SecurityGroupId != null && sgGroupSpecific.ContainsKey((Guid) sgm.SecurityGroupId));
Expand All @@ -197,7 +206,7 @@ private async Task SyncUserGroup(ClaimsPrincipal identity, List<Guid> groupIds,

// Fecth expired group members by comparing the "historical" group members with that of the current based on the group ids
var expiredGroupMembers = groupMembersDict.Values.Where(sgm =>
!sgmGroupSpecific.Any(x => x.Id == sgm.Id) &&
!sgmGroupSpecific.Any(x => x.Id == sgm.Id) &&
sgm.SecurityGroupId != null &&
groupsDict[(Guid) sgm.SecurityGroupId].EntraIdGroupId != null); // Groups of higher aurthority has no EntraGroupId and should not be removed
foreach (var sgm in expiredGroupMembers)
Expand All @@ -209,6 +218,28 @@ private async Task SyncUserGroup(ClaimsPrincipal identity, List<Guid> groupIds,
if (isDirty) await db.SaveChangesAsync(identity);
}

private async Task EnsureAccessGroupsCreated(EAVDBContext<DynamicContext> db)
{
var groups = _options.Value.AccessGroups.Where(kv => !string.IsNullOrEmpty(kv.Value)).Select(c => c.Key).ToArray();
var existingGrouos = await db.Set<TSecurityGroup>().Where(g => groups.Contains(g.Name)).ToListAsync();
var missingGroups = groups.Except(existingGrouos.Select(g => g.Name)).ToArray();
foreach (var missingGroup in missingGroups)
{
var group = new TSecurityGroup();
group.Name = missingGroup;
group.EntraIdGroupId = Guid.Parse(_options.Value.AccessGroups[missingGroup]);
db.Add(group);

existingGrouos.Add(group);
}
foreach (var group in existingGrouos)
{
if (!group.EntraIdGroupId.HasValue)
group.EntraIdGroupId = Guid.Parse(_options.Value.AccessGroups[group.Name]);
}
await db.SaveChangesAsync(_frameworkOptions.Value.SystemAdministratorIdentity);
}

public RequestDelegate OnSignedOut()

Check warning on line 243 in src/EAVFW.Extensions.EasyAuth.MicrosoftEntraId/MicrosoftEntraEasyAuthProvider.cs

View workflow job for this annotation

GitHub Actions / Releasing

'MicrosoftEntraEasyAuthProvider<TContext, TSecurityGroup, TSecurityGroupMember, TIdentity>.OnSignedOut()' hides inherited member 'DefaultAuthProvider.OnSignedOut()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.

Check warning on line 243 in src/EAVFW.Extensions.EasyAuth.MicrosoftEntraId/MicrosoftEntraEasyAuthProvider.cs

View workflow job for this annotation

GitHub Actions / Releasing

'MicrosoftEntraEasyAuthProvider<TContext, TSecurityGroup, TSecurityGroupMember, TIdentity>.OnSignedOut()' hides inherited member 'DefaultAuthProvider.OnSignedOut()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
{
throw new System.NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static AuthenticatedEAVFrameworkBuilder AddMicrosoftEntraIdEasyAuth<TCont
Func<HttpContext, string> getMicrosoftAuthorizationUrl , Func<HttpContext, string> getMicrosoftTokenEndpoint)
where TContext : DynamicContext
where TIdentity: DynamicEntity,IIdentity
where TSecurityGroup : DynamicEntity, IEntraIDSecurityGroup
where TSecurityGroup : DynamicEntity, IEntraIDSecurityGroup,new()
where TSecurityGroupMemeber : DynamicEntity, ISecurityGroupMember, new()
{
builder.AddAuthenticationProvider<MicrosoftEntraEasyAuthProvider<TContext,TSecurityGroup,TSecurityGroupMemeber,TIdentity>,
Expand All @@ -53,7 +53,7 @@ public static AuthenticatedEAVFrameworkBuilder AddMicrosoftEntraIdEasyAuth<TCont
Func<OnCallbackRequest, IEnumerable<Claim>, Task<Guid>> findIdentityAsync)
where TContext : DynamicContext
where TIdentity : DynamicEntity, IIdentity
where TSecurityGroup : DynamicEntity, IEntraIDSecurityGroup
where TSecurityGroup : DynamicEntity, IEntraIDSecurityGroup,new()
where TSecurityGroupMemeber : DynamicEntity, ISecurityGroupMember,new()
{
builder.AddAuthenticationProvider<MicrosoftEntraEasyAuthProvider<TContext,TSecurityGroup, TSecurityGroupMemeber, TIdentity>, MicrosoftEntraIdEasyAuthOptions, IConfiguration>((options, config) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ private static string DefaultGetMicrosoftTokenEndpoint(HttpContext context)
return $"https://login.microsoftonline.com/{options.Value.TenantId}/oauth2/v2.0/token";
}


public Dictionary<string,string> AccessGroups { get; set; } = new Dictionary<string, string>();

}
}

0 comments on commit ed0ab48

Please sign in to comment.