From bdc9d47c091d079827e2f655bf42f0dac36b5f7a Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Thu, 28 Dec 2023 21:54:06 +0100 Subject: [PATCH] Add API key authentication for Elsa client Introduced an `ApiKeyHttpMessageHandler` to use an API key as the authorization header for Elsa API client. This ensures secure interaction with the Elsa server. Also made updates to the `ElsaClientOptions` class to include the API key. An `AddElsaClient` method is added with the API key parameter in `DependencyInjectionExtensions` class for convenience. --- .../DependencyInjectionExtensions.cs | 26 ++++++++++++++++ .../ApiKeyHttpMessageHandler.cs | 30 +++++++++++++++++++ .../Options/ElsaClientOptions.cs | 6 ++-- 3 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 src/clients/Elsa.Api.Client/HttpMessageHandlers/ApiKeyHttpMessageHandler.cs diff --git a/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs b/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs index d3864079a1..a16717ead4 100644 --- a/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs +++ b/src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs @@ -2,6 +2,7 @@ using System.Text.Json.Serialization; using Elsa.Api.Client.Contracts; using Elsa.Api.Client.Converters; +using Elsa.Api.Client.HttpMessageHandlers; using Elsa.Api.Client.Options; using Elsa.Api.Client.Resources.ActivityDescriptorOptions.Contracts; using Elsa.Api.Client.Resources.ActivityDescriptors.Contracts; @@ -31,6 +32,31 @@ namespace Elsa.Api.Client.Extensions; [PublicAPI] public static class DependencyInjectionExtensions { + /// + /// Adds the Elsa client to the service collection. + /// + /// The service collection. + /// The base address of the Elsa API. + /// The API key to use for authentication. + /// An optional delegate that can be used to configure the client options. + /// An optional delegate that can be used to configure the client builder options. + public static IServiceCollection AddElsaClient(this IServiceCollection services, Uri baseAddress, string apiKey, Action? configureOptions = default, Action? configureBuilderOptions = default) + { + services.AddScoped(); + return services.AddElsaClient( + options => + { + options.BaseAddress = baseAddress; + options.ApiKey = apiKey; + configureOptions?.Invoke(options); + }, + configureBuilderOptions: options => + { + options.ConfigureHttpClientBuilder = builder => builder.AddHttpMessageHandler(); + configureBuilderOptions?.Invoke(options); + }); + } + /// /// Adds the Elsa client to the service collection. /// diff --git a/src/clients/Elsa.Api.Client/HttpMessageHandlers/ApiKeyHttpMessageHandler.cs b/src/clients/Elsa.Api.Client/HttpMessageHandlers/ApiKeyHttpMessageHandler.cs new file mode 100644 index 0000000000..8fd0d88393 --- /dev/null +++ b/src/clients/Elsa.Api.Client/HttpMessageHandlers/ApiKeyHttpMessageHandler.cs @@ -0,0 +1,30 @@ +using System.Net.Http.Headers; +using Elsa.Api.Client.Options; +using Microsoft.Extensions.Options; + +namespace Elsa.Api.Client.HttpMessageHandlers; + +/// +/// An that configures the outgoing HTTP request to use an API key as the authorization header. +/// +public class ApiKeyHttpMessageHandler : DelegatingHandler +{ + private readonly ElsaClientOptions _options; + + /// + /// Initializes a new instance of the class. + /// + public ApiKeyHttpMessageHandler(IOptions options) + { + _options = options.Value; + } + + /// + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var apiKey = _options.ApiKey; + request.Headers.Authorization = new AuthenticationHeaderValue("ApiKey", apiKey); + + return await base.SendAsync(request, cancellationToken); + } +} \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Options/ElsaClientOptions.cs b/src/clients/Elsa.Api.Client/Options/ElsaClientOptions.cs index 6ed5187204..21e9af5e86 100644 --- a/src/clients/Elsa.Api.Client/Options/ElsaClientOptions.cs +++ b/src/clients/Elsa.Api.Client/Options/ElsaClientOptions.cs @@ -9,11 +9,11 @@ public class ElsaClientOptions /// Gets or sets the base address of the Elsa server. /// public Uri BaseAddress { get; set; } = default!; - + /// - /// Gets or sets the API key to use when authenticating with the Elsa server. + /// Gets or sets the API key function to use when authenticating with the Elsa server. /// - public string ApiKey { get; set; } = default!; + public string? ApiKey { get; set; } /// /// Gets or sets a delegate that can be used to configure the HTTP client.