using System.Security.Claims; using System.Text.Json; namespace Campaign_Tracker.Server.Authorization; public static class ApplicationRole { public const string ClientServices = "ClientServices"; public const string Production = "Production"; public const string Transportation = "Transportation"; public const string Support = "Support"; public const string Admin = "Admin"; private static readonly IReadOnlyDictionary Aliases = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["client-services"] = ClientServices, ["clientservices"] = ClientServices, ["production-lead"] = Production, ["production"] = Production, ["transportation"] = Transportation, ["support-analyst"] = Support, ["support"] = Support, ["operations-admin"] = Admin, ["admin"] = Admin, }; public static string? Normalize(string role) { return Aliases.TryGetValue(role, out var normalized) ? normalized : null; } public static string[] NormalizeMany(IEnumerable roles) { return roles .Select(Normalize) .OfType() .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray(); } public static bool HasAny(IEnumerable roles, params string[] requiredRoles) { var normalizedRoles = NormalizeMany(roles); return normalizedRoles.Contains(Admin, StringComparer.OrdinalIgnoreCase) || normalizedRoles.Intersect(requiredRoles, StringComparer.OrdinalIgnoreCase).Any(); } public static IEnumerable ExtractKeycloakRoles(IEnumerable claims, string clientId) { foreach (var claim in claims) { if (claim.Type == ClaimTypes.Role || claim.Type == "roles") { yield return claim.Value; continue; } if (claim.Type == "realm_access") { foreach (var role in ExtractRolesFromJson(claim.Value)) { yield return role; } continue; } if (claim.Type == "resource_access") { foreach (var role in ExtractResourceRolesFromJson(claim.Value, clientId)) { yield return role; } } } } private static IEnumerable ExtractRolesFromJson(string json) { using var document = ParseJsonOrDefault(json); if (document is null || !document.RootElement.TryGetProperty("roles", out var roles) || roles.ValueKind != JsonValueKind.Array) { yield break; } foreach (var role in roles.EnumerateArray()) { if (role.ValueKind == JsonValueKind.String) { yield return role.GetString()!; } } } private static IEnumerable ExtractResourceRolesFromJson(string json, string clientId) { using var document = ParseJsonOrDefault(json); if (document is null || !document.RootElement.TryGetProperty(clientId, out var clientAccess)) { yield break; } foreach (var role in ExtractRolesFromJson(clientAccess.GetRawText())) { yield return role; } } private static JsonDocument? ParseJsonOrDefault(string json) { try { return JsonDocument.Parse(json); } catch (JsonException) { return null; } } }