Improved token handling and used new validate auth request for oauth2

This commit is contained in:
Masu Baumgartner
2024-10-18 13:11:02 +02:00
parent 9d1351527d
commit 6be3b8338d
5 changed files with 76 additions and 39 deletions

View File

@@ -17,13 +17,11 @@ public class OAuth2Controller : Controller
private readonly OAuth2Service OAuth2Service; private readonly OAuth2Service OAuth2Service;
private readonly AuthService AuthService; private readonly AuthService AuthService;
private readonly DatabaseRepository<User> UserRepository; private readonly DatabaseRepository<User> UserRepository;
private readonly ConfigService<AppConfiguration> ConfigService;
public OAuth2Controller(OAuth2Service oAuth2Service, ConfigService<AppConfiguration> configService, public OAuth2Controller(OAuth2Service oAuth2Service,
AuthService authService, DatabaseRepository<User> userRepository) AuthService authService, DatabaseRepository<User> userRepository)
{ {
OAuth2Service = oAuth2Service; OAuth2Service = oAuth2Service;
ConfigService = configService;
AuthService = authService; AuthService = authService;
UserRepository = userRepository; UserRepository = userRepository;
} }
@@ -38,14 +36,8 @@ public class OAuth2Controller : Controller
if (responseType != "code") if (responseType != "code")
throw new HttpApiException("Invalid response type", 400); throw new HttpApiException("Invalid response type", 400);
var config = ConfigService.Get(); if (!await OAuth2Service.IsValidAuthorization(clientId, redirectUri))
throw new HttpApiException("Invalid authorization request", 400);
// TODO: This call should be handled by the OAuth2Service
if (clientId != config.Authentication.ClientId)
throw new HttpApiException("Invalid client id", 400);
if (redirectUri != (config.Authentication.AuthorizationRedirect ?? $"{config.PublicUrl}/api/auth/handle"))
throw new HttpApiException("Invalid redirect uri", 400);
Response.StatusCode = 200; Response.StatusCode = 200;
await Response.WriteAsync( await Response.WriteAsync(
@@ -76,14 +68,8 @@ public class OAuth2Controller : Controller
if (responseType != "code") if (responseType != "code")
throw new HttpApiException("Invalid response type", 400); throw new HttpApiException("Invalid response type", 400);
var config = ConfigService.Get(); if (!await OAuth2Service.IsValidAuthorization(clientId, redirectUri))
throw new HttpApiException("Invalid authorization request", 400);
// TODO: This call should be handled by the OAuth2Service
if (clientId != config.Authentication.ClientId)
throw new HttpApiException("Invalid client id", 400);
if (redirectUri != (config.Authentication.AuthorizationRedirect ?? $"{config.PublicUrl}/api/auth/handle"))
throw new HttpApiException("Invalid redirect uri", 400);
var user = await AuthService.Login(email, password); var user = await AuthService.Login(email, password);

View File

@@ -1,14 +1,4 @@
using System.Text.Json; namespace Moonlight.ApiServer.Http.Middleware;
using MoonCore.Extended.Abstractions;
using MoonCore.Extended.Helpers;
using MoonCore.Extended.Models;
using MoonCore.Extended.OAuth2.ApiServer;
using MoonCore.Services;
using Moonlight.ApiServer.Configuration;
using Moonlight.ApiServer.Database.Entities;
using Moonlight.ApiServer.Helpers.Authentication;
namespace Moonlight.ApiServer.Http.Middleware;
public class AuthenticationMiddleware public class AuthenticationMiddleware
{ {
@@ -23,10 +13,10 @@ public class AuthenticationMiddleware
public async Task InvokeAsync(HttpContext context) public async Task InvokeAsync(HttpContext context)
{ {
await Authenticate(context); //await Authenticate(context);
await Next(context); await Next(context);
} }
/*
private async Task Authenticate(HttpContext context) private async Task Authenticate(HttpContext context)
{ {
var request = context.Request; var request = context.Request;
@@ -105,7 +95,7 @@ public class AuthenticationMiddleware
// Save permission state // Save permission state
context.User = new PermClaimsPrinciple(permissions, user); context.User = new PermClaimsPrinciple(permissions, user);
/* /// IGNORE
string? token = null; string? token = null;
// Cookie for Moonlight.Client // Cookie for Moonlight.Client
@@ -140,7 +130,7 @@ public class AuthenticationMiddleware
if (token.Count(x => x == '.') == 2) // JWT only has two dots if (token.Count(x => x == '.') == 2) // JWT only has two dots
await AuthenticateUser(context, token); await AuthenticateUser(context, token);
else else
await AuthenticateApiKey(context, token);*/ await AuthenticateApiKey(context, token);
} }
private async Task AuthenticateUser(HttpContext context, string jwt) private async Task AuthenticateUser(HttpContext context, string jwt)
@@ -182,4 +172,5 @@ public class AuthenticationMiddleware
private async Task AuthenticateApiKey(HttpContext context, string apiKey) private async Task AuthenticateApiKey(HttpContext context, string apiKey)
{ {
} }
*/
} }

View File

@@ -12,8 +12,8 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="MoonCore" Version="1.5.9" /> <PackageReference Include="MoonCore" Version="1.6.1" />
<PackageReference Include="MoonCore.Extended" Version="1.0.8" /> <PackageReference Include="MoonCore.Extended" Version="1.1.0" />
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.0" /> <PackageReference Include="MoonCore.PluginFramework" Version="1.0.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>

View File

@@ -1,13 +1,18 @@
using System.Text.Json;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using MoonCore.Extended.Abstractions; using MoonCore.Extended.Abstractions;
using MoonCore.Extended.Extensions; using MoonCore.Extended.Extensions;
using MoonCore.Extended.Helpers; using MoonCore.Extended.Helpers;
using MoonCore.Extended.OAuth2.ApiServer;
using MoonCore.Extensions; using MoonCore.Extensions;
using MoonCore.Helpers; using MoonCore.Helpers;
using MoonCore.Models;
using MoonCore.Services; using MoonCore.Services;
using Moonlight.ApiServer.Configuration; using Moonlight.ApiServer.Configuration;
using Moonlight.ApiServer.Database; using Moonlight.ApiServer.Database;
using Moonlight.ApiServer.Database.Entities;
using Moonlight.ApiServer.Helpers; using Moonlight.ApiServer.Helpers;
using Moonlight.ApiServer.Helpers.Authentication;
using Moonlight.ApiServer.Http.Middleware; using Moonlight.ApiServer.Http.Middleware;
// Prepare file system // Prepare file system
@@ -119,7 +124,7 @@ if (config.Authentication.UseLocalOAuth2Service)
configuration.RefreshSecret = config.Authentication.RefreshSecret; configuration.RefreshSecret = config.Authentication.RefreshSecret;
configuration.ClientId = config.Authentication.ClientId; configuration.ClientId = config.Authentication.ClientId;
configuration.ClientId = config.Authentication.ClientSecret; configuration.ClientSecret = config.Authentication.ClientSecret;
configuration.CodeSecret = config.Authentication.CodeSecret; configuration.CodeSecret = config.Authentication.CodeSecret;
configuration.AuthorizationRedirect = configuration.AuthorizationRedirect =
config.Authentication.AuthorizationRedirect ?? $"{config.PublicUrl}/api/auth/handle"; config.Authentication.AuthorizationRedirect ?? $"{config.PublicUrl}/api/auth/handle";
@@ -128,6 +133,59 @@ if (config.Authentication.UseLocalOAuth2Service)
}); });
} }
builder.Services.AddTokenAuthentication(configuration =>
{
configuration.AccessSecret = config.Authentication.AccessSecret;
configuration.DataLoader = async (data, provider, context) =>
{
if (!data.TryGetValue("userId", out var userIdStr) || !int.TryParse(userIdStr, out var userId))
return false;
var userRepo = provider.GetRequiredService<DatabaseRepository<User>>();
var user = userRepo.Get().FirstOrDefault(x => x.Id == userId);
if (user == null)
return false;
// OAuth2 - Check external
if (DateTime.UtcNow > user.RefreshTimestamp)
{
var tokenConsumer = new TokenConsumer(user.AccessToken, user.RefreshToken, user.RefreshTimestamp,
async refreshToken =>
{
var oauth2Service = context.RequestServices.GetRequiredService<OAuth2Service>();
var accessData = await oauth2Service.RefreshAccess(refreshToken);
user.AccessToken = accessData.AccessToken;
user.RefreshToken = accessData.RefreshToken;
user.RefreshTimestamp = DateTime.UtcNow.AddSeconds(accessData.ExpiresIn);
userRepo.Update(user);
return new TokenPair()
{
AccessToken = user.AccessToken,
RefreshToken = user.RefreshToken
};
});
await tokenConsumer.GetAccessToken();
//TODO: API CALL (modular)
}
// Load permissions, handle empty values
var permissions = JsonSerializer.Deserialize<string[]>(
string.IsNullOrEmpty(user.PermissionsJson) ? "[]" : user.PermissionsJson
) ?? [];
// Save permission state
context.User = new PermClaimsPrinciple(permissions, user);
return true;
};
});
// Database // Database
var databaseHelper = new DatabaseHelper( var databaseHelper = new DatabaseHelper(
loggerFactory.CreateLogger<DatabaseHelper>() loggerFactory.CreateLogger<DatabaseHelper>()
@@ -168,7 +226,9 @@ app.UseStaticFiles();
app.UseRouting(); app.UseRouting();
app.UseMiddleware<ApiErrorMiddleware>(); app.UseMiddleware<ApiErrorMiddleware>();
app.UseMiddleware<AuthenticationMiddleware>();
app.UseTokenAuthentication(_ => {});
app.UseMiddleware<AuthorizationMiddleware>(); app.UseMiddleware<AuthorizationMiddleware>();
app.MapControllers(); app.MapControllers();

View File

@@ -10,7 +10,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.6"/> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.6"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.6" PrivateAssets="all"/> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.6" PrivateAssets="all"/>
<PackageReference Include="MoonCore" Version="1.5.9" /> <PackageReference Include="MoonCore" Version="1.6.1" />
<PackageReference Include="MoonCore.Blazor" Version="1.2.1" /> <PackageReference Include="MoonCore.Blazor" Version="1.2.1" />
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.0" /> <PackageReference Include="MoonCore.PluginFramework" Version="1.0.0" />
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.0.6" /> <PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.0.6" />