elsa-core/src/modules/Elsa.Identity/Services/RoleManager.cs
Sipke Schoorstra 07f788afb8
fix(identity): isolate in-memory roles by tenant (#8032)
* fix(identity): isolate in-memory roles by tenant

* fix(identity): retain legacy default-tenant roles
2026-09-05 19:01:42 -07:00

50 lines
1.6 KiB
C#

using Elsa.Common.Multitenancy;
using Elsa.Identity.Contracts;
using Elsa.Identity.Entities;
using Elsa.Identity.Models;
using Humanizer;
namespace Elsa.Identity.Services;
/// <summary>
/// Default implementation of <see cref="IRoleManager"/>.
/// </summary>
public class RoleManager(IRoleStore roleStore, IRoleProvider roleProvider, ITenantAccessor tenantAccessor) : IRoleManager
{
/// <inheritdoc />
public async Task<CreateRoleResult> CreateRoleAsync(
string name,
ICollection<string>? permissions = null,
string? id = null,
CancellationToken cancellationToken = default)
{
var roleId = id ?? name.Kebaberize();
if (await RoleExistsAsync(roleId, cancellationToken))
throw new InvalidOperationException($"A role with ID '{roleId}' already exists.");
var role = new Role
{
Id = roleId,
Name = name,
// The in-memory path does not run EF's ApplyTenantId saving handler.
TenantId = tenantAccessor.TenantId,
Permissions = permissions ?? new List<string>()
};
await roleStore.SaveAsync(role, cancellationToken);
return new CreateRoleResult(role);
}
private async Task<bool> RoleExistsAsync(string roleId, CancellationToken cancellationToken)
{
var storedRole = await roleStore.FindAsync(new() { Id = roleId }, cancellationToken);
if (storedRole != null)
return true;
var providedRoles = await roleProvider.FindManyAsync(new() { Id = roleId }, cancellationToken);
return providedRoles.Any(x => x.Id == roleId);
}
}