Add ApiKeys authentication

This commit is contained in:
Zoe Roux 2023-03-20 11:55:11 +09:00
parent bf281820b9
commit 86955cf0cb
2 changed files with 34 additions and 6 deletions

View File

@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Permissions;
@ -30,6 +31,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
namespace Kyoo.Authentication
{
@ -169,22 +171,48 @@ namespace Kyoo.Authentication
string permStr = $"{permission.ToLower()}.{kind.ToString()!.ToLower()}";
string overallStr = $"{_group.ToString().ToLower()}.{kind.ToString()!.ToLower()}";
AuthenticateResult res = await context.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
AuthenticateResult res = _ApiKeyCheck(context);
if (res.None)
res = await context.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
if (res.Succeeded)
{
ICollection<string> permissions = res.Principal.GetPermissions();
if (permissions.All(x => x != permStr && x != overallStr))
context.Result = _ErrorResult($"Missing permission {permStr} or {overallStr}", StatusCodes.Status403Forbidden);
}
else
else if (res.None)
{
ICollection<string> permissions = _options.CurrentValue.Default ?? Array.Empty<string>();
if (res.Failure != null || permissions.All(x => x != permStr && x != overallStr))
if (permissions.All(x => x != permStr && x != overallStr))
{
context.Result = _ErrorResult("Token non present or invalid (it may have expired). " +
$"Unlogged user does not have permission {permStr} or {overallStr}", StatusCodes.Status401Unauthorized);
context.Result = _ErrorResult($"Unlogged user does not have permission {permStr} or {overallStr}", StatusCodes.Status401Unauthorized);
}
}
else if (res.Failure != null)
context.Result = _ErrorResult(res.Failure.Message, StatusCodes.Status403Forbidden);
}
private AuthenticateResult _ApiKeyCheck(ActionContext context)
{
if (!context.HttpContext.Request.Headers.TryGetValue("X-API-Key", out StringValues apiKey))
return AuthenticateResult.NoResult();
if (!_options.CurrentValue.ApiKeys.Contains<string>(apiKey))
return AuthenticateResult.Fail("Invalid API-Key.");
return AuthenticateResult.Success(
new AuthenticationTicket(
new ClaimsPrincipal(
new[]
{
new ClaimsIdentity(new[]
{
// TODO: Make permission configurable, for now every APIKEY as all permissions.
new Claim(Claims.Permissions, string.Join(',', PermissionOption.Admin))
})
}
),
"apikey"
)
);
}
}

View File

@ -96,7 +96,7 @@ namespace Kyoo.Authentication.Views
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(RequestError))]
public async Task<ActionResult<JwtToken>> Login([FromBody] LoginRequest request)
{
User user = await _users.GetOrDefault(x => x.Username == request.Username);
User? user = await _users.GetOrDefault(x => x.Username == request.Username);
if (user == null || !BCryptNet.Verify(request.Password, user.Password))
return Forbid(new RequestError("The user and password does not match."));