Started implementing oauth2 based on MoonCore helper services
Its more or less a test how well the helper services improve the implementation. I havent implemented anything fancy here atm. Just testing the oauth2 flow
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MoonCore.Extended.Abstractions;
|
||||
using MoonCore.Extended.Helpers;
|
||||
using MoonCore.Extended.OAuth2.ApiServer;
|
||||
using MoonCore.Helpers;
|
||||
using MoonCore.Services;
|
||||
using Moonlight.ApiServer.Attributes;
|
||||
using Moonlight.ApiServer.Configuration;
|
||||
using Moonlight.ApiServer.Database.Entities;
|
||||
using Moonlight.ApiServer.Helpers.Authentication;
|
||||
using Moonlight.ApiServer.Services;
|
||||
using Moonlight.Shared.Http.Requests.Auth;
|
||||
@@ -11,39 +18,58 @@ namespace Moonlight.ApiServer.Http.Controllers.Auth;
|
||||
[Route("api/auth")]
|
||||
public class AuthController : Controller
|
||||
{
|
||||
private readonly AuthService AuthService;
|
||||
private readonly OAuth2Service OAuth2Service;
|
||||
private readonly TokenHelper TokenHelper;
|
||||
private readonly ConfigService<AppConfiguration> ConfigService;
|
||||
private readonly DatabaseRepository<User> UserRepository;
|
||||
|
||||
public AuthController(AuthService authService)
|
||||
public AuthController(OAuth2Service oAuth2Service, TokenHelper tokenHelper, DatabaseRepository<User> userRepository, ConfigService<AppConfiguration> configService)
|
||||
{
|
||||
AuthService = authService;
|
||||
OAuth2Service = oAuth2Service;
|
||||
TokenHelper = tokenHelper;
|
||||
UserRepository = userRepository;
|
||||
ConfigService = configService;
|
||||
}
|
||||
|
||||
[HttpPost("login")]
|
||||
public async Task<LoginResponse> Login([FromBody] LoginRequest request)
|
||||
[HttpGet("start")]
|
||||
public async Task<AuthStartResponse> Start()
|
||||
{
|
||||
var user = await AuthService.Login(request.Email, request.Password);
|
||||
var data = await OAuth2Service.StartAuthorizing();
|
||||
|
||||
return new LoginResponse()
|
||||
{
|
||||
Token = await AuthService.GenerateToken(user)
|
||||
};
|
||||
return Mapper.Map<AuthStartResponse>(data);
|
||||
}
|
||||
|
||||
[HttpPost("register")]
|
||||
public async Task<RegisterResponse> Register([FromBody] RegisterRequest request)
|
||||
[HttpGet("handle")]
|
||||
public async Task Handle([FromQuery(Name = "code")] string code)
|
||||
{
|
||||
var user = await AuthService.Register(
|
||||
request.Username,
|
||||
request.Email,
|
||||
request.Password
|
||||
);
|
||||
//TODO: Validate jwt syntax
|
||||
|
||||
return new RegisterResponse()
|
||||
var accessData = await OAuth2Service.RequestAccess(code);
|
||||
|
||||
//TODO: Add modular oauth2 consumer system
|
||||
var userId = 1;
|
||||
|
||||
var user = UserRepository.Get().First(x => x.Id == userId);
|
||||
|
||||
user.AccessToken = accessData.AccessToken;
|
||||
user.RefreshToken = accessData.RefreshToken;
|
||||
user.RefreshTimestamp = DateTime.UtcNow.AddSeconds(accessData.ExpiresIn);
|
||||
|
||||
UserRepository.Update(user);
|
||||
|
||||
var authConfig = ConfigService.Get().Authentication;
|
||||
var tokenPair = await TokenHelper.GeneratePair(authConfig.MlAccessSecret, authConfig.MlAccessSecret, data =>
|
||||
{
|
||||
Token = await AuthService.GenerateToken(user)
|
||||
};
|
||||
data.Add("userId", user.Id.ToString());
|
||||
});
|
||||
|
||||
Response.Cookies.Append("ml-access", tokenPair.AccessToken);
|
||||
Response.Cookies.Append("ml-refresh", tokenPair.RefreshToken);
|
||||
Response.Cookies.Append("ml-timestamp", DateTimeOffset.UtcNow.AddSeconds(3600).ToUnixTimeSeconds().ToString());
|
||||
|
||||
Response.Redirect("/");
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("check")]
|
||||
[RequirePermission("meta.authenticated")]
|
||||
public async Task<CheckResponse> Check()
|
||||
|
||||
133
Moonlight.ApiServer/Http/Controllers/OAuth2/OAuth2Controller.cs
Normal file
133
Moonlight.ApiServer/Http/Controllers/OAuth2/OAuth2Controller.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MoonCore.Exceptions;
|
||||
using MoonCore.Extended.Abstractions;
|
||||
using MoonCore.Extended.OAuth2.AuthServer;
|
||||
using MoonCore.Extended.OAuth2.Models;
|
||||
using MoonCore.Services;
|
||||
using Moonlight.ApiServer.Configuration;
|
||||
using Moonlight.ApiServer.Database.Entities;
|
||||
using Moonlight.ApiServer.Services;
|
||||
|
||||
namespace Moonlight.ApiServer.Http.Controllers.OAuth2;
|
||||
|
||||
[ApiController]
|
||||
[Route("oauth2")]
|
||||
public class OAuth2Controller : Controller
|
||||
{
|
||||
private readonly OAuth2Service OAuth2Service;
|
||||
private readonly AuthService AuthService;
|
||||
private readonly DatabaseRepository<User> UserRepository;
|
||||
private readonly ConfigService<AppConfiguration> ConfigService;
|
||||
|
||||
public OAuth2Controller(OAuth2Service oAuth2Service, ConfigService<AppConfiguration> configService,
|
||||
AuthService authService, DatabaseRepository<User> userRepository)
|
||||
{
|
||||
OAuth2Service = oAuth2Service;
|
||||
ConfigService = configService;
|
||||
AuthService = authService;
|
||||
UserRepository = userRepository;
|
||||
}
|
||||
|
||||
[HttpGet("authorize")]
|
||||
public async Task Authorize(
|
||||
[FromQuery(Name = "response_type")] string responseType,
|
||||
[FromQuery(Name = "client_id")] string clientId,
|
||||
[FromQuery(Name = "redirect_uri")] string redirectUri
|
||||
)
|
||||
{
|
||||
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);
|
||||
|
||||
Response.StatusCode = 200;
|
||||
await Response.WriteAsync(
|
||||
"<h1>Login lol</h1><br />" +
|
||||
"<br />" +
|
||||
"<br />" +
|
||||
"<form method=\"post\">" +
|
||||
"<label for=\"email\">Email:</label>" +
|
||||
"<input type=\"email\" id=\"email\" name=\"email\"><br>" +
|
||||
"<br>" +
|
||||
"<label for=\"password\">Password:</label>" +
|
||||
"<input type=\"password\" id=\"password\" name=\"password\"><br>" +
|
||||
"<br>" +
|
||||
"<input type=\"submit\" value=\"Submit\">" +
|
||||
"</form>"
|
||||
);
|
||||
}
|
||||
|
||||
[HttpPost("authorize")]
|
||||
public async Task AuthorizePost(
|
||||
[FromQuery(Name = "response_type")] string responseType,
|
||||
[FromQuery(Name = "client_id")] string clientId,
|
||||
[FromQuery(Name = "redirect_uri")] string redirectUri,
|
||||
[FromForm(Name = "email")] string email,
|
||||
[FromForm(Name = "password")] string password
|
||||
)
|
||||
{
|
||||
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);
|
||||
|
||||
var user = await AuthService.Login(email, password);
|
||||
|
||||
var code = await OAuth2Service.GenerateCode(data => { data.Add("userId", user.Id.ToString()); });
|
||||
|
||||
var redirectUrl = redirectUri +
|
||||
$"?code={code}";
|
||||
|
||||
Response.Redirect(redirectUrl);
|
||||
}
|
||||
|
||||
[HttpPost("access")]
|
||||
public async Task<AccessData> Access(
|
||||
[FromForm(Name = "client_id")] string clientId,
|
||||
[FromForm(Name = "client_secret")] string clientSecret,
|
||||
[FromForm(Name = "redirect_uri")] string redirectUri,
|
||||
[FromForm(Name = "grant_type")] string grantType,
|
||||
[FromForm(Name = "code")] string code
|
||||
)
|
||||
{
|
||||
if (grantType != "authorization_code")
|
||||
throw new HttpApiException("Invalid grant type", 400);
|
||||
|
||||
User? user = null;
|
||||
|
||||
var access = await OAuth2Service.ValidateAccess(clientId, clientSecret, redirectUri, code, data =>
|
||||
{
|
||||
if (!data.TryGetValue("userId", out var userIdStr))
|
||||
return false;
|
||||
|
||||
if (!int.TryParse(userIdStr, out var userId))
|
||||
return false;
|
||||
|
||||
user = UserRepository.Get().FirstOrDefault(x => x.Id == userId);
|
||||
|
||||
return user != null;
|
||||
}, data =>
|
||||
{
|
||||
data.Add("userId", user!.Id.ToString());
|
||||
});
|
||||
|
||||
if (access == null)
|
||||
throw new HttpApiException("Unable to validate access", 400);
|
||||
|
||||
return access;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user