using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using RdtClient.Data.Enums;
using RdtClient.Service.Services;
using System.ComponentModel.DataAnnotations;
namespace RdtClient.Web.Controllers;
///
/// Handles authentication and user management operations
///
[Route("Api/Authentication")]
public class AuthController(Authentication authentication, Settings settings) : Controller
{
///
/// Checks if the current session is authenticated
///
/// Session is valid and authenticated, or authentication is disabled
/// System requires initial setup - no users exist in the database
/// Session is not authenticated
[AllowAnonymous]
[Route("IsLoggedIn")]
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status402PaymentRequired, Type = typeof(ProblemDetails))]
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(ProblemDetails))]
public async Task IsLoggedIn()
{
if (Settings.Get.General.AuthenticationType == AuthenticationType.None)
{
return Ok();
}
if (User.Identity?.IsAuthenticated == false)
{
var user = await authentication.GetUser();
if (user == null)
{
return Problem(detail: "Setup required", statusCode: StatusCodes.Status402PaymentRequired);
}
return Problem(detail: "Login required", statusCode: StatusCodes.Status403Forbidden);
}
return Ok();
}
///
/// Creates the initial account for the system
///
///
/// This endpoint can only be used when no account exists.
/// It creates the account and automatically logs in.
///
/// Registration details for the new account
/// Account created successfully and user is logged in
/// Invalid request - username/password missing or validation failed
/// Cannot create account - a user already exists in system
[AllowAnonymous]
[Route("Create")]
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(ProblemDetails))]
public async Task Create([FromBody] AuthControllerLoginRequest? request)
{
if (request == null)
{
return BadRequest();
}
var user = await authentication.GetUser();
if (user != null)
{
return Problem(detail: "User already exists - only one user allowed", statusCode: StatusCodes.Status401Unauthorized);
}
if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password))
{
return Problem(detail: "Empty UserName or Password", statusCode: StatusCodes.Status400BadRequest);
}
var registerResult = await authentication.Register(request.UserName, request.Password);
if (!registerResult.Succeeded)
{
return Problem(detail: registerResult.Errors.First().Description, statusCode: StatusCodes.Status400BadRequest);
}
await authentication.Login(request.UserName, request.Password);
return Ok();
}
///
/// Configures the provider settings for the application
///
///
/// This endpoint can only be used when no provider is configured.
/// It sets up the initial provider configuration including the API key.
///
/// Provider configuration details including provider type and API token
/// Provider configured successfully
/// Invalid request - missing required fields
/// Provider already configured
[AllowAnonymous]
[Route("SetupProvider")]
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task SetupProvider([FromBody] AuthControllerSetupProviderRequest? request)
{
if (request == null)
{
return BadRequest();
}
if (!String.IsNullOrEmpty(Settings.Get.Provider.ApiKey))
{
return StatusCode(401);
}
var user = await authentication.GetUser();
if (user != null)
{
return StatusCode(401);
}
await settings.Update("Provider:Provider", request.Provider);
await settings.Update("Provider:ApiKey", request.Token);
return Ok();
}
///
/// Authenticates a user and creates a new session
///
///
/// Validates the provided credentials and creates an authenticated session if valid.
///
/// Login credentials
/// Authentication successful
/// Invalid credentials or missing required fields
/// System requires initial setup - no users exist
[AllowAnonymous]
[Route("Login")]
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
[ProducesResponseType(StatusCodes.Status402PaymentRequired, Type = typeof(ProblemDetails))]
public async Task> Login([FromBody] AuthControllerLoginRequest? request)
{
if (request == null)
{
return BadRequest();
}
var user = await authentication.GetUser();
if (user == null)
{
return Problem(detail: "Setup required", statusCode: StatusCodes.Status402PaymentRequired);
}
if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password))
{
return Problem(detail: "Invalid credentials", statusCode: StatusCodes.Status400BadRequest);
}
var result = await authentication.Login(request.UserName, request.Password);
if (!result.Succeeded)
{
return Problem(detail: "Invalid credentials", statusCode: StatusCodes.Status400BadRequest);
}
return Ok();
}
///
/// Ends the current authenticated session
///
/// Session terminated successfully
[Route("Logout")]
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task Logout()
{
await authentication.Logout();
return Ok();
}
///
/// Updates the authenticated user's password
///
///
/// Requires authentication. Updates the password for the currently logged in user.
///
/// Password update request containing the new password
/// Password updated successfully
/// Invalid request or password validation failed
/// Unauthorized - user must be authenticated
[Route("Update")]
[HttpPost]
[Authorize(Policy = "AuthSetting")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task> Update([FromBody] AuthControllerUpdateRequest? request)
{
if (request == null)
{
return BadRequest();
}
if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password))
{
return Problem(detail: "Invalid UserName or Password", statusCode: StatusCodes.Status400BadRequest);
}
var updateResult = await authentication.Update(request.UserName, request.Password);
if (!updateResult.Succeeded)
{
return Problem(detail: updateResult.Errors.First().Description, statusCode: StatusCodes.Status400BadRequest);
}
return Ok();
}
}
///
/// Request model for login and user creation operations
///
public class AuthControllerLoginRequest
{
///
/// Username for authentication
///
/// admin
[Required]
public String? UserName { get; set; }
///
/// Password for authentication
///
/// MySecurePassword123!
[Required]
public String? Password { get; set; }
}
///
/// Request model for configuring the provider settings
///
public class AuthControllerSetupProviderRequest
{
///
/// Provider type identifier
///
/// 1
[Required]
public Int32 Provider { get; set; }
///
/// API token or key for the provider
///
/// sk-1234567890abcdef
[Required]
public String? Token { get; set; }
}
///
/// Request model for updating user password
///
public class AuthControllerUpdateRequest
{
///
/// Username for the account
///
/// myusername
[Required]
public String? UserName { get; set; }
///
/// New password for the user account
///
/// NewSecurePassword123!
[Required]
public String? Password { get; set; }
}