-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into @mramos/V8.1.3
- Loading branch information
Showing
24 changed files
with
343 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace Encamina.Enmarcha.AspNet.OpenApi; | ||
|
||
/// <summary> | ||
/// Constants used in the OpenAPI library. | ||
/// </summary> | ||
public static class Constants | ||
{ | ||
/// <summary> | ||
/// OpenAPI related constants. | ||
/// </summary> | ||
public static class OpenApi | ||
{ | ||
/// <summary> | ||
/// The OpenAPI key header. | ||
/// </summary> | ||
public static readonly string KeyHeader = @"x-openapi-key"; | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/Encamina.Enmarcha.AspNet.OpenApi/Encamina.Enmarcha.AspNet.OpenApi.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<OutputType>Library</OutputType> | ||
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile> | ||
<IsPackable>true</IsPackable> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup> | ||
<PackageReadmeFile>README.md</PackageReadmeFile> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<None Include="README.md" Pack="true" PackagePath="\" /> | ||
</ItemGroup> | ||
|
||
</Project> |
52 changes: 52 additions & 0 deletions
52
src/Encamina.Enmarcha.AspNet.OpenApi/Extensions/IApplicationBuilderExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
using Encamina.Enmarcha.AspNet.OpenApi.Middlewares; | ||
|
||
using Microsoft.Extensions.Options; | ||
|
||
namespace Encamina.Enmarcha.AspNet.OpenApi.Extensions; | ||
|
||
/// <summary> | ||
/// Extension methods for <see cref="IApplicationBuilder"/>. | ||
/// </summary> | ||
public static class IApplicationBuilderExtensions | ||
{ | ||
/// <summary> | ||
/// Use the OpenAPI group name key authorization middleware with a given configuration. | ||
/// </summary> | ||
/// <param name="app">A valid instance of <see cref="IApplicationBuilder"/> as the application's request pipeline builder.</param> | ||
/// <param name="setupAction">An optional setup action for the <see cref="GroupNameKeyAuthenticationOptions"/>.</param> | ||
/// <returns>The <see cref="IApplicationBuilder"/> so that additional calls can be chained.</returns> | ||
public static IApplicationBuilder UseOpenApiGroupNameKeyAuthorization(this IApplicationBuilder app, Action<GroupNameKeyAuthenticationOptions> setupAction) | ||
{ | ||
GroupNameKeyAuthenticationOptions options; | ||
|
||
using (var scope = app.ApplicationServices.CreateScope()) | ||
{ | ||
options = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<GroupNameKeyAuthenticationOptions>>().Value; | ||
|
||
setupAction?.Invoke(options); | ||
} | ||
|
||
return app.UseOpenApiGroupNameKeyAuthorization(options); | ||
} | ||
|
||
/// <summary> | ||
/// Use the OpenAPI group name key authorization middleware with options. | ||
/// </summary> | ||
/// <param name="app">A valid instance of <see cref="IApplicationBuilder"/> as the application's request pipeline builder.</param> | ||
/// <param name="options">Option parameters for the group name key authorization middleware.</param> | ||
/// <returns>The <see cref="IApplicationBuilder"/> so that additional calls can be chained.</returns> | ||
public static IApplicationBuilder UseOpenApiGroupNameKeyAuthorization(this IApplicationBuilder app, GroupNameKeyAuthenticationOptions options) | ||
{ | ||
return app.UseMiddleware<GroupNameKeyAuthorizationMiddleware>(Options.Create(options)); | ||
} | ||
|
||
/// <summary> | ||
/// Use the OpenAPI group name key authorization middleware. | ||
/// </summary> | ||
/// <param name="app">A valid instance of <see cref="IApplicationBuilder"/> as the application's request pipeline builder.</param> | ||
/// <returns>The <see cref="IApplicationBuilder"/> so that additional calls can be chained.</returns> | ||
public static IApplicationBuilder UseOpenApiGroupNameKeyAuthorization(this IApplicationBuilder app) | ||
{ | ||
return app.UseMiddleware<GroupNameKeyAuthorizationMiddleware>(); | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/Encamina.Enmarcha.AspNet.OpenApi/Middlewares/GroupNameKeyAuthenticationOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
namespace Encamina.Enmarcha.AspNet.OpenApi.Middlewares; | ||
|
||
/// <summary> | ||
/// Option parameters for the group name key authorization middleware. | ||
/// </summary> | ||
public sealed class GroupNameKeyAuthenticationOptions | ||
{ | ||
/// <summary> | ||
/// Gets or sets a dictionary of keys indexed by group name. | ||
/// </summary> | ||
public IDictionary<string, string> GroupNameKeys { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the specification file name. By default, it is set to <c>swagger.json</c> because it is the most common OpenAPI implementation. | ||
/// </summary> | ||
public string SpecificationFileName { get; set; } = @"swagger.json"; | ||
|
||
/// <summary> | ||
/// Gets or sets the specification path. By default, it is set to <c>/swagger</c> because it is the most common OpenAPI implementation. | ||
/// </summary> | ||
/// <remarks>It is very important that the value of this property starts with '<c>/</c>'.</remarks> | ||
public string SpecificationPath { get; set; } = @"/swagger"; | ||
|
||
/// <summary> | ||
/// Gets or sets a value indicating whether the middleware is enabled. By default, it is set to <c>true</c>. | ||
/// </summary> | ||
/// <remarks>This property would allow turning on/off the middleware for development or testing purposes.</remarks> | ||
public bool IsEnabled { get; set; } = true; | ||
} |
64 changes: 64 additions & 0 deletions
64
src/Encamina.Enmarcha.AspNet.OpenApi/Middlewares/GroupNameKeyAuthorizationMiddleware.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
using System.Net; | ||
|
||
using Microsoft.Extensions.Options; | ||
|
||
namespace Encamina.Enmarcha.AspNet.OpenApi.Middlewares; | ||
|
||
/// <summary> | ||
/// A middleware that authorizes requests for specific OpenAPI specifications based on a key associated with a group name of an API. | ||
/// </summary> | ||
public class GroupNameKeyAuthorizationMiddleware | ||
{ | ||
private readonly RequestDelegate next; | ||
private readonly GroupNameKeyAuthenticationOptions options; | ||
private readonly ILogger logger; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="GroupNameKeyAuthorizationMiddleware"/> class. | ||
/// </summary> | ||
/// <param name="next">The delegate representing the remaining middleware in the request pipeline.</param> | ||
/// <param name="options">Option parameters for the group name key authorization middleware.</param> | ||
/// <param name="loggerFactory">A factory for <see cref="ILogger"/> instances.</param> | ||
public GroupNameKeyAuthorizationMiddleware(RequestDelegate next, IOptions<GroupNameKeyAuthenticationOptions> options, ILoggerFactory loggerFactory) | ||
{ | ||
this.next = next; | ||
this.options = options.Value; | ||
|
||
logger = loggerFactory.CreateLogger<GroupNameKeyAuthorizationMiddleware>(); | ||
} | ||
|
||
/// <summary> | ||
/// Executes the middleware. | ||
/// </summary> | ||
/// <param name="context">The <see cref="HttpContext"/> for the current request.</param> | ||
/// <returns>A task that represents the execution of this middleware.</returns> | ||
public async Task InvokeAsync(HttpContext context) | ||
{ | ||
if (!options.IsEnabled) | ||
{ | ||
logger.LogInformation(@"Swagger group name key authorization middleware is disabled!"); | ||
await next.Invoke(context).ConfigureAwait(false); | ||
return; | ||
} | ||
|
||
var requestPathValue = context.Request.Path.Value; | ||
|
||
if (requestPathValue == null || !requestPathValue.EndsWith(options.SpecificationFileName, StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
await next.Invoke(context).ConfigureAwait(false); | ||
return; | ||
} | ||
|
||
var groupNameKey = options.GroupNameKeys.FirstOrDefault(item => requestPathValue.StartsWith($@"{options.SpecificationPath}/{item.Key}", StringComparison.OrdinalIgnoreCase)).Value; | ||
|
||
if (groupNameKey == null || (context.Request.Headers.TryGetValue(Constants.OpenApi.KeyHeader, out var apiKey) && apiKey.Equals(groupNameKey))) | ||
{ | ||
await next.Invoke(context).ConfigureAwait(false); | ||
return; | ||
} | ||
|
||
logger.LogInformation(@"Invalid or missing key for path {RequestPath}!", requestPathValue); | ||
|
||
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# OpenApi | ||
|
||
[![Nuget package](https://img.shields.io/nuget/v/Encamina.Enmarcha.AspNet.OpenApi)](https://www.nuget.org/packages/Encamina.Enmarcha.AspNet.OpenApi) | ||
|
||
This package provides extensions and types to work with OpenAPI (a.k.a. Swagger). | ||
|
||
## Setup | ||
|
||
### Nuget package | ||
|
||
First, [install NuGet](http://docs.nuget.org/docs/start-here/installing-nuget). Then, install [Encamina.Enmarcha.AspNet.OpenApi](https://www.nuget.org/packages/Encamina.Enmarcha.AspNet.OpenApi) from the package manager console: | ||
|
||
PM> Install-Package Encamina.Enmarcha.AspNet.OpenApi | ||
|
||
### .NET CLI: | ||
|
||
First, [install .NET CLI](https://learn.microsoft.com/en-us/dotnet/core/tools/). Then, install [Encamina.Enmarcha.AspNet.OpenApi](https://www.nuget.org/packages/Encamina.Enmarcha.AspNet.OpenApi) from the .NET CLI: | ||
|
||
dotnet add package Encamina.Enmarcha.AspNet.OpenApi | ||
|
||
## How to use | ||
|
||
### Middlewares | ||
|
||
#### GroupNameKeyAuthorizationMiddleware | ||
|
||
This middleware is used to block access to an OpenAPI document or specification by using a pre-shared key that must be provided in the request header per specification. | ||
|
||
To configure, use the `GroupNameKeyAuthenticationOptions` class. | ||
|
||
When requesting an OpenAPI specification, identified by its group name, the client must provide the pre-shared key in the request header. Otherwise, the request will fail with an `HTTP 401 UNAUTHORIZED` response. | ||
|
||
### Extensions | ||
|
||
#### IApplicationBuilderExtensions | ||
|
||
The `IApplicationBuilderExtensions` is a static class that provides extension methods for `IApplicationBuilder`, usually to add and configure middlewares. | ||
|
||
Using it is quite simple, just get an instance of an `IApplicationBuilder` and call any of the available extension methods. | ||
|
||
```csharp | ||
|
||
var builder = WebApplication.CreateBuilder(new WebApplicationOptions() | ||
{ | ||
ContentRootPath = Directory.GetCurrentDirectory(), | ||
}); | ||
|
||
// ... | ||
var app = builder.Build(); | ||
|
||
app.UseSwaggerGroupNameKeyAuthorization(options => | ||
{ | ||
// Enable only if not in Development environment. Allow developers to test without keys... | ||
options.IsEnabled = !builder.Environment.IsDevelopment(); | ||
}); | ||
|
||
// ... | ||
``` | ||
|
||
Currently, available extension methods are: | ||
|
||
- `UseSwaggerGroupNameKeyAuthorization(this IApplicationBuilder app, SwaggerGroupNameKeyAuthenticationOptions options)`: adds the `GroupNameKeyAuthorizationMiddleware` middleware using provided options. | ||
- `UseSwaggerGroupNameKeyAuthorization(this IApplicationBuilder app, Action<SwaggerGroupNameKeyAuthenticationOptions>? setupAction = null)`: adds the `GroupNameKeyAuthorizationMiddleware` middleware configuring options inline. | ||
|
||
**Important**: Make sure that `UseSwaggerGroupNameKeyAuthorization` is added before any `UseSwagger()`, `UseSwaggerUI()`, or any other OpenAPI implementation middleware call, so that authorization middleware is called before accessing the OpenAPI document. |
Oops, something went wrong.