Improved token handling and used new validate auth request for oauth2
This commit is contained in:
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
@@ -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"/>
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
Reference in New Issue
Block a user