diff --git a/.vs/SecureCore/v16/.suo b/.vs/SecureCore/v16/.suo index 21a296f..2ea9387 100644 Binary files a/.vs/SecureCore/v16/.suo and b/.vs/SecureCore/v16/.suo differ diff --git a/SecureCore/Authentication/PasswordManager.cs b/SecureCore/Authentication/PasswordManager.cs index 97c0096..5376ac9 100644 --- a/SecureCore/Authentication/PasswordManager.cs +++ b/SecureCore/Authentication/PasswordManager.cs @@ -29,20 +29,22 @@ namespace SecureCore.Authentication return (GetHash(password, salt), Convert.ToBase64String(salt)); } - public static (bool IsValid, string Message) IsPasswordValid(string password, string salt, string passwordHash) + public static (bool IsValid, string Message) IsPasswordValid(string password) { if (password.Length < MinPasswordLength) return (false, $"Your password is too short, it must be at least {MinPasswordLength} characters long and not exceed {MaxPasswordLength} characters."); if (password.Length > MaxPasswordLength) return (false, $"Your password is too long, it must not exceed {MaxPasswordLength} characters and must contain at least {MinPasswordLength} characters."); - var saltBytes = Convert.FromBase64String(salt); - - if (passwordHash == GetHash(password, saltBytes)) - return (true, string.Empty); - else - return (false, "User name or password is not correct."); + return (true, string.Empty); } - public static void InsertPasswordResetRequest(string userName, string sessionToken, DateTime expirationDate, string userAgent, string ipAddress, string connectionString) + public static bool IsPasswordAMatch(string password, string salt, string passwordHash) + { + var saltBytes = Convert.FromBase64String(salt); + + return passwordHash == GetHash(password, saltBytes); + } + + public static void InsertPasswordResetRequest(string email, string sessionToken, DateTime expirationDate, string userAgent, string ipAddress, string connectionString) { using var connection = new SqlConnection(connectionString); @@ -50,7 +52,7 @@ namespace SecureCore.Authentication command.Parameters.AddWithValue("SessionToken", sessionToken); command.Parameters.AddWithValue("ExpirationDate", expirationDate); - command.Parameters.AddWithValue("UserName", userName); + command.Parameters.AddWithValue("Email", email); command.Parameters.AddWithValue("UserAgent", userAgent); command.Parameters.AddWithValue("IpAddress", ipAddress); @@ -59,7 +61,19 @@ namespace SecureCore.Authentication command.ExecuteNonQuery(); } - //TODO: Reset Password Function Here + public static void ResetPassword(string passwordHash, string salt, string sessionToken, string connectionString) + { + using var connection = new SqlConnection(connectionString); + using var command = new SqlCommand("ResetPassword", connection) { CommandType = CommandType.StoredProcedure }; + + command.Parameters.AddWithValue("PasswordHash", passwordHash); + command.Parameters.AddWithValue("Salt", salt); + command.Parameters.AddWithValue("SessionToken", sessionToken); + + connection.Open(); + + command.ExecuteNonQuery(); + } public static (string PasswordHash, string Salt) GetPasswordHashAndSalt(string username, string connectionString) { diff --git a/SecureCore/Controllers/AuthController.cs b/SecureCore/Controllers/AuthController.cs index ac48bf4..c9676d8 100644 --- a/SecureCore/Controllers/AuthController.cs +++ b/SecureCore/Controllers/AuthController.cs @@ -23,25 +23,26 @@ namespace SecureCore.Controllers //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); - //if (HttpContext.Request.Cookies.ContainsKey("Session")) - //{ - // if(UserDataService.IsSessionTokenValid(HttpContext.Request.Cookies["Session"]))//, info.UserName)) - // return Ok($"Session is live{Environment.NewLine}"); - //} //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, salt, password); + 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); @@ -64,6 +65,15 @@ namespace SecureCore.Controllers [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(); @@ -99,9 +109,9 @@ namespace SecureCore.Controllers return Ok(); } - [HttpGet("ResetPassword")] - //[AcceptVerbs("GET")] - public IActionResult ResetPassword([FromQuery] string token) + [HttpPost("ResetPassword")] + [AcceptVerbs("POST")] + public IActionResult ResetPassword([FromQuery] string token, [FromBody] string password) { AppSettingsManager.TryGetConnectionStringByName("MainDataConnectionString", out string connectionString); @@ -109,17 +119,21 @@ namespace SecureCore.Controllers { 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); } - return Ok("Done"); } [HttpPost("CreatePasswordResetLink")] [AcceptVerbs("POST")] - public IActionResult CreatePasswordResetLink([FromBody] string userName) //TODO: this sig should only accept an email, so the link can be sent there. + 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(); @@ -128,7 +142,7 @@ namespace SecureCore.Controllers try { - PasswordManager.InsertPasswordResetRequest(userName, token, DateTime.Now.AddHours(1), agent, ip, connectionString); + PasswordManager.InsertPasswordResetRequest(email, token, DateTime.Now.AddHours(1), agent, ip, connectionString); token = HttpUtility.UrlEncode(token);