using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; using Suspectus.Gandalf.Core.Abstractions.CQRS.Commands; using Suspectus.Gandalf.Core.Abstractions.DTOs.Internal.Auth; using Suspectus.Gandalf.Core.Abstractions.Extensions; using Suspectus.Gandalf.Palantir.Client; namespace Suspectus.Gandalf.Bridgekeeper.Api.Controllers; [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly IPalantirClient _client; private readonly IDistributedCache _tokenCache; public AuthController(IPalantirClient client, IDistributedCache tokenCache) { _client = client; _tokenCache = tokenCache; } [HttpGet("[action]")] public async Task Check() { return Ok(true); } [HttpPost("[action]")] public async Task Login([FromBody] ValidateCredentialsCommand validateCredentialsCommand, [FromQuery] string? clientId, CancellationToken cancellationToken) { if (clientId is null) { var masterAppInfoResponse = await _client.Internal.App.GetMasterInfo(); if (masterAppInfoResponse.IsFaulted) { return BadRequest($"Failed to retrieve master app info."); } clientId = masterAppInfoResponse.GetValue().Id; } var tokenRequestCommandResponse = await _client.Internal.Auth.Token(new TokenRequestCommand { Password = validateCredentialsCommand.Password, Username = validateCredentialsCommand.UsernameOrEmail, GrandType = GrandType.Password, ClientId = clientId }); if (tokenRequestCommandResponse.IsFaulted) { return tokenRequestCommandResponse.Match( BadRequest, e => BadRequest($"{e.Message}\n{e.InnerException?.Message}") ); } var tokenRequestResponse = tokenRequestCommandResponse.GetValue(); if (tokenRequestResponse is null) { return BadRequest("Invalid username or password."); } await _tokenCache.SetStringAsync( GetCacheKey(tokenRequestResponse.SubjectId, clientId, "access_token"), tokenRequestResponse.AccessToken, new DistributedCacheEntryOptions { AbsoluteExpiration = tokenRequestResponse.AccessTokenExpiresAt.AddSeconds(-10), }, cancellationToken ); await _tokenCache.SetStringAsync( GetCacheKey(tokenRequestResponse.SubjectId, clientId, "refresh_token"), tokenRequestResponse.RefreshToken, new DistributedCacheEntryOptions { AbsoluteExpiration = tokenRequestResponse.RefreshTokenExpiresAt.AddSeconds(-10), }, cancellationToken ); Response.Cookies.Append("MithrandirSession", tokenRequestResponse.SubjectId, new CookieOptions { Secure = true, HttpOnly = true, SameSite = SameSiteMode.Lax, Expires = tokenRequestResponse.RefreshTokenExpiresAt.AddSeconds(-10) }); return Ok(); } [HttpGet("[action]")] public async Task Logout() { Response.Cookies.Delete("MithrandirSession"); return Ok(); } [HttpPost("[action]")] public async Task Register() { return Ok(true); } private string GetCacheKey(string subjectId, string appId, string tokenType) { return $"{subjectId}:{appId}:{tokenType}"; } }