Switch to JWT authentication (#19)
* switch to jwt authentication * fix delete files * adjust saving of deletion of all files * update api to main/jwt Co-authored-by: rootdarkarchon <root.darkarchon@outlook.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
using MareSynchronos.API;
|
||||
using MareSynchronosShared;
|
||||
using MareSynchronosShared.Authentication;
|
||||
using MareSynchronosShared.Services;
|
||||
using MareSynchronosShared.Utils;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
|
||||
namespace MareSynchronosServer.Controllers;
|
||||
|
||||
[AllowAnonymous]
|
||||
[Route(MareAuth.Auth)]
|
||||
public class JwtController : Controller
|
||||
{
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
private readonly SecretKeyAuthenticatorService _secretKeyAuthenticatorService;
|
||||
private readonly IConfigurationService<MareConfigurationAuthBase> _configuration;
|
||||
|
||||
public JwtController(IHttpContextAccessor accessor, SecretKeyAuthenticatorService secretKeyAuthenticatorService, IConfigurationService<MareConfigurationAuthBase> configuration)
|
||||
{
|
||||
_accessor = accessor;
|
||||
_secretKeyAuthenticatorService = secretKeyAuthenticatorService;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost(MareAuth.AuthCreate)]
|
||||
public async Task<IActionResult> CreateToken(string auth)
|
||||
{
|
||||
if (string.IsNullOrEmpty(auth)) return BadRequest("No Authkey");
|
||||
|
||||
var ip = _accessor.GetIpAddress();
|
||||
|
||||
var authResult = await _secretKeyAuthenticatorService.AuthorizeAsync(ip, auth);
|
||||
|
||||
if (!authResult.Success) return Unauthorized("Invalid Authkey");
|
||||
|
||||
var token = CreateToken(new List<Claim>()
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, authResult.Uid)
|
||||
});
|
||||
|
||||
return Content(token.RawData);
|
||||
}
|
||||
|
||||
private JwtSecurityToken CreateToken(IEnumerable<Claim> authClaims)
|
||||
{
|
||||
var authSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_configuration.GetValue<string>(nameof(MareConfigurationAuthBase.Jwt))));
|
||||
|
||||
var token = new SecurityTokenDescriptor()
|
||||
{
|
||||
Subject = new ClaimsIdentity(authClaims),
|
||||
SigningCredentials = new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256Signature)
|
||||
};
|
||||
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
return handler.CreateJwtSecurityToken(token);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.RegularExpressions;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
@@ -9,6 +8,7 @@ using MareSynchronosShared.Models;
|
||||
using MareSynchronosShared.Protos;
|
||||
using MareSynchronosShared.Utils;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace MareSynchronosServer.Hubs;
|
||||
@@ -37,7 +37,7 @@ public partial class MareHub
|
||||
request.Hash.AddRange(ownFiles.Select(f => f.Hash));
|
||||
Metadata headers = new Metadata()
|
||||
{
|
||||
{ "Authorization", Context.User!.Claims.SingleOrDefault(c => string.Equals(c.Type, ClaimTypes.Authentication, StringComparison.Ordinal))?.Value }
|
||||
{ "Authorization", Context.GetHttpContext().Request.Headers["Authorization"].ToString() }
|
||||
};
|
||||
_ = await _fileServiceClient.DeleteFilesAsync(request, headers).ConfigureAwait(false);
|
||||
}
|
||||
@@ -213,7 +213,7 @@ public partial class MareHub
|
||||
|
||||
Metadata headers = new Metadata()
|
||||
{
|
||||
{ "Authorization", Context.User!.Claims.SingleOrDefault(c => string.Equals(c.Type, ClaimTypes.Authentication, StringComparison.Ordinal))?.Value }
|
||||
{ "Authorization", Context.GetHttpContext().Request.Headers["Authorization"].ToString() }
|
||||
};
|
||||
var streamingCall = _fileServiceClient.UploadFile(headers);
|
||||
using var tempFileStream = new FileStream(tempFileName, FileMode.Open, FileAccess.Read);
|
||||
|
||||
@@ -14,6 +14,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace MareSynchronosServer.Hubs;
|
||||
|
||||
[Authorize(Policy = "Authenticated")]
|
||||
public partial class MareHub : Hub<IMareHub>, IMareHub
|
||||
{
|
||||
private readonly MareMetrics _mareMetrics;
|
||||
@@ -118,6 +119,7 @@ public partial class MareHub : Hub<IMareHub>, IMareHub
|
||||
return Task.FromResult(needsReconnect);
|
||||
}
|
||||
|
||||
[Authorize(Policy = "Authenticated")]
|
||||
public override async Task OnConnectedAsync()
|
||||
{
|
||||
_logger.LogCallInfo(MareHubLogger.Args(_contextAccessor.GetIpAddress()));
|
||||
@@ -125,6 +127,7 @@ public partial class MareHub : Hub<IMareHub>, IMareHub
|
||||
await base.OnConnectedAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Authorize(Policy = "Authenticated")]
|
||||
public override async Task OnDisconnectedAsync(Exception exception)
|
||||
{
|
||||
_mareMetrics.DecGauge(MetricsAPI.GaugeConnections);
|
||||
|
||||
@@ -31,11 +31,14 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.25.1" />
|
||||
<PackageReference Include="prometheus-net.AspNetCore" Version="7.0.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.25.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using MareSynchronos.API;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MareSynchronosServer.Hubs;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@@ -20,6 +19,9 @@ using MareSynchronosShared.Services;
|
||||
using Prometheus;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Grpc.Net.ClientFactory;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Text;
|
||||
|
||||
namespace MareSynchronosServer;
|
||||
|
||||
@@ -62,6 +64,7 @@ public class Startup
|
||||
ConfigureMareServices(services, mareConfig);
|
||||
|
||||
services.AddHealthChecks();
|
||||
services.AddControllers();
|
||||
}
|
||||
|
||||
private static void ConfigureMareServices(IServiceCollection services, IConfigurationSection mareConfig)
|
||||
@@ -121,17 +124,35 @@ public class Startup
|
||||
{
|
||||
services.AddSingleton<SecretKeyAuthenticatorService>();
|
||||
services.AddTransient<IAuthorizationHandler, UserRequirementHandler>();
|
||||
services.AddAuthentication(SecretKeyAuthenticationHandler.AuthScheme)
|
||||
.AddScheme<AuthenticationSchemeOptions, SecretKeyAuthenticationHandler>(SecretKeyAuthenticationHandler.AuthScheme, options => { options.Validate(); });
|
||||
|
||||
services.AddOptions<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme)
|
||||
.Configure<IConfigurationService<MareConfigurationAuthBase>>((o, s) =>
|
||||
{
|
||||
o.TokenValidationParameters = new()
|
||||
{
|
||||
ValidateIssuer = false,
|
||||
ValidateLifetime = false,
|
||||
ValidateAudience = false,
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(s.GetValue<string>(nameof(MareConfigurationAuthBase.Jwt))))
|
||||
};
|
||||
});
|
||||
|
||||
services.AddAuthentication(o =>
|
||||
{
|
||||
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
}).AddJwtBearer();
|
||||
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.DefaultPolicy = new AuthorizationPolicyBuilder()
|
||||
.AddAuthenticationSchemes(SecretKeyAuthenticationHandler.AuthScheme)
|
||||
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
|
||||
.RequireAuthenticatedUser().Build();
|
||||
options.AddPolicy("Authenticated", policy =>
|
||||
{
|
||||
policy.AddAuthenticationSchemes(SecretKeyAuthenticationHandler.AuthScheme);
|
||||
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
|
||||
policy.RequireAuthenticatedUser();
|
||||
});
|
||||
options.AddPolicy("Identified", policy =>
|
||||
@@ -306,7 +327,8 @@ public class Startup
|
||||
endpoints.MapGrpcService<GrpcConfigurationService<ServerConfiguration>>().AllowAnonymous();
|
||||
}
|
||||
|
||||
endpoints.MapHealthChecks("/health").WithMetadata(new AllowAnonymousAttribute());
|
||||
endpoints.MapHealthChecks("/health").AllowAnonymous();
|
||||
endpoints.MapControllers().AllowAnonymous();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user