Files
Berufsschule_HAM/src/Controllers/UsersController.cs
2025-11-03 19:07:36 +01:00

222 lines
9.2 KiB
C#

using Berufsschule_HAM.Services;
using Microsoft.AspNetCore.Mvc;
using Novell.Directory.Ldap;
using Berufsschule_HAM.Models;
using Berufsschule_HAM.Helpers;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Authorization;
using System.Text.Json;
using System.Buffers.Text;
[Authorize(Roles = "CanManageUsers")]
[Route("[controller]")]
public class UsersController : Controller
{
private readonly LdapService _ldap;
private readonly ILogger<UsersController> _logger;
public UsersController(LdapService ldap, ILogger<UsersController> logger)
{
_ldap = ldap;
_logger = logger;
}
[HttpGet("GetAll")]
public async Task<IEnumerable<UserModel>> GetAll(UsersGetAllRequestModel requestModel)
{
string? uid = requestModel.Uid;
List<string> attributes = ["cn", "sn", "title", "uid", "jpegPhoto", "userPassword", "description"];
if (!requestModel.Cn) attributes.Remove("cn");
if (!requestModel.Sn) attributes.Remove("sn");
if (!requestModel.Title) attributes.Remove("title");
if (!requestModel.JpegPhoto) attributes.Remove("jpegPhoto");
if (!requestModel.UserPassword) attributes.Remove("userPassword");
if (!requestModel.Description) attributes.Remove("description");
if (uid is null)
{
var users = await _ldap.ListUsersAsync([.. attributes]);
return users;
}
else
{
var user = await _ldap.GetUserByUidAsync(uid, [.. attributes]);
return [user];
}
}
[HttpDelete("Delete")]
public async Task<UsersDeleteRequestModel> Delete(string uid)
{
try
{
await _ldap.DeleteUserAsync(uid);
return new UsersDeleteRequestModel(true);
}
catch (Exception ex)
{
return new UsersDeleteRequestModel(false, ex.Message);
}
}
[HttpPost("Create")]
public async Task<UsersCreateResponseModel> Create([FromBody] UsersCreateRequestModel requestModel)
{
if (requestModel is null)
{
return new() { Success = false, Exception = "The request model is null" };
}
try
{
Task<AdminSettingsModel> settingsTask = _ldap.GetAdminSettingsModelAsync();
string? jpegPhoto = requestModel.JpegPhoto;
string? title = requestModel.Title;
string userPassword = requestModel.UserPassword ?? "";
UserDescription? description = requestModel.Description;
jpegPhoto ??= Convert.ToBase64String(System.IO.File.ReadAllBytes("wwwroot/user_default.jpeg")); // TODO: cleanup - make this a config setting
string uid = UsersHelper.CreateUsername(requestModel.Cn ?? "", requestModel.Sn ?? "");
title ??= "";
description ??= new() {Address = new(), BirthDate = "", Workplace = "", Groups = []};
if (!userPassword.StartsWith('{'))
{
AdminSettingsModel settings = await settingsTask;
byte[] passwordBytes = Encoding.UTF8.GetBytes(userPassword);
byte[] hashedPassword = settings.hashAlgorithm?.ComputeHash(passwordBytes) ?? throw new Exception("Hash algorithm not instantiated yet");
userPassword = $"{{{settings.DefaultHashAlgorithm.ToUpperInvariant()}}}{Convert.ToBase64String(hashedPassword)}";
}
LdapAttributeSet attributeSet =
[
new LdapAttribute("objectClass", "inetOrgPerson"),
new LdapAttribute("cn", requestModel.Cn),
new LdapAttribute("sn", requestModel.Sn),
new LdapAttribute("title", title),
new LdapAttribute("uid", uid),
new LdapAttribute("jpegPhoto", jpegPhoto),
new LdapAttribute("description", JsonSerializer.Serialize(description)),
new LdapAttribute("userPassword", userPassword),
];
await _ldap.CreateUser(uid, attributeSet);
return new(){Success = true, Uid = uid};
}
catch (Exception ex)
{
_logger.LogError("Unable to create user: {ex.Message} - {ex.StackTrace}", [ex.Message, ex.StackTrace]);
return new() {Success = false, Exception = ex.Message};
}
}
[HttpPost("Update")]
public async Task<UsersUpdateResponseModel> Update([FromBody] UsersModifyRequestModel requestModel)
{
if (requestModel is null)
{
_logger.LogError("Unable to update a user because the UsersModifyRequestModel is null");
return new() { Success = false };
}
try
{
Task<AdminSettingsModel> settingsTask = _ldap.GetAdminSettingsModelAsync();
string uid = requestModel.Uid;
UserModel? user = null;
if (requestModel.NewUid is not null && requestModel.NewUid.Length > 0)
{
await _ldap.UpdateUser(uid, "uid", requestModel.NewUid);
uid = requestModel.NewUid;
}
if (requestModel.Title is not null)
{
await _ldap.UpdateUser(uid, "title", requestModel.Title);
}
if (requestModel.Description is not null)
{
await _ldap.UpdateUser(uid, "description", JsonSerializer.Serialize(requestModel.Description));
}
if (requestModel.JpegPhoto is not null && requestModel.JpegPhoto.Length > 0)
{
await _ldap.UpdateUser(uid, "jpegPhoto", requestModel.JpegPhoto);
}
if (requestModel.UserPassword is not null && requestModel.UserPassword.Length > 0)
{
AdminSettingsModel settings = await settingsTask;
byte[] passwordBytes = Encoding.UTF8.GetBytes(requestModel.UserPassword);
byte[] hashedPassword = settings.hashAlgorithm?.ComputeHash(passwordBytes) ?? throw new Exception("Hash algorithm not instantiated yet");
requestModel.UserPassword = $"{{{settings.DefaultHashAlgorithm.ToUpperInvariant()}}}{Convert.ToBase64String(hashedPassword)}";
await _ldap.UpdateUser(uid, "userPassword", requestModel.UserPassword);
}
string newUid = uid;
if (requestModel.Cn is not null)
{
await _ldap.UpdateUser(uid, "cn", requestModel.Cn);
user ??= await _ldap.GetUserByUidAsync(uid);
newUid = UsersHelper.CreateUsername(requestModel.Cn, user.Sn ?? "");
}
if (requestModel.Sn is not null)
{
await _ldap.UpdateUser(uid, "sn", requestModel.Sn);
user ??= await _ldap.GetUserByUidAsync(uid);
newUid = UsersHelper.CreateUsername(user.Cn ?? "", requestModel.Sn);
}
if (newUid.Length == 0)
{
throw new Exception("Username cannot be empty");
}
if (newUid != uid)
{
await _ldap.UpdateUser(uid, "uid", newUid);
uid = newUid;
}
return new() { Success = true, NewUid = uid };
} catch (Exception ex)
{
return new() { Success = false, Exception = ex.Message };
}
}
[HttpPost("AddGroup")]
public async Task<bool> AddGroup([FromBody]UsersAddGroupRequestModel requestModel)
{
try
{
UserModel userModel = await _ldap.GetUserByUidAsync(requestModel.Uid);
userModel.Description ??= new() { Address = new(), BirthDate = "", Workplace = "" };
userModel.Description.Groups ??= [];
try
{
GroupModel group = await _ldap.GetGroupByCnAsync(requestModel.GroupUid, _ldap.GroupsAttributes);
} catch (Exception)
{
return false;
}
userModel.Description.Groups.Add(requestModel.GroupUid);
await _ldap.UpdateUser(requestModel.Uid, "description", JsonSerializer.Serialize(userModel.Description));
return true;
} catch (Exception ex)
{
_logger.LogError("Unable to add group {} to user {}: {ex.Message} - {ex.StackTrace}", [requestModel.GroupUid, requestModel.Uid, ex.Message, ex.StackTrace]);
return false;
}
}
[HttpPost("RemoveGroup")]
public async Task<bool> RemoveGroup([FromBody]UsersRemoveGroupRequestModel requestModel)
{
try
{
UserModel userModel = await _ldap.GetUserByUidAsync(requestModel.Uid);
userModel.Description ??= new() { Address = new(), BirthDate = "", Workplace = "" };
userModel.Description.Groups ??= [];
userModel.Description.Groups.Remove(requestModel.GroupUid);
await _ldap.UpdateUser(requestModel.Uid, "description", JsonSerializer.Serialize(userModel.Description));
return true;
} catch (Exception ex)
{
_logger.LogError("Unable to remove group {} from user {}: {ex.Message} - {ex.StackTrace}", [requestModel.GroupUid, requestModel.Uid, ex.Message, ex.StackTrace]);
return false;
}
}
}