using Microsoft.AspNetCore.Mvc; using Berufsschule_HAM.Models; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using System.Security.Claims; using Berufsschule_HAM.Services; using ElmahCore; using Berufsschule_HAM.Exceptions; using Microsoft.AspNetCore.Authorization; using Berufsschule_HAM.Helpers; [ApiExplorerSettings(IgnoreApi = true)] [Route("[controller]")] public class HomeController : Controller { private readonly LdapService _ldap; public HomeController(LdapService ldap) { _ldap = ldap ?? throw new ArgumentNullException(nameof(ldap)); } [Authorize] [HttpGet("Index")] [HttpGet("/")] public ActionResult Index() { return View(); } [Authorize(Roles = "CanManageAssets")] [HttpGet("Assets")] public async Task Assets() { IEnumerable assets = await _ldap.ListDeviceAsync(); List assetsTableViewModels = []; foreach (AssetModel asset in assets) { assetsTableViewModels.Add(new() { AssetCn = asset.Cn, AssetName = asset.Name, LocationName = asset.Location, UserUID = asset.Owner?.Split('=')[1], }); } return View(new HomeIndexViewModel() { AssetsTableViewModels = assetsTableViewModels }); } [Authorize(Roles = "CanInventorize")] [HttpGet("Inventory")] public ActionResult Inventory() { return View(); } [Authorize(Roles = "CanManageLocations")] [HttpGet("Locations")] public async Task LocationsAsync() { IEnumerable locations = await _ldap.ListLocationsAsync(); List LocationsTableViewModels = []; foreach (LocationModel location in locations) { LocationsTableViewModels.Add(new() { LocationID = location.Location, LocationName = location.Description?.Location ?? "", RoomNumber = location.Description?.RoomNumber ?? "", Seat = location.Description?.Seat ?? "" }); } return View(new LocationsIndexViewModel() { LocationTableViewModels = LocationsTableViewModels }); } [Authorize(Roles = "CanManageUsers")] [HttpGet("Users")] public async Task UsersAsync() { IEnumerable users = await _ldap.ListUsersAsync([.. _ldap.UsersAttributes.Where(attr => attr != "jpegPhoto" && attr != "userPassword")]); List UserTableViewModels = []; foreach (UserModel user in users) { UserTableViewModels.Add(new() { Name = user.Cn ?? "", Surname = user.Sn ?? "", Title = user.Title ?? "", Uid = user.Uid, Description = user.Description ?? new() {Address = new(), BirthDate = "", Workplace = "", Groups = []} }); } return View(new UsersIndexViewModel() { UserTableViewModels = UserTableViewModels }); } [Authorize(Roles = "CanManageUsers")] [HttpGet("UserPhoto")] [ResponseCache(Duration = 3600, Location = ResponseCacheLocation.Any, VaryByQueryKeys = new[] { "uid", "size" })] public async Task UserPhotoAsync(string uid, int? size) { UserModel? user = await _ldap.GetUserByUidAsync(uid, _ldap.UsersAttributes); if (user is null || user.JpegPhoto is null || user.JpegPhoto == "") { return File(ImageHelper.GetDefaultUserImage(size ?? 48), "image/webp"); } if (size is null) { return File(Convert.FromBase64String(user.JpegPhoto), "image/webp"); } if (size is not null) { AdminSettingsModel adminSettingsModel = await _ldap.GetAdminSettingsModelAsync(); size = Math.Min((int)size, adminSettingsModel.MaxDownloadableUserImageSize); } byte[] encodedFile = ImageHelper.ResizeAndConvertToWebp(user.JpegPhoto, size ?? 32); return File(encodedFile, "image/webp"); } [Authorize(Roles = "CanManageGroups")] [HttpGet("Groups")] public async Task GroupsAsync() { IEnumerable groups = await _ldap.ListGroupsAsync(); return View(new GroupsIndexViewModel(groups)); } [HttpPost("Login")] public async Task Login(string username, string password) { var authenticationResult = await _ldap.AuthenticateUser(username, password); if (authenticationResult.Success) { List claims = [ new(ClaimTypes.Name, username) ]; HashSet roles = []; foreach (string groupCn in authenticationResult.UserModel?.Description?.Groups ?? []) { GroupModel group = await _ldap.GetGroupByCnAsync(groupCn, _ldap.GroupsAttributes); foreach (GroupPermission permission in group.Permissions) { roles.Add(permission.ToString()); } } foreach (string role in roles) { claims.Add(new(ClaimTypes.Role, role)); } var claimsIdentity = new ClaimsIdentity( claims, CookieAuthenticationDefaults.AuthenticationScheme); var authProperties = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(300) }; await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties); return RedirectToAction("Index", "Home"); } Response.StatusCode = 500; switch (authenticationResult.AuthenticationState) { case UserNotAuthenticatedReason.InvalidCredentials: return View(new LoginViewModel() { ErrorText = "Invalid login credentials" }); case UserNotAuthenticatedReason.UserLockedOut: return View(new LoginViewModel() { ErrorText = "Your account has been locked. Wait a few minutes or ask an administrator to unlock you" }); case UserNotAuthenticatedReason.UserNotAuthorized: return View(new LoginViewModel() { ErrorText = "You are not authorized for login. Ask an administrator to authorize you." }); default: await HttpContext.RaiseError(new HellFrozeOverException()); return View(new LoginViewModel() { ErrorText = "Hell froze over. Make a screenshot and send it to an administrator." }); } } [HttpGet("Login")] public ActionResult Login() { return View(new LoginViewModel()); } [HttpGet("Logout")] public ActionResult Logout() { HttpContext.SignOutAsync(); return RedirectToAction("Index", "Home"); } [HttpGet("Accessibility")] public ActionResult Accessibility() { return View(); } [HttpGet("AccessDenied")] public ActionResult AccessDenied() { return View(); } [Authorize] [HttpGet("RemainingTime")] public async Task GetRemainingSessionTime() { var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme); if (!result.Succeeded || result.Properties?.ExpiresUtc == null) return Json(new { remainingMinutes = 0 }); var remaining = result.Properties.ExpiresUtc.Value - DateTimeOffset.UtcNow; return Json(new { remainingMinutes = (int) Math.Ceiling(remaining.TotalMinutes) }); } }