Move registration to AuthenticationService, add scripts for UserLogin and UserRegistration
This commit is contained in:
parent
117f2d6c2b
commit
e9e5bc096d
6 changed files with 197 additions and 74 deletions
|
|
@ -3,16 +3,10 @@ using LANCommander.SDK.Helpers;
|
|||
using LANCommander.SDK.Models;
|
||||
using LANCommander.SDK.PowerShell;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Steamworks.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace LANCommander.SDK.Services
|
||||
{
|
||||
|
|
@ -41,6 +35,78 @@ namespace LANCommander.SDK.Services
|
|||
Client = client;
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
#region Authentication Scripts
|
||||
public async Task RunUserLoginScript(Script loginScript, User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var op = Logger.BeginOperation("Executing user login script"))
|
||||
{
|
||||
var script = new PowerShellScript(Enums.ScriptType.UserLogin);
|
||||
|
||||
script.AddVariable("User", user);
|
||||
script.AddVariable("ServerAddress", Client.BaseUrl.ToString());
|
||||
|
||||
script.UseInline(loginScript.Contents);
|
||||
|
||||
try
|
||||
{
|
||||
op
|
||||
.Enrich("UserId", user.Id)
|
||||
.Enrich("Username", user.UserName)
|
||||
.Enrich("ScriptId", loginScript.Id)
|
||||
.Enrich("ScriptName", loginScript.Name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogError(ex, "Could not enrich logs");
|
||||
}
|
||||
|
||||
await script.ExecuteAsync<int>();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogError(ex, "Could not execute user login script");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RunUserRegistrationScript(Script registrationScript, User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var op = Logger.BeginOperation("Executing user registration script"))
|
||||
{
|
||||
var script = new PowerShellScript(Enums.ScriptType.UserRegistration);
|
||||
|
||||
script.AddVariable("User", user);
|
||||
script.AddVariable("ServerAddress", Client.BaseUrl.ToString());
|
||||
|
||||
script.UseInline(registrationScript.Contents);
|
||||
|
||||
try
|
||||
{
|
||||
op
|
||||
.Enrich("UserId", user.Id)
|
||||
.Enrich("Username", user.UserName)
|
||||
.Enrich("ScriptId", registrationScript.Id)
|
||||
.Enrich("ScriptName", registrationScript.Name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogError(ex, "Could not enrich logs");
|
||||
}
|
||||
|
||||
await script.ExecuteAsync<int>();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogError(ex, "Could not execute user registration script");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Redistributables
|
||||
public async Task<bool> RunDetectInstallScriptAsync(string installDirectory, Guid gameId, Guid redistributableId)
|
||||
|
|
|
|||
|
|
@ -3,20 +3,52 @@ using System.IdentityModel.Tokens.Jwt;
|
|||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using AutoMapper;
|
||||
using LANCommander.SDK.Enums;
|
||||
using LANCommander.SDK.Models;
|
||||
using LANCommander.Server.Services.Exceptions;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
using YamlDotNet.Serialization;
|
||||
using PascalCaseNamingConvention = YamlDotNet.Serialization.NamingConventions.PascalCaseNamingConvention;
|
||||
|
||||
namespace LANCommander.Server.Services
|
||||
{
|
||||
public class AuthenticationService(ILogger<AuthenticationService> logger, UserService userService) : BaseService(logger)
|
||||
public class AuthenticationService(
|
||||
ILogger<AuthenticationService> logger,
|
||||
IMapper mapper,
|
||||
UserService userService,
|
||||
RoleService roleService,
|
||||
ScriptService scriptService) : BaseService(logger)
|
||||
{
|
||||
public async Task<AuthToken> LoginAsync(string userName, string password)
|
||||
{
|
||||
if (!String.IsNullOrWhiteSpace(userName) && await userService.CheckPassword(userName, password))
|
||||
{
|
||||
return await LoginAsync(userName);
|
||||
var token = await LoginAsync(userName);
|
||||
|
||||
try
|
||||
{
|
||||
var user = await userService.GetAsync<User>(userName);
|
||||
var scripts = await scriptService.GetAsync<SDK.Models.Script>(s => s.Type == ScriptType.UserLogin);
|
||||
|
||||
if (scripts.Any())
|
||||
{
|
||||
var client = new SDK.Client(_settings.Beacon.Address, "", logger);
|
||||
|
||||
client.UseToken(token);
|
||||
|
||||
foreach (var script in scripts)
|
||||
{
|
||||
await client.Scripts.RunUserLoginScript(script, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError(ex, "Could not execute user login script");
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
else
|
||||
throw new Exception("Invalid username or password");
|
||||
|
|
@ -108,6 +140,76 @@ namespace LANCommander.Server.Services
|
|||
Expiration = newAccessToken.ValidTo
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<AuthToken> RegisterAsync(string userName, string password, string passwordConfirmation)
|
||||
{
|
||||
if (password != passwordConfirmation)
|
||||
throw new UserRegistrationException("Passwords don't match");
|
||||
|
||||
var user = await userService.GetAsync(userName);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
_logger?.LogDebug("Cannot register user with username {UserName}, already exists", userName);
|
||||
|
||||
throw new UserRegistrationException("Username is unavailable");
|
||||
}
|
||||
|
||||
user = new Data.Models.User();
|
||||
user.UserName = userName;
|
||||
|
||||
user = await userService.AddAsync(user);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
await userService.ChangePassword(user.UserName, password);
|
||||
|
||||
try
|
||||
{
|
||||
if (_settings.Roles.DefaultRoleId == Guid.Empty)
|
||||
{
|
||||
var defaultRole = await roleService.GetAsync(_settings.Roles.DefaultRoleId);
|
||||
|
||||
if (defaultRole != null)
|
||||
await userService.AddToRoleAsync(user.UserName, defaultRole.Name);
|
||||
}
|
||||
|
||||
var token = await LoginAsync(user.UserName, password);
|
||||
|
||||
logger?.LogDebug("Successfully registered user {UserName}", user.UserName);
|
||||
|
||||
try
|
||||
{
|
||||
var scripts = await scriptService.GetAsync<SDK.Models.Script>(s => s.Type == ScriptType.UserLogin);
|
||||
|
||||
if (scripts.Any())
|
||||
{
|
||||
var client = new SDK.Client(_settings.Beacon.Address, "", logger);
|
||||
|
||||
client.UseToken(token);
|
||||
|
||||
foreach (var script in scripts)
|
||||
{
|
||||
await client.Scripts.RunUserRegistrationScript(script, mapper.Map<SDK.Models.User>(user));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError(ex, "Could not execute user login script");
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError(ex, "Could not register user {UserName}", user.UserName);
|
||||
throw new UserRegistrationException("An unknown error occurred while registering");
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new UserRegistrationException("Unknown Error");
|
||||
}
|
||||
|
||||
private ClaimsPrincipal? GetPrincipalFromExpiredToken(string? token)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ public class UserRegistrationException : Exception
|
|||
{
|
||||
public IdentityResult IdentityResult { get; set; }
|
||||
|
||||
public UserRegistrationException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public UserRegistrationException(IdentityResult identityResult, string message) : base(message)
|
||||
{
|
||||
IdentityResult = identityResult;
|
||||
|
|
|
|||
|
|
@ -17,13 +17,6 @@ using User = LANCommander.Server.Data.Models.User;
|
|||
|
||||
namespace LANCommander.Server.Controllers.Api
|
||||
{
|
||||
public class TokenModel
|
||||
{
|
||||
public string AccessToken { get; set; }
|
||||
public string RefreshToken { get; set; }
|
||||
public DateTime Expiration { get; set; }
|
||||
}
|
||||
|
||||
public class LoginModel
|
||||
{
|
||||
public string UserName { get; set; }
|
||||
|
|
@ -147,64 +140,17 @@ namespace LANCommander.Server.Controllers.Api
|
|||
[HttpPost("Register")]
|
||||
public async Task<IActionResult> RegisterAsync([FromBody] RegisterModel model)
|
||||
{
|
||||
if (model.Password != model.PasswordConfirmation)
|
||||
return Unauthorized(new
|
||||
{
|
||||
Message = "Passwords don't match."
|
||||
});
|
||||
|
||||
var user = await UserService.GetAsync(model.UserName);
|
||||
|
||||
if (user != null)
|
||||
try
|
||||
{
|
||||
Logger?.LogDebug("Cannot register user with username {UserName}, already exists", model.UserName);
|
||||
var token = await AuthenticationService.RegisterAsync(model.UserName, model.Password,
|
||||
model.PasswordConfirmation);
|
||||
|
||||
return Unauthorized(new
|
||||
{
|
||||
Message = "Username is unavailable"
|
||||
});
|
||||
return Ok(token);
|
||||
}
|
||||
|
||||
user = new User();
|
||||
|
||||
user.UserName = model.UserName;
|
||||
|
||||
user = await UserService.AddAsync(user);
|
||||
|
||||
if (user != null)
|
||||
catch (Exception ex)
|
||||
{
|
||||
await UserService.ChangePassword(user.UserName, model.Password);
|
||||
|
||||
try
|
||||
{
|
||||
if (Settings.Roles.DefaultRoleId != Guid.Empty)
|
||||
{
|
||||
var defaultRole = await RoleService.GetAsync(Settings.Roles.DefaultRoleId);
|
||||
|
||||
if (defaultRole != null)
|
||||
await UserService.AddToRoleAsync(user.UserName, defaultRole.Name);
|
||||
}
|
||||
|
||||
var token = await AuthenticationService.LoginAsync(user.UserName, model.Password);
|
||||
|
||||
Logger?.LogDebug("Successfully registered user {UserName}", user.UserName);
|
||||
|
||||
return Ok(token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogError(ex, "Could not register user {UserName}", user.UserName);
|
||||
return BadRequest(new
|
||||
{
|
||||
Message = "An unknown error occurred"
|
||||
});
|
||||
}
|
||||
return Unauthorized(ex.Message);
|
||||
}
|
||||
|
||||
return Unauthorized(new
|
||||
{
|
||||
//Message = "Error:\n" + String.Join('\n', result.Errors.Select(e => e.Description))
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("AuthenticationProviders")]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
TItem="Script"
|
||||
HidePagination
|
||||
Responsive
|
||||
Query="s => (s.GameId != Guid.Empty && s.GameId == GameId) || (s.RedistributableId != Guid.Empty && s.RedistributableId == RedistributableId) || (s.ServerId != Guid.Empty && s.ServerId == ServerId)">
|
||||
Query="s => s.GameId == Guid.Empty && s.RedistributableId == Guid.Empty && s.ServerId == Guid.Empty">
|
||||
<BoundDataColumn Property="s => s.Type">
|
||||
@context.Type.GetDisplayName()
|
||||
</BoundDataColumn>
|
||||
|
|
@ -63,10 +63,6 @@
|
|||
{
|
||||
ScriptId = scriptId ?? default,
|
||||
AllowedTypes = AllowedTypes,
|
||||
ArchiveId = ArchiveId,
|
||||
GameId = GameId,
|
||||
RedistributableId = RedistributableId,
|
||||
ServerId = ServerId
|
||||
};
|
||||
|
||||
var modalRef = await ModalService.CreateModalAsync<ScriptEditorDialog, ScriptEditorOptions, Script>(modalOptions, options);
|
||||
|
|
|
|||
9
LANCommander.Server/UI/Pages/Settings/Scripts.razor
Normal file
9
LANCommander.Server/UI/Pages/Settings/Scripts.razor
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
@page "/Settings/Scripts"
|
||||
@using LANCommander.SDK.Enums
|
||||
@attribute [Authorize(Roles = RoleService.AdministratorRoleName)]
|
||||
|
||||
<PageHeader Title="Scripts" />
|
||||
|
||||
<div style="padding: 0 24px;">
|
||||
<ScriptEditor AllowedTypes="new [] { ScriptType.UserLogin, ScriptType.UserRegistration }" />
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue