From e03610e390c572a73de5673785baaf9240498ce2 Mon Sep 17 00:00:00 2001 From: Garrritt McCune Date: Sun, 3 Jan 2021 22:09:36 -0600 Subject: [PATCH] Started to try and organize all the authentication code. --- .vs/SecureCore/v16/.suo | Bin 38400 -> 60416 bytes SecureCore/Authentication.cs | 67 ------------------ SecureCore/Authentication/ByteGenerator.cs | 13 ++++ SecureCore/Authentication/PasswordManager.cs | 57 +++++++++++++++ SecureCore/Authentication/SessionManager.cs | 19 +++++ SecureCore/Authentication/Settings.cs | 13 ++++ SecureCore/Controllers/AuthController.cs | 30 ++++++-- SecureCore/Controllers/EmployeeController.cs | 19 +++-- SecureCore/Program.cs | 7 -- SecureCore/Services/UserDataService.cs | 34 +++++++++ SecureCore/Startup.cs | 1 - SecureCore/appsettings.json | 3 +- .../SecureCore.csproj.CoreCompileInputs.cache | 2 +- .../SecureCore.csprojAssemblyReference.cache | Bin 424 -> 424 bytes .../obj/Debug/netcoreapp3.1/SecureCore.dll | Bin 17920 -> 18944 bytes .../obj/Debug/netcoreapp3.1/SecureCore.pdb | Bin 23228 -> 24148 bytes 16 files changed, 174 insertions(+), 91 deletions(-) delete mode 100644 SecureCore/Authentication.cs create mode 100644 SecureCore/Authentication/ByteGenerator.cs create mode 100644 SecureCore/Authentication/PasswordManager.cs create mode 100644 SecureCore/Authentication/SessionManager.cs create mode 100644 SecureCore/Authentication/Settings.cs diff --git a/.vs/SecureCore/v16/.suo b/.vs/SecureCore/v16/.suo index d6d28df2ee73c463819c3ae5ebe2dbc9a2819ce4..4fe6fcb823ba1e32953e34109edd23f9c350b821 100644 GIT binary patch delta 5932 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 diff --git a/SecureCore/Authentication.cs b/SecureCore/Authentication.cs deleted file mode 100644 index 19b29fb..0000000 --- a/SecureCore/Authentication.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using Microsoft.AspNetCore.Http; -using System.Security.Cryptography; -using Microsoft.AspNetCore.Cryptography.KeyDerivation; -using SecureCore.Services; - -namespace SecureCore -{ - public class Authentication - { - private static int Iterations { get; set; } = 100000; - private static KeyDerivationPrf KeyType { get; } = KeyDerivationPrf.HMACSHA512; - private static int KeySize { get; } = 512 / 8; - private static int SaltSize { get; } = 128 / 8; //128 bit salt - private static int SessionKeySize { get; } = 32; //32 bytes - - public static string CreateSessionToken() - { - var token = new byte[SessionKeySize]; - - GetRandomBytes(ref token); - - return Convert.ToBase64String(token); - } - - public static (string Hash, string Salt) HashPassword(string password) - { - var salt = new byte[SaltSize]; - - GetRandomBytes(ref salt); - - return (GetPasswordHash(password, salt), Convert.ToBase64String(salt)); - } - - public static bool PasswordIsValid(string password, string salt, string passwordHash) - { - var saltBytes = Convert.FromBase64String(salt); - - return passwordHash == GetPasswordHash(password, saltBytes); - } - - public static bool IsAllowed(HttpContext context) - { - if (!context.Request.Cookies.ContainsKey("Session")) return false; - - return UserDataService.IsSessionTokenValid(context.Request.Cookies["Session"]); - } - - private static string GetPasswordHash(string password, byte[] salt) - { - return Convert.ToBase64String(KeyDerivation.Pbkdf2(password, salt, KeyType, Iterations, KeySize)); - } - - private static void GetRandomBytes(ref byte[] bytes) - { - using var rng = RandomNumberGenerator.Create(); - rng.GetBytes(bytes); - } - } - - public class LoginInfo - { - public string UserName { get; set; } - public string Password { get; set; } - public string Email { get; set; } - } -} diff --git a/SecureCore/Authentication/ByteGenerator.cs b/SecureCore/Authentication/ByteGenerator.cs new file mode 100644 index 0000000..56044ea --- /dev/null +++ b/SecureCore/Authentication/ByteGenerator.cs @@ -0,0 +1,13 @@ +using System.Security.Cryptography; + +namespace SecureCore.Authentication +{ + public static class ByteGenerator + { + public static void GetRandomBytes(ref byte[] bytes) + { + using var rng = RandomNumberGenerator.Create(); + rng.GetBytes(bytes); + } + } +} diff --git a/SecureCore/Authentication/PasswordManager.cs b/SecureCore/Authentication/PasswordManager.cs new file mode 100644 index 0000000..9200720 --- /dev/null +++ b/SecureCore/Authentication/PasswordManager.cs @@ -0,0 +1,57 @@ +using System; +using System.Data.SqlClient; +using Microsoft.AspNetCore.Cryptography.KeyDerivation; + +namespace SecureCore.Authentication +{ + public class PasswordManager + { + private static string ConnectionString = @"Server=DESKTOP-OEDDVKC\SQLEXPRESS;Database=main;Integrated Security=true;"; + + public PasswordManager() + { + } + + public static (string Hash, string Salt) HashPassword(string password) + { + var salt = new byte[Settings.SaltSize]; + + ByteGenerator.GetRandomBytes(ref salt); + + return (GetPasswordHash(password, salt), Convert.ToBase64String(salt)); + } + + public static bool PasswordIsValid(string password, string salt, string passwordHash) + { + var saltBytes = Convert.FromBase64String(salt); + + return passwordHash == GetPasswordHash(password, saltBytes); + } + + public static (string PasswordHash, string SaltHash) GetUserPasswordHash(int userId) + { + using (var connection = new SqlConnection(ConnectionString)) + { + using (var command = new SqlCommand("SELECT [Password Hash], [Salt Hash] FROM Login WHERE [User Key] = @UserId", connection)) + { + command.Parameters.AddWithValue("UserId", userId); + + connection.Open(); + + var reader = command.ExecuteReader(); + + if (!reader.HasRows) throw new MissingFieldException("No login records exist for this user."); + + reader.Read(); + + return (reader["Password Hash"].ToString(), reader["Salt Hash"].ToString()); + } + } + } + + private static string GetPasswordHash(string password, byte[] salt) + { + return Convert.ToBase64String(KeyDerivation.Pbkdf2(password, salt, Settings.KeyType, Settings.Iterations, Settings.KeySize)); + } + } +} diff --git a/SecureCore/Authentication/SessionManager.cs b/SecureCore/Authentication/SessionManager.cs new file mode 100644 index 0000000..5009182 --- /dev/null +++ b/SecureCore/Authentication/SessionManager.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace SecureCore.Authentication +{ + public class SessionManager + { + public static string CreateSessionToken() + { + var token = new byte[Settings.SessionKeySize]; + + ByteGenerator.GetRandomBytes(ref token); + + return Convert.ToBase64String(token); + } + } +} diff --git a/SecureCore/Authentication/Settings.cs b/SecureCore/Authentication/Settings.cs new file mode 100644 index 0000000..bb3ce7b --- /dev/null +++ b/SecureCore/Authentication/Settings.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Cryptography.KeyDerivation; + +namespace SecureCore.Authentication +{ + public static class Settings + { + public static int Iterations { get; } = 100000; + public static KeyDerivationPrf KeyType { get; } = KeyDerivationPrf.HMACSHA512; + public static int KeySize { get; } = 512 / 8; + public static int SaltSize { get; } = 128 / 8; //128 bit salt + public static int SessionKeySize { get; } = 32; //32 bytes + } +} diff --git a/SecureCore/Controllers/AuthController.cs b/SecureCore/Controllers/AuthController.cs index 7f6ea92..b1b4bda 100644 --- a/SecureCore/Controllers/AuthController.cs +++ b/SecureCore/Controllers/AuthController.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using SecureCore.Services; +using SecureCore.Authentication; namespace SecureCore.Controllers { @@ -17,9 +18,12 @@ namespace SecureCore.Controllers [AcceptVerbs("POST")] public IActionResult Login(LoginInfo info) { + //Very the user has login data. + if (!UserDataService.UserHasLoginData(info.UserName)) return Unauthorized("User doesn't have login creds"); + var (password, saltHash) = UserDataService.GetUserPasswordHash(info.UserName); - if (Authentication.PasswordIsValid(info.Password, saltHash, password)) + if (PasswordManager.PasswordIsValid(info.Password, saltHash, password)) { if (HttpContext.Request.Cookies.ContainsKey("Session")) { @@ -27,7 +31,7 @@ namespace SecureCore.Controllers return Ok($"Session is live{Environment.NewLine}"); } - var sessionToken = Authentication.CreateSessionToken(); + var sessionToken = SessionManager.CreateSessionToken(); UserDataService.SetUserSessionToken(UserDataService.GetUserId(info.UserName), sessionToken, DateTime.Now.AddDays(7)); @@ -45,8 +49,8 @@ namespace SecureCore.Controllers [AcceptVerbs("POST")] public IActionResult Register(LoginInfo info) { - var (hash, salt) = Authentication.HashPassword(info.Password); - var sessionToken = Authentication.CreateSessionToken(); + var (hash, salt) = PasswordManager.HashPassword(info.Password); + var sessionToken = SessionManager.CreateSessionToken(); try { @@ -62,6 +66,17 @@ namespace SecureCore.Controllers } } + [HttpPost("Logout")] + [AcceptVerbs("POST")] + public IActionResult Logout(LoginInfo info) + { + UserDataService.DestorySession(HttpContext.Request.Cookies["Session"]); + + HttpContext.Response.Cookies.Delete("Session"); + + return Ok(); + } + private CookieOptions GetCookieOptions() { return new CookieOptions @@ -76,6 +91,13 @@ namespace SecureCore.Controllers } } + 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 } diff --git a/SecureCore/Controllers/EmployeeController.cs b/SecureCore/Controllers/EmployeeController.cs index 3189e55..8759034 100644 --- a/SecureCore/Controllers/EmployeeController.cs +++ b/SecureCore/Controllers/EmployeeController.cs @@ -5,8 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using SecureCore.Services; -using System.Security.Cryptography; -using Microsoft.AspNetCore.Cryptography.KeyDerivation; +using SecureCore.Authentication; namespace SecureCore.Controllers { @@ -25,19 +24,19 @@ namespace SecureCore.Controllers [HttpGet] public IActionResult Get() { - if (Authentication.IsAllowed(HttpContext)) - return Ok(DataService.Get()); - else - return Unauthorized(); + //if (Authentication.IsAllowed(HttpContext)) + return Ok(DataService.Get()); + //else + // return Unauthorized(); } [HttpGet("{id}", Name = "Get")] public IActionResult Get(int id) { - if (Authentication.IsAllowed(HttpContext)) - return Ok(DataService.GetById(id)); - else - return Unauthorized(); + //if (Authentication.IsAllowed(HttpContext)) + return Ok(DataService.GetById(id)); + //else + // return Unauthorized(); } } diff --git a/SecureCore/Program.cs b/SecureCore/Program.cs index 8739c1c..39079a5 100644 --- a/SecureCore/Program.cs +++ b/SecureCore/Program.cs @@ -13,16 +13,9 @@ namespace SecureCore { public static void Main(string[] args) { - //CreateHostBuilder(args).Build().Run(); CreateWebHostBuilder(args).Run(); } - //public static IHostBuilder CreateHostBuilder(string[] args) => - // Host.CreateDefaultBuilder(args) - // .ConfigureWebHostDefaults(webBuilder => - // { - // webBuilder.UseStartup(); - // }); public static IWebHost CreateWebHostBuilder(string[] args) { return new WebHostBuilder().UseKestrel().UseContentRoot(Directory.GetCurrentDirectory()).UseUrls("http://*:5000").UseIISIntegration().UseStartup().Build(); diff --git a/SecureCore/Services/UserDataService.cs b/SecureCore/Services/UserDataService.cs index b35b4a2..0db4dcf 100644 --- a/SecureCore/Services/UserDataService.cs +++ b/SecureCore/Services/UserDataService.cs @@ -33,6 +33,25 @@ namespace SecureCore.Services } } + public static bool UserHasLoginData(string userName) + { + var userId = GetUserId(userName); + + using (var connection = new SqlConnection(ConnectionString)) + { + using (var command = new SqlCommand("SELECT [Password Hash], [Salt Hash] FROM Login WHERE [User Key] = @UserId", connection)) + { + command.Parameters.AddWithValue("UserId", userId); + + connection.Open(); + + var reader = command.ExecuteReader(); + + return reader.HasRows; + } + } + } + public static int GetUserId(string userName) { using (var connection = new SqlConnection(ConnectionString)) @@ -121,5 +140,20 @@ namespace SecureCore.Services } } } + + public static void DestorySession(string sessionToken) + { + using (var connection = new SqlConnection(ConnectionString)) + { + using (var command = new SqlCommand("DELETE FROM [Session] WHERE [Session Token] = @SessionToken", connection)) + { + command.Parameters.AddWithValue("SessionToken", sessionToken); + + connection.Open(); + + command.ExecuteNonQuery(); + } + } + } } } diff --git a/SecureCore/Startup.cs b/SecureCore/Startup.cs index 6144ea4..b0fbc97 100644 --- a/SecureCore/Startup.cs +++ b/SecureCore/Startup.cs @@ -28,7 +28,6 @@ namespace SecureCore { services.AddTransient(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Latest); - //services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/SecureCore/appsettings.json b/SecureCore/appsettings.json index d9d9a9b..e77600c 100644 --- a/SecureCore/appsettings.json +++ b/SecureCore/appsettings.json @@ -6,5 +6,6 @@ "Microsoft.Hosting.Lifetime": "Information" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "ConnectionString": "Server=DESKTOP-OEDDVKC\\SQLEXPRESS;Database=main;Integrated Security=true;" } diff --git a/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.csproj.CoreCompileInputs.cache b/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.csproj.CoreCompileInputs.cache index 0771db9..20b0a63 100644 --- a/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.csproj.CoreCompileInputs.cache +++ b/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -4d9579093cc42096d4f65291f56f6cb3edc17317 +390c9f5585bc7dcf8f0c5f65f443d23f17063571 diff --git a/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.csprojAssemblyReference.cache b/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.csprojAssemblyReference.cache index bd1b30cc891802ff5e893bf14348aacda4f3677a..c26662d4c401df88f9a58f71514689daa52affdf 100644 GIT binary patch delta 14 VcmZ3%yn=ayKO@s2^~r&Z;Q%BG1bzSj delta 14 VcmZ3%yn=ayKO@r?naP2S;Q%9l1Z4mK diff --git a/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.dll b/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.dll index a279d83de68189d6809cd5e11a348838c08ef0c0..97e1b270071ec4bd368e512a17486d2471e16682 100644 GIT binary patch delta 9023 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 U^V$7kWtw2OSjL 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 delta 3740 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