using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication; using System.Security.Claims; using Microsoft.AspNetCore.Mvc; using DigitalData.UserManager.Application.Contracts; using DigitalData.UserManager.Application.DTOs.User; using Microsoft.AspNetCore.Authorization; using DigitalData.UserManager.Application; using DigitalData.Core.Abstractions.Application; using Microsoft.Extensions.Localization; using DigitalData.Core.DTO; using WorkFlow.API.Models; using WorkFlow.API.Attributes; namespace WorkFlow.API.Controllers { //TODO: implement up-to-date AuthController in UserManager [APIKeyAuth] [Route("api/[controller]")] [ApiController] public class AuthController(IUserService userService, IDirectorySearchService dirSearchService, IStringLocalizer localizer, ILogger logger) : ControllerBase { [AllowAnonymous] [HttpGet("check")] public IActionResult CheckAuthentication() { try { return Ok(User.Identity?.IsAuthenticated ?? false); } catch(Exception ex) { logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } [NonAction] public async Task Login(UserReadDto user) { // Create claimsIdentity var claimsIdentity = new ClaimsIdentity(user.ToClaimList(), CookieAuthenticationDefaults.AuthenticationScheme); // Create authProperties var authProperties = new AuthenticationProperties { IsPersistent = true, AllowRefresh = true, ExpiresUtc = DateTime.UtcNow.AddMinutes(60) }; // Sign in await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties); return Ok(); } [AllowAnonymous] [HttpPost("login")] public async Task Login([FromBody] Login login) { try { return dirSearchService.ValidateCredentials(login.Username, login.Password) ? await userService.ReadByUsernameAsync(login.Username).ThenAsync( SuccessAsync: Login, Fail: IActionResult (msg, ntc) => { logger.LogNotice(ntc); logger.LogError("User could not be found, although verified by directory-search-service. It needs to be imported by UserManager. User name is {username}.", login.Username); return StatusCode(StatusCodes.Status500InternalServerError); }) : Unauthorized(localizer[WFKey.UserNotFoundOrWrongPassword].Value); } catch(Exception ex) { logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } [AllowAnonymous] [HttpPost("login/{id}")] public async Task LoginById([FromRoute] int id, [FromQuery] string password) { try { return await userService.ReadByIdAsync(id).ThenAsync( SuccessAsync: async user => dirSearchService.ValidateCredentials(user.Username, password) ? await Login(user) : Unauthorized(localizer[WFKey.WrongPassword].Value), Fail: (msg, ntc) => { if (ntc.HasFlag(Flag.NotFound)) return Unauthorized(Key.UserNotFound); logger.LogNotice(ntc); return StatusCode(StatusCodes.Status500InternalServerError); }); } catch (Exception ex) { logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } [Authorize] [HttpGet("user")] public async Task GetUserWithClaims() { try { // Extract the username from the Name claim. string? username = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value; if (string.IsNullOrEmpty(username)) return Unauthorized(); return await userService.ReadByUsernameAsync(username) .ThenAsync(Ok, IActionResult (m, n) => { logger.LogNotice(n); return NotFound(Result.Fail().Message(localizer[Key.UserNotFound].Value)); }); } catch (Exception ex) { logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } [Authorize] [HttpPost("logout")] public async Task Logout() { try { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return Ok(); } catch(Exception ex) { logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } } }