diff --git a/Moonlight.ApiServer/Http/Controllers/OAuth2/OAuth2Controller.cs b/Moonlight.ApiServer/Http/Controllers/OAuth2/OAuth2Controller.cs index 62de5042..061acad7 100644 --- a/Moonlight.ApiServer/Http/Controllers/OAuth2/OAuth2Controller.cs +++ b/Moonlight.ApiServer/Http/Controllers/OAuth2/OAuth2Controller.cs @@ -17,13 +17,11 @@ public class OAuth2Controller : Controller private readonly OAuth2Service OAuth2Service; private readonly AuthService AuthService; private readonly DatabaseRepository UserRepository; - private readonly ConfigService ConfigService; - public OAuth2Controller(OAuth2Service oAuth2Service, ConfigService configService, + public OAuth2Controller(OAuth2Service oAuth2Service, AuthService authService, DatabaseRepository userRepository) { OAuth2Service = oAuth2Service; - ConfigService = configService; AuthService = authService; UserRepository = userRepository; } @@ -38,14 +36,8 @@ public class OAuth2Controller : Controller if (responseType != "code") throw new HttpApiException("Invalid response type", 400); - var config = ConfigService.Get(); - - // 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); + if (!await OAuth2Service.IsValidAuthorization(clientId, redirectUri)) + throw new HttpApiException("Invalid authorization request", 400); Response.StatusCode = 200; await Response.WriteAsync( @@ -76,14 +68,8 @@ public class OAuth2Controller : Controller if (responseType != "code") throw new HttpApiException("Invalid response type", 400); - var config = ConfigService.Get(); - - // 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); + if (!await OAuth2Service.IsValidAuthorization(clientId, redirectUri)) + throw new HttpApiException("Invalid authorization request", 400); var user = await AuthService.Login(email, password); diff --git a/Moonlight.ApiServer/Http/Middleware/AuthenticationMiddleware.cs b/Moonlight.ApiServer/Http/Middleware/AuthenticationMiddleware.cs index f4b30294..0960818e 100644 --- a/Moonlight.ApiServer/Http/Middleware/AuthenticationMiddleware.cs +++ b/Moonlight.ApiServer/Http/Middleware/AuthenticationMiddleware.cs @@ -1,14 +1,4 @@ -using System.Text.Json; -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; +namespace Moonlight.ApiServer.Http.Middleware; public class AuthenticationMiddleware { @@ -23,10 +13,10 @@ public class AuthenticationMiddleware public async Task InvokeAsync(HttpContext context) { - await Authenticate(context); + //await Authenticate(context); await Next(context); } - +/* private async Task Authenticate(HttpContext context) { var request = context.Request; @@ -105,7 +95,7 @@ public class AuthenticationMiddleware // Save permission state context.User = new PermClaimsPrinciple(permissions, user); - /* + /// IGNORE string? token = null; // Cookie for Moonlight.Client @@ -140,7 +130,7 @@ public class AuthenticationMiddleware if (token.Count(x => x == '.') == 2) // JWT only has two dots await AuthenticateUser(context, token); else - await AuthenticateApiKey(context, token);*/ + await AuthenticateApiKey(context, token); } private async Task AuthenticateUser(HttpContext context, string jwt) @@ -182,4 +172,5 @@ public class AuthenticationMiddleware private async Task AuthenticateApiKey(HttpContext context, string apiKey) { } +*/ } \ No newline at end of file diff --git a/Moonlight.ApiServer/Moonlight.ApiServer.csproj b/Moonlight.ApiServer/Moonlight.ApiServer.csproj index e0d46530..2b7f0291 100644 --- a/Moonlight.ApiServer/Moonlight.ApiServer.csproj +++ b/Moonlight.ApiServer/Moonlight.ApiServer.csproj @@ -12,8 +12,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/Moonlight.ApiServer/Program.cs b/Moonlight.ApiServer/Program.cs index 58d2016c..7803801a 100644 --- a/Moonlight.ApiServer/Program.cs +++ b/Moonlight.ApiServer/Program.cs @@ -1,13 +1,18 @@ +using System.Text.Json; using Microsoft.OpenApi.Models; using MoonCore.Extended.Abstractions; using MoonCore.Extended.Extensions; using MoonCore.Extended.Helpers; +using MoonCore.Extended.OAuth2.ApiServer; using MoonCore.Extensions; using MoonCore.Helpers; +using MoonCore.Models; using MoonCore.Services; using Moonlight.ApiServer.Configuration; using Moonlight.ApiServer.Database; +using Moonlight.ApiServer.Database.Entities; using Moonlight.ApiServer.Helpers; +using Moonlight.ApiServer.Helpers.Authentication; using Moonlight.ApiServer.Http.Middleware; // Prepare file system @@ -119,7 +124,7 @@ if (config.Authentication.UseLocalOAuth2Service) configuration.RefreshSecret = config.Authentication.RefreshSecret; configuration.ClientId = config.Authentication.ClientId; - configuration.ClientId = config.Authentication.ClientSecret; + configuration.ClientSecret = config.Authentication.ClientSecret; configuration.CodeSecret = config.Authentication.CodeSecret; configuration.AuthorizationRedirect = 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>(); + 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(); + + 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.IsNullOrEmpty(user.PermissionsJson) ? "[]" : user.PermissionsJson + ) ?? []; + + // Save permission state + context.User = new PermClaimsPrinciple(permissions, user); + + return true; + }; +}); + // Database var databaseHelper = new DatabaseHelper( loggerFactory.CreateLogger() @@ -168,7 +226,9 @@ app.UseStaticFiles(); app.UseRouting(); app.UseMiddleware(); -app.UseMiddleware(); + +app.UseTokenAuthentication(_ => {}); + app.UseMiddleware(); app.MapControllers(); diff --git a/Moonlight.Client/Moonlight.Client.csproj b/Moonlight.Client/Moonlight.Client.csproj index 7909ccdc..46d2787c 100644 --- a/Moonlight.Client/Moonlight.Client.csproj +++ b/Moonlight.Client/Moonlight.Client.csproj @@ -10,7 +10,7 @@ - +