From b02c644e6465fcb8f31a0902dd981d6fcd3ae8e8 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Sat, 22 Apr 2023 11:10:44 +0200 Subject: [PATCH] Implement admin API key provider --- .../Features/DefaultAuthenticationFeature.cs | 33 +++++++++++++++++-- .../Elsa.Identity/Features/IdentityFeature.cs | 3 -- .../Providers/AdminApiKeyProvider.cs | 27 +++++++++++++++ .../Elsa.Samples.WorkflowServer/Program.cs | 2 +- 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 src/modules/Elsa.Identity/Providers/AdminApiKeyProvider.cs diff --git a/src/modules/Elsa.Identity/Features/DefaultAuthenticationFeature.cs b/src/modules/Elsa.Identity/Features/DefaultAuthenticationFeature.cs index d3d3c80d4..48e29ba8b 100644 --- a/src/modules/Elsa.Identity/Features/DefaultAuthenticationFeature.cs +++ b/src/modules/Elsa.Identity/Features/DefaultAuthenticationFeature.cs @@ -5,6 +5,7 @@ using Elsa.Features.Attributes; using Elsa.Features.Services; using Elsa.Identity.Providers; using Elsa.Requirements; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.DependencyInjection; @@ -18,19 +19,42 @@ namespace Elsa.Identity.Features; public class DefaultAuthenticationFeature : FeatureBase { private const string MultiScheme = "Jwt-or-ApiKey"; + private Func _configureApiKeyAuthorization = builder => builder.AddApiKeyInAuthorizationHeader(); /// public DefaultAuthenticationFeature(IModule module) : base(module) { } + /// + /// Gets or sets the . + /// + public Type ApiKeyProviderType { get; set; } = typeof(DefaultApiKeyProvider); + + /// + /// Configures the API key provider type. + /// + /// The type of the API key provider. + /// The current . + public DefaultAuthenticationFeature UseApiKeyAuthorization() where T : class, IApiKeyProvider + { + _configureApiKeyAuthorization = builder => builder.AddApiKeyInAuthorizationHeader(); + return this; + } + + /// + /// Configures the API key provider type to . + /// + /// The current . + public DefaultAuthenticationFeature UseAdminApiKeyAuthorization() => UseApiKeyAuthorization(); + /// public override void Apply() { Services.ConfigureOptions(); Services.ConfigureOptions(); - Services + var authBuilder = Services .AddAuthentication(MultiScheme) .AddPolicyScheme(MultiScheme, MultiScheme, options => { @@ -41,10 +65,13 @@ public class DefaultAuthenticationFeature : FeatureBase : JwtBearerDefaults.AuthenticationScheme; }; }) - .AddJwtBearer() - .AddApiKeyInAuthorizationHeader(); + .AddJwtBearer(); + + _configureApiKeyAuthorization(authBuilder); Services.AddSingleton(); + Services.AddSingleton(ApiKeyProviderType); + Services.AddSingleton(sp => (IApiKeyProvider)sp.GetRequiredService(ApiKeyProviderType)); Services.AddAuthorization(options => options.AddPolicy(IdentityPolicyNames.SecurityRoot, policy => policy.AddRequirements(new LocalHostRequirement()))); } } \ No newline at end of file diff --git a/src/modules/Elsa.Identity/Features/IdentityFeature.cs b/src/modules/Elsa.Identity/Features/IdentityFeature.cs index 2fefaefa2..7ad33fba1 100644 --- a/src/modules/Elsa.Identity/Features/IdentityFeature.cs +++ b/src/modules/Elsa.Identity/Features/IdentityFeature.cs @@ -179,9 +179,6 @@ public class IdentityFeature : FeatureBase .AddSingleton() .AddSingleton() .AddSingleton(); - - // API Key. - Services.AddSingleton(); // Services. Services diff --git a/src/modules/Elsa.Identity/Providers/AdminApiKeyProvider.cs b/src/modules/Elsa.Identity/Providers/AdminApiKeyProvider.cs new file mode 100644 index 000000000..0fb8a189b --- /dev/null +++ b/src/modules/Elsa.Identity/Providers/AdminApiKeyProvider.cs @@ -0,0 +1,27 @@ +using System.Security.Claims; +using AspNetCore.Authentication.ApiKey; +using Elsa.Identity.Models; + +namespace Elsa.Identity.Providers; + +/// +/// Provides an with admin privileges for the default admin API key. +/// +public class AdminApiKeyProvider : IApiKeyProvider +{ + /// + /// The default admin API key. + /// + public static readonly string DefaultApiKey = Guid.Empty.ToString(); + + /// + public Task ProvideAsync(string key) + { + if(key != DefaultApiKey) + return Task.FromResult(null); + + var claims = new List { new("permissions", "*") }; + var apiKey = new ApiKey(key, "admin", claims); + return Task.FromResult(apiKey)!; + } +} \ No newline at end of file diff --git a/src/samples/aspnet/Elsa.Samples.WorkflowServer/Program.cs b/src/samples/aspnet/Elsa.Samples.WorkflowServer/Program.cs index fd81d7171..77a916806 100644 --- a/src/samples/aspnet/Elsa.Samples.WorkflowServer/Program.cs +++ b/src/samples/aspnet/Elsa.Samples.WorkflowServer/Program.cs @@ -40,7 +40,7 @@ builder.Services.AddElsa(elsa => }); // Use default authentication (JWT). - elsa.UseDefaultAuthentication(); + elsa.UseDefaultAuthentication(auth => auth.UseAdminApiKeyAuthorization()); // Register custom activities. elsa.AddActivity();