Files
secure-core/SecureCore/Controllers/AuthController.cs
T

181 lines
7.8 KiB
C#

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using System;
using System.Web;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Threading.Tasks;
using SecureCore.Services;
using SecureCore.Authentication;
namespace SecureCore.Controllers
{
[Route("[controller]")]
[ApiController]
public class AuthController : Controller
{
//TODO: Login will only ever return messages like "Wrong username / password." whereas register can return messages like "User exists.", "Password to weak", or "Password in top 100 most used.".
[HttpPost("login")]
[AcceptVerbs("POST")]
public IActionResult Login([FromBody] LoginInfo info)
{
AppSettingsManager.TryGetConnectionStringByName("MainDataConnectionString", out string connectionString);
//TODO: see if the request has an active session key so we don't spam out new keys like mad
try
{
if (HttpContext.Request.Cookies.ContainsKey("Session"))
if (SessionManager.IsSessionTokenValid(HttpContext.Request.Cookies["Session"], connectionString))
return Ok("Logged in\n");
//Verify that the username provided is valid, i.e. no whitespace, special characters, etc.
var result = UserDataService.IsUsernameValid(info.UserName);
//If the name isn't valid, return the error message to the user.
if (!result.IsValid) return Unauthorized(result.Message);
//Next try to get the user's login data, if the fuction returns empty strings, then the user isn't a registered name.
var (password, salt) = PasswordManager.GetPasswordHashAndSalt(info.UserName, connectionString);
//If the user name isn't in the system, then simply return a generic error message about something not being right.
if (password == string.Empty) return Unauthorized("User name or password is not correct.");
result = PasswordManager.IsPasswordValid(info.Password);
if (!result.IsValid) return Unauthorized(result.Message);
if(!PasswordManager.IsPasswordAMatch(info.Password, salt, password)) return Unauthorized("User name or password is not correct.");
var sessionToken = SessionManager.CreateSessionToken();
var agent = HttpContext.Request.Headers[Microsoft.Net.Http.Headers.HeaderNames.UserAgent];
var ip = PasswordManager.HashStringData(Request.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString(), salt);
var cookieOptions = GetCookieOptions();
SessionManager.Login(info.UserName, sessionToken, cookieOptions.Expires.Value.UtcDateTime, agent, ip, connectionString);
HttpContext.Response.Cookies.Append("Session", sessionToken, cookieOptions);
return Ok($"Logged in success{Environment.NewLine}");
}
catch(Exception ex)
{
//TODO: Log this event.
return Unauthorized("An error has occured trying to process your request, please try again in a few minutes.");
}
}
[HttpPost("Register")]
[AcceptVerbs("POST")]
public IActionResult Register([FromBody] LoginInfo info)
{
//Verify that the username provided is valid, i.e. no whitespace, special characters, etc.
var result = UserDataService.IsUsernameValid(info.UserName);
//If the name isn't valid, return the error message to the user.
if (!result.IsValid) return Unauthorized(result.Message);
//Validate the password, make sure its not to long or short, etc.
result = PasswordManager.IsPasswordValid(info.Password);
if (!result.IsValid) return Unauthorized(result.Message);
AppSettingsManager.TryGetConnectionStringByName("MainDataConnectionString", out string connectionString);
var (hash, salt) = PasswordManager.HashPassword(info.Password);
var sessionToken = SessionManager.CreateSessionToken();
var agent = HttpContext.Request.Headers[Microsoft.Net.Http.Headers.HeaderNames.UserAgent];
var ip = PasswordManager.HashStringData(Request.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString(), salt);
try
{
var cookieOptions = GetCookieOptions();
var i = UserDataService.RegisterNewUser(info.UserName, info.Email, hash, salt, sessionToken, cookieOptions.Expires.Value.UtcDateTime, agent, ip, connectionString);
HttpContext.Response.Cookies.Append("Session", sessionToken, cookieOptions);
return Ok($"New User ID: {i}");
}
catch (Exception e)
{
return Unauthorized(e.Message);
}
}
[HttpPost("Logout")]
[AcceptVerbs("POST")]
public IActionResult Logout()
{
AppSettingsManager.TryGetConnectionStringByName("MainDataConnectionString", out string connectionString);
SessionManager.Logout(HttpContext.Request.Cookies["Session"], connectionString);
HttpContext.Response.Cookies.Delete("Session");
return Ok();
}
[HttpPost("ResetPassword")]
[AcceptVerbs("POST")]
public IActionResult ResetPassword([FromQuery] string token, [FromBody] string password)
{
AppSettingsManager.TryGetConnectionStringByName("MainDataConnectionString", out string connectionString);
try
{
if (!SessionManager.IsSessionTokenValid(token, connectionString, true)) return Unauthorized("Token invalid");
var (Hash, Salt) = PasswordManager.HashPassword(password);
PasswordManager.ResetPassword(Hash, Salt, token, connectionString);
return Ok("Reset successful\n");
}
catch (Exception e)
{
return Unauthorized(e.Message);
}
}
[HttpPost("CreatePasswordResetLink")]
[AcceptVerbs("POST")]
public IActionResult CreatePasswordResetLink([FromBody] string email) //TODO: this sig should only accept an email, so the link can be sent there.
{
AppSettingsManager.TryGetConnectionStringByName("MainDataConnectionString", out string connectionString);
var token = SessionManager.CreateSessionToken();
var agent = HttpContext.Request.Headers[Microsoft.Net.Http.Headers.HeaderNames.UserAgent];
var ip = PasswordManager.HashStringData(Request.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString());
try
{
PasswordManager.InsertPasswordResetRequest(email, token, DateTime.Now.AddHours(1), agent, ip, connectionString);
token = HttpUtility.UrlEncode(token);
return Ok($"192.168.255.200:5000/auth/ResetPassword?token={token}{Environment.NewLine}");
}
catch(Exception e)
{
return Unauthorized($"{e.Message}{Environment.NewLine}");
}
}
private CookieOptions GetCookieOptions()
{
return new CookieOptions
{
//Domain = "copyrightcrusader.org",
Expires = DateTime.Now.AddDays(7),
//HttpOnly = true,
//Secure = true,
Path = "/",
SameSite = SameSiteMode.Strict
};
}
}
public class LoginInfo
{
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
//TODO: Read more https://www.valentinog.com/blog/cookies/
// And this https://blog.webf.zone/ultimate-guide-to-http-cookies-2aa3e083dbae
}