From d2c84966b9ed1bf43fbb861207c39d660964c6ba Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 26 Sep 2023 18:58:46 -0400 Subject: [PATCH] Refactoring and password hashing --- Controllers/PasswordVerification.cs | 42 +++++++ ...gisterController.cs => UsersController.cs} | 19 ++- Models/User.cs | 14 +++ Repositories/UserRepository.cs | 61 ---------- Repositories/UsersRepository.cs | 112 ++++++++++++++++++ 5 files changed, 182 insertions(+), 66 deletions(-) create mode 100644 Controllers/PasswordVerification.cs rename Controllers/{RegisterController.cs => UsersController.cs} (61%) delete mode 100644 Repositories/UserRepository.cs create mode 100644 Repositories/UsersRepository.cs diff --git a/Controllers/PasswordVerification.cs b/Controllers/PasswordVerification.cs new file mode 100644 index 0000000..1bee7b0 --- /dev/null +++ b/Controllers/PasswordVerification.cs @@ -0,0 +1,42 @@ +using System; +using System.Security.Cryptography; +using System.Text; + +using TextSender_API.Models; + +namespace TextSender_API.Controllers; + +public class PasswordVerification +{ + #region Fiends + private int _keySize = 64; + private int _iterations = 350000; + #endregion + + #region Constructors + #endregion + + #region Methods + public Salt CreateSalt(User user) + { + var salt = new Salt(); + salt.Key = RandomNumberGenerator.GetBytes(this._keySize); + + return salt; + } + + public string HashPassword(User user, Salt salt) + { + var hashAlgorithm = HashAlgorithmName.SHA512; + + var hash = Rfc2898DeriveBytes.Pbkdf2( + Encoding.UTF8.GetBytes(user.Password!), + salt.Key!, + this._iterations, + hashAlgorithm, + this._keySize); + + return Convert.ToHexString(hash); + } + #endregion +} \ No newline at end of file diff --git a/Controllers/RegisterController.cs b/Controllers/UsersController.cs similarity index 61% rename from Controllers/RegisterController.cs rename to Controllers/UsersController.cs index e15a45a..af82d06 100644 --- a/Controllers/RegisterController.cs +++ b/Controllers/UsersController.cs @@ -9,17 +9,17 @@ namespace TextSender_API.Controllers; [ApiController] [Route("api/v1/user")] -public class RegisterController : ControllerBase +public class UsersController : ControllerBase { #region Fields - private readonly ILogger _logger; + private readonly ILogger _logger; private IConfiguration _config; #endregion #region Constructors - public RegisterController(ILogger logger, IConfiguration config) + public UsersController(ILogger logger, IConfiguration config) { this._logger = logger; this._config = config; @@ -33,15 +33,24 @@ public class RegisterController : ControllerBase try { var connString = this._config.GetConnectionString("MongoDBURI"); - var userRepo = new UserRepository(connString); + var userRepo = new UsersRepository(connString!); + var saltRepo = new SaltRepository(connString!); var allUsers = userRepo.RetrieveAllUsers(); - var result = allUsers.Exists(ea => ea.Username.Equals(userRequest.Username)); + var result = allUsers.Exists(ea => ea.Username!.Equals(userRequest.Username)); if (!result) { + var pwdVerify = new PasswordVerification(); + var salt = pwdVerify.CreateSalt(userRequest); + var hashedPassword = pwdVerify.HashPassword(userRequest, salt); + this._logger.LogInformation("Creating user"); + userRequest.Password = hashedPassword; userRequest.DateCreated = DateTime.Now; userRepo.CreateUser(userRequest); + + salt.UserId = userRequest.Id; + saltRepo.Create(salt); } else { diff --git a/Models/User.cs b/Models/User.cs index 9889755..4dc8992 100644 --- a/Models/User.cs +++ b/Models/User.cs @@ -3,6 +3,7 @@ using System; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Conventions; +using MongoDB.Bson.Serialization.IdGenerators; using MongoDB.Driver; namespace TextSender_API.Models; @@ -27,3 +28,16 @@ public class User public DateTime? DateCreated { get; set; } #endregion } + +public class Salt +{ + #region Properties + [BsonId] + [BsonRepresentation(BsonType.ObjectId)] + public string? Id { get; set; } + [BsonElement("key")] + public byte[]? Key { get; set; } + [BsonElement("user_id")] + public string? UserId { get; set; } + #endregion +} diff --git a/Repositories/UserRepository.cs b/Repositories/UserRepository.cs deleted file mode 100644 index 03a34b4..0000000 --- a/Repositories/UserRepository.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; - -using MongoDB.Bson; -using MongoDB.Driver; - -using TextSender_API.Models; - -namespace TextSender_API.Repositories; - - -public class UserRepository -{ - #region Fields - private string _connectionString; - private string _databaseName; - private string _tableName; - private readonly IMongoCollection _bookCollection; - #endregion - - - #region Constructors - public UserRepository(string connectionString) - { - this._connectionString = connectionString; - this._databaseName = "TextSender"; - this._tableName = "Users"; - var client = this.InitializeClient(); - this._bookCollection = client.GetDatabase(this._databaseName).GetCollection(this._tableName); - } - #endregion - - #region Metods - public void CreateUser(User user) - { - this._bookCollection.InsertOne(user); - var i = 0; - } - - public List RetrieveAllUsers() - { - return this._bookCollection.Find(_ => true).ToList(); - } - - public void Update(User user) - { - var filter = Builders.Filter.Eq(u => u.Id, user.Id); - this._bookCollection.ReplaceOne(filter, user); - } - - public void Delete(User user) - { - var filter = Builders.Filter.Eq(u => u.Id, user.Id); - this._bookCollection.DeleteOne(filter); - } - - private MongoClient InitializeClient() - { - return new MongoClient(this._connectionString); - } - #endregion -} \ No newline at end of file diff --git a/Repositories/UsersRepository.cs b/Repositories/UsersRepository.cs new file mode 100644 index 0000000..fa10199 --- /dev/null +++ b/Repositories/UsersRepository.cs @@ -0,0 +1,112 @@ +using System; + +using MongoDB.Bson; +using MongoDB.Driver; + +using TextSender_API.Models; + +namespace TextSender_API.Repositories; + + +public class UsersRepository +{ + #region Fields + private string _connectionString; + private string _databaseName; + private string _tableName; + private readonly IMongoCollection _bookCollection; + #endregion + + + #region Constructors + public UsersRepository(string connectionString) + { + this._connectionString = connectionString; + this._databaseName = "TextSender"; + this._tableName = "users"; + var client = this.InitializeClient(); + this._bookCollection = client.GetDatabase(this._databaseName).GetCollection(this._tableName); + } + #endregion + + #region Metods + public void CreateUser(User user) + { + this._bookCollection.InsertOne(user); + } + + public List RetrieveAllUsers() + { + return this._bookCollection.Find(_ => true).ToList(); + } + + public void Update(User user) + { + var filter = Builders.Filter.Eq(u => u.Id, user.Id); + this._bookCollection.ReplaceOne(filter, user); + } + + public void Delete(User user) + { + var filter = Builders.Filter.Eq(u => u.Id, user.Id); + this._bookCollection.DeleteOne(filter); + } + + private MongoClient InitializeClient() + { + return new MongoClient(this._connectionString); + } + #endregion +} + + +public class SaltRepository +{ + #region Fields + private string _connectionString; + private string _databaseName; + private string _tableName; + private readonly IMongoCollection _bookCollection; + #endregion + + + #region Constructors + public SaltRepository(string connectionString) + { + this._connectionString = connectionString; + this._databaseName = "TextSender"; + this._tableName = "salt"; + var client = this.InitializeClient(); + this._bookCollection = client.GetDatabase(this._databaseName).GetCollection(this._tableName); + } + #endregion + + #region Metods + public void Create(Salt salt) + { + this._bookCollection.InsertOne(salt); + } + + public List RetrieveAll() + { + return this._bookCollection.Find(_ => true).ToList(); + } + + public void Update(Salt salt) + { + var filter = Builders.Filter.Eq(u => u.Id, salt.Id); + this._bookCollection.ReplaceOne(filter, salt); + } + + public void Delete(Salt salt) + { + var filter = Builders.Filter.Eq(u => u.Id, salt.Id); + this._bookCollection.DeleteOne(filter); + } + + private MongoClient InitializeClient() + { + return new MongoClient(this._connectionString); + } + #endregion +} \ No newline at end of file