| | | 1 | | using Elsa.Authorization; |
| | | 2 | | using FastEndpoints; |
| | | 3 | | using Microsoft.AspNetCore.Builder; |
| | | 4 | | using Microsoft.AspNetCore.Http; |
| | | 5 | | using Microsoft.Extensions.DependencyInjection; |
| | | 6 | | |
| | | 7 | | namespace Elsa.Abstractions; |
| | | 8 | | |
| | | 9 | | /// <summary> |
| | | 10 | | /// The one implementation behind every base class's security helpers. The base classes cannot share a |
| | | 11 | | /// common ancestor of their own, so the logic lives here rather than being copied six times. |
| | | 12 | | /// </summary> |
| | | 13 | | internal static class EndpointSecurity |
| | | 14 | | { |
| | | 15 | | /// <summary>Used when the host has registered no evaluator of its own. Stateless, so sharing is safe.</summary> |
| | 0 | 16 | | private static readonly IPermissionEvaluator SharedEvaluator = new PermissionEvaluator(); |
| | | 17 | | |
| | | 18 | | /// <summary> |
| | | 19 | | /// Requires a permission satisfying <paramref name="resource"/> and <paramref name="verb"/>. The |
| | | 20 | | /// requirement is attached as an inline policy so it needs no separate policy registration, and it is |
| | | 21 | | /// evaluated by <see cref="IPermissionEvaluator"/> like every other permission decision. |
| | | 22 | | /// </summary> |
| | | 23 | | public static void RequirePermission(EndpointDefinition definition, string resource, string verb) |
| | | 24 | | { |
| | 324 | 25 | | if (!EndpointSecurityOptions.SecurityIsEnabled) |
| | | 26 | | { |
| | 12 | 27 | | definition.AllowAnonymous(); |
| | 12 | 28 | | return; |
| | | 29 | | } |
| | | 30 | | |
| | 312 | 31 | | var permission = new Permission(resource, verb); |
| | | 32 | | |
| | 312 | 33 | | EndpointPermissionRegistry.Record(definition.EndpointType, permission); |
| | | 34 | | |
| | | 35 | | // Evaluated inline rather than through a registered IAuthorizationHandler. A handler would make |
| | | 36 | | // enforcement depend on the host having called AddElsaAuthorization: miss it, and every endpoint |
| | | 37 | | // answers 403 with nothing to indicate why. Hosts that wire FastEndpoints themselves -- several |
| | | 38 | | // test hosts among them -- do exactly that. The evaluator is stateless, so falling back to a shared |
| | | 39 | | // instance is safe, while a host that registers its own still wins. |
| | 1032 | 40 | | definition.Options(x => x.RequireAuthorization(policy => policy.RequireAssertion(context => |
| | 1032 | 41 | | { |
| | 30 | 42 | | var evaluator = (context.Resource as HttpContext)?.RequestServices.GetService<IPermissionEvaluator>() ?? Sha |
| | 1032 | 43 | | |
| | 30 | 44 | | return evaluator.HasPermission(context.User, permission); |
| | 1032 | 45 | | }))); |
| | 312 | 46 | | } |
| | | 47 | | |
| | | 48 | | /// <summary> |
| | | 49 | | /// Requires an authenticated caller but no permission. FR-019's third declaration state: it exists so |
| | | 50 | | /// that a deliberate "needs an identity, needs no grant" choice is distinguishable from an author who |
| | | 51 | | /// forgot to declare anything, which the coverage gate would otherwise have to treat alike. |
| | | 52 | | /// </summary> |
| | | 53 | | public static void RequireAuthenticatedOnly(EndpointDefinition definition) |
| | | 54 | | { |
| | 3 | 55 | | if (!EndpointSecurityOptions.SecurityIsEnabled) |
| | | 56 | | { |
| | 0 | 57 | | definition.AllowAnonymous(); |
| | 0 | 58 | | return; |
| | | 59 | | } |
| | | 60 | | |
| | 9 | 61 | | definition.Options(x => x.RequireAuthorization(policy => policy.RequireAuthenticatedUser())); |
| | 3 | 62 | | } |
| | | 63 | | |
| | | 64 | | /// <summary>The legacy string-based declaration, preserved for modules outside this repository.</summary> |
| | | 65 | | public static void ConfigurePermissions(EndpointDefinition definition, string[] permissions) |
| | | 66 | | { |
| | 0 | 67 | | if (!EndpointSecurityOptions.SecurityIsEnabled) |
| | 0 | 68 | | definition.AllowAnonymous(); |
| | | 69 | | else |
| | 0 | 70 | | definition.Permissions([PermissionNames.All, .. permissions]); |
| | 0 | 71 | | } |
| | | 72 | | } |