From 4e25410d309b8eb5e40773243604278c1b39e0ac Mon Sep 17 00:00:00 2001 From: Garrritt McCune Date: Tue, 12 Jan 2021 20:12:38 -0600 Subject: [PATCH] Updated the password validation and created a username validation function. --- .vs/SecureCore/v16/.suo | Bin 67584 -> 67584 bytes SecureCore/Authentication/PasswordManager.cs | 13 ++++++++++-- SecureCore/Controllers/AuthController.cs | 20 ++++++++++++++++--- SecureCore/Services/UserDataService.cs | 19 ++++++++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/.vs/SecureCore/v16/.suo b/.vs/SecureCore/v16/.suo index d785088e1fa74d3a1251c392b5633ad8c0ae1dc3..342ce739cbb713d7c1be19a57e9606831757587c 100644 GIT binary patch delta 4585 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 Cb=T7X delta 5399 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 MaxPasswordLength) return (false, $"Password length exceeds {MaxPasswordLength} characters."); + var saltBytes = Convert.FromBase64String(salt); - return passwordHash == GetHash(password, saltBytes); + if (passwordHash == GetHash(password, saltBytes)) + return (true, string.Empty); + else + return (false, string.Empty); } public static (string PasswordHash, string SaltHash) GetUserPasswordHash(int userId) diff --git a/SecureCore/Controllers/AuthController.cs b/SecureCore/Controllers/AuthController.cs index 478974c..fbbd3b0 100644 --- a/SecureCore/Controllers/AuthController.cs +++ b/SecureCore/Controllers/AuthController.cs @@ -14,6 +14,7 @@ namespace SecureCore.Controllers [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) @@ -21,6 +22,11 @@ namespace SecureCore.Controllers //NOTE: password length should be at most 64 - 128 characters long. //Very the user has login data. //if (!UserDataService.UserHasLoginData(info.UserName)) return Unauthorized("User doesn't have login creds"); + if (info.Password.Length > PasswordManager.MaxPasswordLength) return Unauthorized($"Password exceeds maxium length of {PasswordManager.MaxPasswordLength} characters."); + + var result = UserDataService.UserNameIsValid(info.UserName); + + if (!result.IsValid) return Unauthorized(result.Message); if (HttpContext.Request.Cookies.ContainsKey("Session")) { @@ -31,8 +37,9 @@ namespace SecureCore.Controllers var (password, salt) = UserDataService.GetUserPasswordHash(info.UserName); var agent = HttpContext.Request.Headers[Microsoft.Net.Http.Headers.HeaderNames.UserAgent]; var ip = PasswordManager.HashStringData(Request.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString(), salt); + result = PasswordManager.PasswordIsValid(info.Password, salt, password); - if (PasswordManager.PasswordIsValid(info.Password, salt, password)) + if (result.IsValid) { var session = new SessionManager(); @@ -89,14 +96,21 @@ namespace SecureCore.Controllers //[AcceptVerbs("GET")] public IActionResult ResetPassword([FromQuery] string token) { - if (!UserDataService.IsResetTokenValid(token)) return Unauthorized("Token invalid"); + try + { + if (!UserDataService.IsResetTokenValid(token)) return Unauthorized("Token invalid"); + } + catch (Exception e) + { + + } return Ok("Done"); } [HttpPost("CreatePasswordResetLink")] [AcceptVerbs("POST")] - public IActionResult CreatePasswordResetLink([FromBody] string userName) + public IActionResult CreatePasswordResetLink([FromBody] string userName) //TODO: this sig should only accept an email, so the link can be sent there. { var sessionManager = new SessionManager(); var token = sessionManager.CreateSessionToken(); diff --git a/SecureCore/Services/UserDataService.cs b/SecureCore/Services/UserDataService.cs index 8e15c01..3a54b1e 100644 --- a/SecureCore/Services/UserDataService.cs +++ b/SecureCore/Services/UserDataService.cs @@ -10,8 +10,27 @@ namespace SecureCore.Services { public static class UserDataService { + // + public static int UserNameMaxLength { get; } = 64; + private static string ConnectionString = @"Server=DESKTOP-OEDDVKC\SQLEXPRESS;Database=main;Integrated Security=true;"; + public static (bool IsValid, string Message) UserNameIsValid(string userName) + { + if (userName.Length > UserNameMaxLength) return (false, $"Username to long, must not exceed {UserNameMaxLength} characters."); + + var invalidChars = new List(); + + foreach(var c in userName) + { + if (char.IsPunctuation(c) || char.IsSymbol(c) || char.IsControl(c) || char.IsSeparator(c) || char.IsWhiteSpace(c)) invalidChars.Add(c);//return (false, $"The character '{c}' is not allowed."); + } + + if (invalidChars.Count > 0) return (false, $"The characters '{string.Join(",", invalidChars)}' are not allowed in a user name."); + + return (true, string.Empty); + } + public static (string PasswordHash, string SaltHash) GetUserPasswordHash(string userName) { var userId = GetUserId(userName);