Added more validation to the various AuthController functions.
This commit is contained in:
@@ -47,7 +47,6 @@ namespace SecureCore.Authentication
|
||||
public static void InsertPasswordResetRequest(string email, string sessionToken, DateTime expirationDate, string userAgent, string ipAddress, string connectionString)
|
||||
{
|
||||
using var connection = new SqlConnection(connectionString);
|
||||
|
||||
using var command = new SqlCommand("LogPasswordResetRequest", connection) { CommandType = CommandType.StoredProcedure };
|
||||
|
||||
command.Parameters.AddWithValue("SessionToken", sessionToken);
|
||||
@@ -78,7 +77,6 @@ namespace SecureCore.Authentication
|
||||
public static (string PasswordHash, string Salt) GetPasswordHashAndSalt(string username, string connectionString)
|
||||
{
|
||||
using var connection = new SqlConnection(connectionString);
|
||||
|
||||
using var command = new SqlCommand("SELECT [Password Hash], [Salt] FROM dbo.GetUserPasswordHashAndSalt(@Username)", connection);
|
||||
|
||||
command.Parameters.AddWithValue("Username", username);
|
||||
|
||||
@@ -20,7 +20,6 @@ namespace SecureCore.Authentication
|
||||
public static bool IsSessionTokenValid(string sessionToken, string connectionString, bool isResetToken = false)
|
||||
{
|
||||
using var connection = new SqlConnection(connectionString);
|
||||
|
||||
using var command = new SqlCommand("ValidateSessionToken", connection) { CommandType = CommandType.StoredProcedure };
|
||||
|
||||
command.Parameters.AddWithValue("SessionToken", sessionToken);
|
||||
@@ -36,7 +35,6 @@ namespace SecureCore.Authentication
|
||||
public static void Logout(string sessionToken, string connectionString)
|
||||
{
|
||||
using var connection = new SqlConnection(connectionString);
|
||||
|
||||
using var command = new SqlCommand("LogoutUser", connection) { CommandType = CommandType.StoredProcedure };
|
||||
|
||||
command.Parameters.AddWithValue("SessionToken", sessionToken);
|
||||
@@ -49,7 +47,6 @@ namespace SecureCore.Authentication
|
||||
public static void Login(string userName, string sessionToken, DateTime expirationDate, string userAgent, string ipAddress, string connectionString)
|
||||
{
|
||||
using var connection = new SqlConnection(connectionString);
|
||||
|
||||
using var command = new SqlCommand("LoginUser", connection) { CommandType = CommandType.StoredProcedure };
|
||||
|
||||
command.Parameters.AddWithValue("SessionToken", sessionToken);
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace SecureCore.Controllers
|
||||
public IActionResult Login([FromBody] UserInformation.LoginData 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"))
|
||||
@@ -27,6 +27,10 @@ namespace SecureCore.Controllers
|
||||
//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);
|
||||
//Now make sure the password is valid.
|
||||
result = PasswordManager.IsPasswordValid(info.Password);
|
||||
|
||||
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.
|
||||
@@ -34,10 +38,6 @@ namespace SecureCore.Controllers
|
||||
//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();
|
||||
@@ -62,6 +62,7 @@ namespace SecureCore.Controllers
|
||||
[AcceptVerbs("POST")]
|
||||
public IActionResult Register([FromBody] UserInformation.RegistrationData info)
|
||||
{
|
||||
AppSettingsManager.TryGetConnectionStringByName("MainDataConnectionString", out string connectionString);
|
||||
//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.
|
||||
@@ -71,7 +72,12 @@ namespace SecureCore.Controllers
|
||||
|
||||
if (!result.IsValid) return Unauthorized(result.Message);
|
||||
|
||||
AppSettingsManager.TryGetConnectionStringByName("MainDataConnectionString", out string connectionString);
|
||||
result = UserDataService.IsEmailValid(info.Email);
|
||||
|
||||
if (!result.IsValid) return Unauthorized(result.Message);
|
||||
|
||||
if (UserDataService.IsEmailInUse(info.Email, connectionString)) return Unauthorized("This email is already in use.");
|
||||
|
||||
var (hash, salt) = PasswordManager.HashPassword(info.Password);
|
||||
var sessionToken = SessionManager.CreateSessionToken();
|
||||
var agent = HttpContext.Request.Headers[Microsoft.Net.Http.Headers.HeaderNames.UserAgent];
|
||||
@@ -97,9 +103,18 @@ namespace SecureCore.Controllers
|
||||
[AcceptVerbs("POST")]
|
||||
public IActionResult Logout()
|
||||
{
|
||||
if (!HttpContext.Request.Cookies.ContainsKey("Session")) return Ok();
|
||||
|
||||
AppSettingsManager.TryGetConnectionStringByName("MainDataConnectionString", out string connectionString);
|
||||
|
||||
try
|
||||
{
|
||||
SessionManager.Logout(HttpContext.Request.Cookies["Session"], connectionString);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//TODO: decide what to do here. If the SQL fails to clear the token from the database, do we want to clear the token cookie?
|
||||
}
|
||||
|
||||
HttpContext.Response.Cookies.Delete("Session");
|
||||
|
||||
@@ -114,7 +129,11 @@ namespace SecureCore.Controllers
|
||||
|
||||
try
|
||||
{
|
||||
if (!SessionManager.IsSessionTokenValid(token, connectionString, true)) return Unauthorized("Token invalid");
|
||||
if (!SessionManager.IsSessionTokenValid(token, connectionString, true)) return Unauthorized("This link has expired, please request a new email reset link.");
|
||||
|
||||
var (IsValid, Message) = PasswordManager.IsPasswordValid(password);
|
||||
|
||||
if (!IsValid) return Unauthorized(Message);
|
||||
|
||||
var (Hash, Salt) = PasswordManager.HashPassword(password);
|
||||
|
||||
@@ -133,6 +152,14 @@ namespace SecureCore.Controllers
|
||||
public IActionResult CreatePasswordResetLink([FromBody] string email)
|
||||
{
|
||||
AppSettingsManager.TryGetConnectionStringByName("MainDataConnectionString", out string connectionString);
|
||||
//Validate the email input.
|
||||
var (IsValid, Message) = UserDataService.IsEmailValid(email);
|
||||
|
||||
if (!IsValid) return Unauthorized(Message);
|
||||
|
||||
//If its a properly formatted email, then check to see if its in use by anyone.
|
||||
if (!UserDataService.IsEmailInUse(email, connectionString)) return Unauthorized("Email is not valid.");
|
||||
|
||||
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());
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace SecureCore.Services
|
||||
{
|
||||
//
|
||||
public static int UserNameMaxLength { get; } = 64;
|
||||
public static int EmailMaxLength { get; } = 512;
|
||||
|
||||
public static (bool IsValid, string Message) IsUsernameValid(string userName)
|
||||
{
|
||||
@@ -29,7 +30,6 @@ namespace SecureCore.Services
|
||||
public static int RegisterNewUser(string userName, string email, string passwordHash, string saltHash, string sessionToken, DateTime expirationDate, string userAgent, string ipAddress, string connectionString)
|
||||
{
|
||||
using var connection = new SqlConnection(connectionString);
|
||||
|
||||
using var command = new SqlCommand("RegisterNewUser", connection) { CommandType = CommandType.StoredProcedure };
|
||||
|
||||
command.Parameters.AddWithValue("UserName", userName);
|
||||
@@ -47,5 +47,36 @@ namespace SecureCore.Services
|
||||
|
||||
return Convert.ToInt32(result);
|
||||
}
|
||||
|
||||
public static bool IsEmailInUse(string email, string connectionString)
|
||||
{
|
||||
using var connection = new SqlConnection(connectionString);
|
||||
using var command = new SqlCommand("SELECT dbo.EmailInUse(@Email) AS InUse", connection);
|
||||
|
||||
command.Parameters.AddWithValue("Email", email);
|
||||
|
||||
connection.Open();
|
||||
|
||||
return Convert.ToBoolean(command.ExecuteScalar());
|
||||
}
|
||||
|
||||
public static (bool IsValid, string Message) IsEmailValid(string email)
|
||||
{
|
||||
if (email.Length > EmailMaxLength) return (false, $"Email exceeds the maximum length of {EmailMaxLength} characters.");
|
||||
|
||||
//Code taken from user "Cogwheel" on StackOverflow: https://stackoverflow.com/questions/1365407/c-sharp-code-to-validate-email-address
|
||||
try
|
||||
{
|
||||
var addr = new System.Net.Mail.MailAddress(email);
|
||||
|
||||
if (addr.Address != email) return (false, $"The provided email is not in the correct format.");
|
||||
|
||||
return (true, string.Empty);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return (false, $"The provided email is not in the correct format.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user