WIP add API Key authentication
This commit is contained in:
parent
005eea35e2
commit
3f1ab3eb12
5 changed files with 104 additions and 2 deletions
65
src/Robware.Api.Auth/ApiKey/ApiKeyAuthenticationHandler.cs
Normal file
65
src/Robware.Api.Auth/ApiKey/ApiKeyAuthenticationHandler.cs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Robware.Auth.API;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Robware.Api.Auth.ApiKey {
|
||||||
|
public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions> {
|
||||||
|
private const string ApiKeyHeaderName = "X-Api-Key";
|
||||||
|
private readonly IApiKeyValidator _apiKeyValidator;
|
||||||
|
private readonly IApiKeys _apiKeys;
|
||||||
|
|
||||||
|
public ApiKeyAuthenticationHandler(
|
||||||
|
IOptionsMonitor<ApiKeyAuthenticationOptions> options,
|
||||||
|
ILoggerFactory logger,
|
||||||
|
UrlEncoder encoder,
|
||||||
|
ISystemClock clock,
|
||||||
|
IApiKeyValidator apiKeyValidator,
|
||||||
|
IApiKeys apiKeys) : base(options, logger, encoder, clock) {
|
||||||
|
_apiKeyValidator = apiKeyValidator;
|
||||||
|
_apiKeys = apiKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() {
|
||||||
|
if (!Request.Headers.TryGetValue(ApiKeyHeaderName, out var apiKeyHeaderValues)) {
|
||||||
|
return AuthenticateResult.NoResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
var providedApiKey = apiKeyHeaderValues.FirstOrDefault();
|
||||||
|
|
||||||
|
if (apiKeyHeaderValues.Count == 0 || string.IsNullOrWhiteSpace(providedApiKey)) {
|
||||||
|
return AuthenticateResult.NoResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await _apiKeyValidator.Validate(providedApiKey)) {
|
||||||
|
var key = await _apiKeys.Get(providedApiKey);
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.Name, key.Name)
|
||||||
|
};
|
||||||
|
|
||||||
|
var identity = new ClaimsIdentity(claims, Options.AuthenticationType);
|
||||||
|
var principal = new ClaimsPrincipal(new[] { identity });
|
||||||
|
var ticket = new AuthenticationTicket(principal, Options.Scheme);
|
||||||
|
|
||||||
|
return AuthenticateResult.Success(ticket);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AuthenticateResult.Fail("Invalid API Key provided.");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task HandleChallengeAsync(AuthenticationProperties properties) {
|
||||||
|
Response.StatusCode = 401;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties) {
|
||||||
|
Response.StatusCode = 403;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
|
||||||
|
namespace Robware.Api.Auth.ApiKey {
|
||||||
|
public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions {
|
||||||
|
public const string DefaultScheme = "API Key";
|
||||||
|
public string Scheme => DefaultScheme;
|
||||||
|
public string AuthenticationType = DefaultScheme;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Robware.Api.Auth.ApiKey {
|
||||||
|
public static class AuthenticationBuilderExtensions {
|
||||||
|
public static AuthenticationBuilder AddApiKeySupport(this AuthenticationBuilder authenticationBuilder, Action<ApiKeyAuthenticationOptions> options) {
|
||||||
|
return authenticationBuilder.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>(ApiKeyAuthenticationOptions.DefaultScheme, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
|
using Robware.Api.Auth.ApiKey;
|
||||||
using Robware.Auth.API;
|
using Robware.Auth.API;
|
||||||
using Robware.Auth.Users;
|
using Robware.Auth.Users;
|
||||||
using Robware.Data;
|
using Robware.Data;
|
||||||
|
@ -26,6 +27,12 @@ namespace Robware.Api.Auth {
|
||||||
.AddSingleton<IUsers, UserRepository>()
|
.AddSingleton<IUsers, UserRepository>()
|
||||||
.AddSingleton<IApiKeyValidator, ApiKeyValidator>()
|
.AddSingleton<IApiKeyValidator, ApiKeyValidator>()
|
||||||
.AddSingleton<IApiKeys, ApiKeyRepository>();
|
.AddSingleton<IApiKeys, ApiKeyRepository>();
|
||||||
|
|
||||||
|
services.AddAuthentication(options => {
|
||||||
|
options.DefaultAuthenticateScheme = ApiKeyAuthenticationOptions.DefaultScheme;
|
||||||
|
options.DefaultChallengeScheme = ApiKeyAuthenticationOptions.DefaultScheme;
|
||||||
|
})
|
||||||
|
.AddApiKeySupport(options=>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMongoDatabase SetupMongoDatabase() {
|
private IMongoDatabase SetupMongoDatabase() {
|
||||||
|
@ -43,6 +50,8 @@ namespace Robware.Api.Auth {
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints => {
|
app.UseEndpoints(endpoints => {
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
using Robware.Auth.API;
|
using Robware.Auth.API;
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Robware.Data {
|
namespace Robware.Data {
|
||||||
public class ApiKeyRepository : IApiKeys {
|
public class ApiKeyRepository : IApiKeys {
|
||||||
public Task<ApiKey> Get(string key) {
|
public async Task<ApiKey> Get(string key) {
|
||||||
throw new System.NotImplementedException();
|
if (key=="denied")
|
||||||
|
throw new ApiKeyNotFoundException(key);
|
||||||
|
|
||||||
|
return new ApiKey {
|
||||||
|
Name = "Hardcoded key",
|
||||||
|
Key = key,
|
||||||
|
Enabled = true,
|
||||||
|
IssueTimestamp = DateTime.Now
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue