Skip to content

Commit

Permalink
add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
pwelter34 committed Mar 22, 2024
1 parent 4dd9132 commit b92364f
Show file tree
Hide file tree
Showing 17 changed files with 227 additions and 25 deletions.
18 changes: 16 additions & 2 deletions src/AspNetCore.SecurityKey/ApplicationBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,24 @@

namespace AspNetCore.SecurityKey;

/// <summary>
/// Extension methods for the <see cref="SecurityKeyMiddleware"/>.
/// </summary>
public static class ApplicationBuilderExtensions
{
public static IApplicationBuilder UseSecurityKey(this IApplicationBuilder app)
/// <summary>
/// Adds middleware for requiring security API key for all requests.
/// </summary>
/// <param name="builder">The <see cref="IApplicationBuilder" /> instance this method extends</param>
/// <returns>
/// The <see cref="IApplicationBuilder" /> for requirirng security API keys
/// </returns>
/// <exception cref="System.ArgumentNullException">builder is null</exception>
public static IApplicationBuilder UseSecurityKey(this IApplicationBuilder builder)
{
return app.UseMiddleware<SecurityKeyMiddleware>();
if (builder is null)
throw new ArgumentNullException(nameof(builder));

return builder.UseMiddleware<SecurityKeyMiddleware>();
}
}
56 changes: 52 additions & 4 deletions src/AspNetCore.SecurityKey/AuthenticationBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,62 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;

namespace AspNetCore.SecurityKey;

/// <summary>
/// Extension methods to configure security API key authentication.
/// </summary>
public static class AuthenticationBuilderExtensions
{
/// <summary>
/// Adds security API key authentication to <see cref="AuthenticationBuilder"/> using the default scheme.
/// The default scheme is specified by <see cref="SecurityKeyAuthenticationDefaults.AuthenticationScheme"/>.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/>.</param>
/// <returns>A reference to <paramref name="builder"/> after the operation has completed.</returns>
public static AuthenticationBuilder AddSecurityKey(this AuthenticationBuilder builder)
=> builder.AddSecurityKey(SecurityKeyAuthenticationDefaults.AuthenticationScheme);

/// <summary>
/// Adds security API key authentication to <see cref="AuthenticationBuilder"/> using the specified scheme.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/>.</param>
/// <param name="authenticationScheme">The authentication scheme.</param>
/// <returns>A reference to <paramref name="builder"/> after the operation has completed.</returns>
public static AuthenticationBuilder AddSecurityKey(this AuthenticationBuilder builder, string authenticationScheme)
=> builder.AddSecurityKey(authenticationScheme, configureOptions: null!);

/// <summary>
/// Adds security API key authentication to <see cref="AuthenticationBuilder"/> using the default scheme.
/// The default scheme is specified by <see cref="SecurityKeyAuthenticationDefaults.AuthenticationScheme"/>.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/>.</param>
/// <param name="configureOptions">A delegate to configure <see cref="SecurityKeyAuthenticationSchemeOptions"/>.</param>
/// <returns>A reference to <paramref name="builder"/> after the operation has completed.</returns>
public static AuthenticationBuilder AddSecurityKey(this AuthenticationBuilder builder, Action<SecurityKeyAuthenticationSchemeOptions> configureOptions)
=> builder.AddSecurityKey(SecurityKeyAuthenticationDefaults.AuthenticationScheme, configureOptions);

/// <summary>
/// Adds security api key authentication to <see cref="AuthenticationBuilder"/> using the specified scheme.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/>.</param>
/// <param name="authenticationScheme">The authentication scheme.</param>
/// <param name="configureOptions">A delegate to configure <see cref="SecurityKeyAuthenticationSchemeOptions"/>.</param>
/// <returns>A reference to <paramref name="builder"/> after the operation has completed.</returns>
public static AuthenticationBuilder AddSecurityKey(this AuthenticationBuilder builder, string authenticationScheme, Action<SecurityKeyAuthenticationSchemeOptions> configureOptions)
=> builder.AddSecurityKey(authenticationScheme, displayName: null, configureOptions: configureOptions);

/// <summary>
/// Adds security api key authentication to <see cref="AuthenticationBuilder"/> using the specified scheme.
/// </summary>
/// <param name="builder">The <see cref="AuthenticationBuilder"/>.</param>
/// <param name="authenticationScheme">The authentication scheme.</param>
/// <param name="displayName">A display name for the authentication handler.</param>
/// <param name="configureOptions">A delegate to configure <see cref="SecurityKeyAuthenticationSchemeOptions"/>.</param>
/// <returns>A reference to <paramref name="builder"/> after the operation has completed.</returns>
public static AuthenticationBuilder AddSecurityKey(this AuthenticationBuilder builder, string authenticationScheme, string? displayName, Action<SecurityKeyAuthenticationSchemeOptions> configureOptions)
{
return builder.AddScheme<SecurityKeyAuthenticationSchemeOptions, SecurityKeyAuthenticationHandler>(
SecurityKeyAuthenticationDefaults.AuthenticationScheme,
options => { }
);
builder.Services.AddOptions<SecurityKeyAuthenticationSchemeOptions>(authenticationScheme);
return builder.AddScheme<SecurityKeyAuthenticationSchemeOptions, SecurityKeyAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
}
}
11 changes: 11 additions & 0 deletions src/AspNetCore.SecurityKey/DependencyInjectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@

namespace AspNetCore.SecurityKey;

/// <summary>
/// Extension methods for setting up security API key services
/// </summary>
public static class DependencyInjectionExtensions
{
/// <summary>
/// Adds the security API key services to the specified <see cref="IServiceCollection"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add services.</param>
/// <param name="configure">An action delegate to configure the provided <see cref="SecurityKeyOptions"/>.</param>
/// <returns>
/// The <see cref="IServiceCollection"/> so that additional calls can be chained.
/// </returns>
public static IServiceCollection AddSecurityKey(this IServiceCollection services, Action<SecurityKeyOptions>? configure = null)
{
services.AddHttpContextAccessor();
Expand Down
14 changes: 12 additions & 2 deletions src/AspNetCore.SecurityKey/EndpointFilterExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
#if NET7_0_OR_GREATER
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

namespace AspNetCore.SecurityKey;

/// <summary>
/// Extension methods for adding <see cref="IEndpointFilter" /> to a route handler.
/// </summary>
public static class EndpointFilterExtensions
{
#if NET7_0_OR_GREATER
/// <summary>
/// Registers an endpoint filter requiring security API key for the specified route handler.
/// </summary>
/// <param name="builder">The <see cref="RouteHandlerBuilder"/>.</param>
/// <returns>
/// A <see cref="RouteHandlerBuilder"/> that can be used to further customize the route handler.
/// </returns>
public static RouteHandlerBuilder RequireSecurityKey(this RouteHandlerBuilder builder)
{
builder.AddEndpointFilter<SecurityKeyEndpointFilter>();
return builder;
}
#endif
}
#endif
8 changes: 8 additions & 0 deletions src/AspNetCore.SecurityKey/ISecurityKeyExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

namespace AspNetCore.SecurityKey;

/// <summary>
/// An interface for extracting the security API key
/// </summary>
public interface ISecurityKeyExtractor
{
/// <summary>
/// Gets the security API key from the specified <see cref="HttpContent"/>.
/// </summary>
/// <param name="context">The <see cref="HttpContent"/> to get security key from.</param>
/// <returns>The security API key if found; otherwise null</returns>
string? GetKey(HttpContext? context);
}
8 changes: 8 additions & 0 deletions src/AspNetCore.SecurityKey/ISecurityKeyValidator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
namespace AspNetCore.SecurityKey;

/// <summary>
/// An interface for validating the security API key
/// </summary>
public interface ISecurityKeyValidator
{
/// <summary>
/// Validates the specified security API key.
/// </summary>
/// <param name="value">The security API key to validate.</param>
/// <returns>true if security API key is valid; otherwise false</returns>
bool Validate(string? value);
}
10 changes: 8 additions & 2 deletions src/AspNetCore.SecurityKey/SecurityKeyAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@

namespace AspNetCore.SecurityKey;

/// <summary>
/// Specifies that the class or method that this attribute is applied to requires security API key authorization.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class SecurityKeyAttribute : ServiceFilterAttribute
{
public SecurityKeyAttribute()
: base(typeof(SecurityKeyAuthorizationFilter))
/// <summary>
/// Initializes a new instance of the <see cref="SecurityKeyAttribute"/> class.
/// </summary>
public SecurityKeyAttribute() : base(typeof(SecurityKeyAuthorizationFilter))
{
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
namespace AspNetCore.SecurityKey;
namespace AspNetCore.SecurityKey;

/// <summary>
/// Default values related to security API key authentication
/// </summary>
public static class SecurityKeyAuthenticationDefaults
{
/// <summary>
/// The default authentication scheme
/// </summary>
public const string AuthenticationScheme = "SecurityKey";
}
13 changes: 13 additions & 0 deletions src/AspNetCore.SecurityKey/SecurityKeyAuthenticationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,24 @@

namespace AspNetCore.SecurityKey;

/// <summary>
/// Implementation for the cookie-based authentication handler.
/// </summary>
public class SecurityKeyAuthenticationHandler : AuthenticationHandler<SecurityKeyAuthenticationSchemeOptions>
{
private readonly ISecurityKeyExtractor _securityKeyExtractor;
private readonly ISecurityKeyValidator _securityKeyValidator;

#pragma warning disable CS0618 // allow ISystemClock for compatibility
/// <summary>
/// Initializes a new instance of the <see cref="SecurityKeyAuthenticationHandler"/> class.
/// </summary>
/// <param name="options">Accessor to <see cref="SecurityKeyAuthenticationSchemeOptions"/>.</param>
/// <param name="logger">The <see cref="ILoggerFactory"/>.</param>
/// <param name="encoder">The <see cref="UrlEncoder"/>.</param>
/// <param name="clock">The <see cref="ISystemClock"/>.</param>
/// <param name="securityKeyExtractor">The security key extractor.</param>
/// <param name="securityKeyValidator">The security key validator.</param>
public SecurityKeyAuthenticationHandler(
IOptionsMonitor<SecurityKeyAuthenticationSchemeOptions> options,
ILoggerFactory logger,
Expand All @@ -29,6 +41,7 @@ public SecurityKeyAuthenticationHandler(
}
#pragma warning restore CS0618

/// <inheritdoc />
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var securityKey = _securityKeyExtractor.GetKey(Context);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication;

namespace AspNetCore.SecurityKey;

/// <summary>
/// Configuration options for SecurityKeyAuthenticationSchemeOptions.
/// </summary>
/// <seealso cref="Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" />
public class SecurityKeyAuthenticationSchemeOptions : AuthenticationSchemeOptions
{

Expand Down
27 changes: 19 additions & 8 deletions src/AspNetCore.SecurityKey/SecurityKeyAuthorizationFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,41 @@

namespace AspNetCore.SecurityKey;

/// <summary>
/// A filter that requiring security API key authorization.
/// </summary>
/// <seealso cref="Microsoft.AspNetCore.Mvc.Filters.IAuthorizationFilter" />
public class SecurityKeyAuthorizationFilter : IAuthorizationFilter
{
private readonly ISecurityKeyExtractor _authenticationKeyExtractor;
private readonly ISecurityKeyValidator _authenticationKeyValidator;
private readonly ISecurityKeyExtractor _securityKeyExtractor;
private readonly ISecurityKeyValidator _securityKeyValidator;
private readonly ILogger<SecurityKeyAuthorizationFilter> _logger;

/// <summary>
/// Initializes a new instance of the <see cref="SecurityKeyAuthorizationFilter"/> class.
/// </summary>
/// <param name="securityKeyExtractor">The authentication key extractor.</param>
/// <param name="securityKeyValidator">The authentication key validator.</param>
/// <param name="logger">The logger.</param>
public SecurityKeyAuthorizationFilter(
ISecurityKeyExtractor authenticationKeyExtractor,
ISecurityKeyValidator authenticationKeyValidator,
ISecurityKeyExtractor securityKeyExtractor,
ISecurityKeyValidator securityKeyValidator,
ILogger<SecurityKeyAuthorizationFilter> logger)
{
_authenticationKeyExtractor = authenticationKeyExtractor ?? throw new ArgumentNullException(nameof(authenticationKeyExtractor));
_authenticationKeyValidator = authenticationKeyValidator ?? throw new ArgumentNullException(nameof(authenticationKeyValidator));
_securityKeyExtractor = securityKeyExtractor ?? throw new ArgumentNullException(nameof(securityKeyExtractor));
_securityKeyValidator = securityKeyValidator ?? throw new ArgumentNullException(nameof(securityKeyValidator));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

/// <inheritdoc />
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context is null)
throw new ArgumentNullException(nameof(context));

var securityKey = _authenticationKeyExtractor.GetKey(context.HttpContext);
var securityKey = _securityKeyExtractor.GetKey(context.HttpContext);

if (_authenticationKeyValidator.Validate(securityKey))
if (_securityKeyValidator.Validate(securityKey))
return;

SecurityKeyLogger.InvalidSecurityKey(_logger, securityKey);
Expand Down
10 changes: 10 additions & 0 deletions src/AspNetCore.SecurityKey/SecurityKeyEndpointFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@
namespace AspNetCore.SecurityKey;

#if NET7_0_OR_GREATER
/// <summary>
/// A filter that requiring security API key authorization.
/// </summary>
public class SecurityKeyEndpointFilter : IEndpointFilter
{
private readonly ISecurityKeyExtractor _securityKeyExtractor;
private readonly ISecurityKeyValidator _securityKeyValidator;
private readonly ILogger<SecurityKeyAuthorizationFilter> _logger;

/// <summary>
/// Initializes a new instance of the <see cref="SecurityKeyEndpointFilter"/> class.
/// </summary>
/// <param name="securityKeyExtractor">The authentication key extractor.</param>
/// <param name="securityKeyValidator">The authentication key validator.</param>
/// <param name="logger">The logger.</param>
public SecurityKeyEndpointFilter(
ISecurityKeyExtractor securityKeyExtractor,
ISecurityKeyValidator securityKeyValidator,
Expand All @@ -22,6 +31,7 @@ public SecurityKeyEndpointFilter(
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

/// <inheritdoc />
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
{
if (context is null)
Expand Down
10 changes: 10 additions & 0 deletions src/AspNetCore.SecurityKey/SecurityKeyExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@

namespace AspNetCore.SecurityKey;

/// <summary>
/// Default implementation for extracting the security API key
/// </summary>
/// <seealso cref="AspNetCore.SecurityKey.ISecurityKeyExtractor" />
public class SecurityKeyExtractor : ISecurityKeyExtractor
{
private readonly SecurityKeyOptions _securityKeyOptions;

/// <summary>
/// Initializes a new instance of the <see cref="SecurityKeyExtractor"/> class.
/// </summary>
/// <param name="securityKeyOptions">The security key options.</param>
/// <exception cref="System.ArgumentNullException">securityKeyOptions</exception>
public SecurityKeyExtractor(IOptions<SecurityKeyOptions> securityKeyOptions)
{
if (securityKeyOptions == null)
Expand All @@ -15,6 +24,7 @@ public SecurityKeyExtractor(IOptions<SecurityKeyOptions> securityKeyOptions)
_securityKeyOptions = securityKeyOptions.Value;
}

/// <inheritdoc />
public string? GetKey(HttpContext? context)
{
if (context is null)
Expand Down
6 changes: 3 additions & 3 deletions src/AspNetCore.SecurityKey/SecurityKeyLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

namespace AspNetCore.Extensions.Authentication;

public partial class SecurityKeyLogger
internal partial class SecurityKeyLogger
{
[LoggerMessage(1001, LogLevel.Error, "Invalid Security Key '{SecurityKey}'")]
public static partial void InvalidSecurityKey(ILogger logger, string? securityKey);
internal static partial void InvalidSecurityKey(ILogger logger, string? securityKey);

[LoggerMessage(1002, LogLevel.Debug, "Using Security Keys '{SecurityKey}' from configuration '{ConfigurationName}'")]
public static partial void SecurityKeyUsage(ILogger logger, string? securityKey, string? configurationName);
internal static partial void SecurityKeyUsage(ILogger logger, string? securityKey, string? configurationName);

}
2 changes: 1 addition & 1 deletion src/AspNetCore.SecurityKey/SecurityKeyMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace AspNetCore.SecurityKey;

public class SecurityKeyMiddleware
internal sealed class SecurityKeyMiddleware
{
private readonly RequestDelegate _next;

Expand Down
Loading

0 comments on commit b92364f

Please sign in to comment.