| | | 1 | | using Elsa.Authorization; |
| | | 2 | | using Elsa.ExternalAuthentication.Contracts; |
| | | 3 | | using Elsa.ExternalAuthentication.Models; |
| | | 4 | | using Elsa.ExternalAuthentication.Services; |
| | | 5 | | using Microsoft.AspNetCore.Http; |
| | | 6 | | using Microsoft.Extensions.DependencyInjection; |
| | | 7 | | |
| | | 8 | | namespace Elsa.ExternalAuthentication.Endpoints.Connections; |
| | | 9 | | |
| | | 10 | | internal static class ConnectionEndpointSupport |
| | | 11 | | { |
| | | 12 | | public static bool TryGetExpectedRevision(HttpContext context, out long revision) |
| | | 13 | | { |
| | 30 | 14 | | revision = 0; |
| | 30 | 15 | | var value = context.Request.Headers.IfMatch.FirstOrDefault(); |
| | 30 | 16 | | return !string.IsNullOrWhiteSpace(value) && value is ['"', _, ..] && value[^1] == '"' && long.TryParse(value[1.. |
| | | 17 | | } |
| | | 18 | | |
| | 40 | 19 | | public static void SetEtag(HttpContext context, long revision) => context.Response.Headers.ETag = $"\"{revision}\""; |
| | | 20 | | |
| | 18 | 21 | | public static Task SendMutationResultAsync(HttpContext context, ManagementConnectionMutationResult result, IdentityP |
| | 18 | 22 | | { |
| | 0 | 23 | | ManagementConnectionMutationResult.NotFound => SendErrorAsync(context, StatusCodes.Status404NotFound, "not_found |
| | 0 | 24 | | ManagementConnectionMutationResult.Forbidden => SendErrorAsync(context, StatusCodes.Status403Forbidden, "forbidd |
| | 4 | 25 | | ManagementConnectionMutationResult.Conflict conflict => SendErrorAsync(context, StatusCodes.Status409Conflict, " |
| | 2 | 26 | | ManagementConnectionMutationResult.PreconditionFailed conflict => SendErrorAsync(context, StatusCodes.Status412P |
| | 12 | 27 | | ManagementConnectionMutationResult.ValidationFailed validation => SendErrorAsync(context, StatusCodes.Status400B |
| | 0 | 28 | | _ => throw new InvalidOperationException("A successful connection mutation must be handled by the endpoint.") |
| | 18 | 29 | | }; |
| | | 30 | | |
| | | 31 | | public static Task SendErrorAsync(HttpContext context, int statusCode, string error, string message, object? details |
| | | 32 | | { |
| | 27 | 33 | | context.Response.StatusCode = statusCode; |
| | 27 | 34 | | return context.Response.WriteAsJsonAsync( |
| | 27 | 35 | | new ManagementErrorResponse(error, message, details, BrokerErrorFactory.CreateCorrelationId()), |
| | 27 | 36 | | cancellationToken); |
| | | 37 | | } |
| | | 38 | | |
| | 9 | 39 | | public static Task SendErrorAsync(HttpContext context, int statusCode, string error, string message, CancellationTok |
| | | 40 | | |
| | | 41 | | /// <summary> |
| | | 42 | | /// Whether the acting user holds <paramref name="resource"/> and <paramref name="verb"/>. |
| | | 43 | | /// </summary> |
| | | 44 | | /// <remarks> |
| | | 45 | | /// These are the checks an endpoint makes after its own <c>RequirePermission</c> gate has passed, for the |
| | | 46 | | /// extra operations a single request can opt into: managing a policy, revoking sessions, or confirming an |
| | | 47 | | /// unsafe setting. Routing them through <see cref="IPermissionEvaluator"/> is what makes a wildcard grant |
| | | 48 | | /// mean the same thing here as it does on the gate itself. Comparing claim values directly, as this used |
| | | 49 | | /// to, also silently stopped matching anything once the legacy permission names were retired. |
| | | 50 | | /// </remarks> |
| | | 51 | | public static bool HasPermission(HttpContext context, string resource, string verb) => |
| | 19 | 52 | | (context.RequestServices.GetService<IPermissionEvaluator>() ?? PermissionEvaluator.Shared).HasPermission(context |
| | 40 | 53 | | public static bool RequiresPolicyManagement(ConnectionRequest request) => request.UnlinkedPolicy is not null || requ |
| | 30 | 54 | | public static bool IsDatabaseOwned(EffectiveIdentityProviderConnection connection) => connection.Ownership == Connec |
| | | 55 | | } |