using System; using System.Security.Cryptography; using System.Text; using Luticate2.Auth.DataAccess; using Luticate2.Auth.Dbo.Users; using Luticate2.Auth.Interfaces.Tokens; using Luticate2.Auth.Interfaces.Users; using Luticate2.Utils.Business; using Luticate2.Utils.Dbo.Basic; using Luticate2.Utils.Dbo.PaginatedRequest; using Luticate2.Utils.Dbo.Result; using Luticate2.Utils.Interfaces; using Luticate2.Utils.Utils; using Microsoft.AspNetCore.Cryptography.KeyDerivation; namespace Luticate2.Auth.Business { public class LuUsersBusiness : LuCrudBusiness, ILuUsersBusiness { private readonly ILuTokensBusiness _luTokensBusiness; private readonly ILuLoggedUserAccessor _luLoggedUserAccessor; public LuUsersBusiness(LuUsersDataAccess dataAccess, IServiceProvider serviceProvider, ILuTokensBusiness luTokensBusiness, ILuLoggedUserAccessor luLoggedUserAccessor) : base(dataAccess, serviceProvider) { _luTokensBusiness = luTokensBusiness; _luLoggedUserAccessor = luLoggedUserAccessor; } public string GenerateSalt() { var salt = new byte[128 / 8]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(salt); } return Convert.ToBase64String(salt); } public string HashPassword(string password, string salt) { var hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(password, Encoding.ASCII.GetBytes(salt), KeyDerivationPrf.HMACSHA1, 10000, 256 / 8)); return hashed; } public bool VerifyPasswordHash(string password, string hash, string salt) { var newHash = HashPassword(password, salt); return newHash == hash; } public LuResult FindByUsername(string username) { return DataAccess.FindByUsername(username); } public LuResult Register(LuUsersAddDbo user) { var userRes = FindByUsername(user.Username); if (userRes) { return LuResult.Error(LuStatus.InputError, $"username: {user.Username}", "Username already exists"); } if (userRes.Status != LuStatus.NotFound) { return userRes; } var salt = GenerateSalt(); var password = HashPassword(user.Password, salt); return this.AddDbo(new LuUsersAddFullDbo { AuthenticationSourceId = Guid.Empty.ToDbo(), Data = null, Password = password, Salt = salt, Username = user.Username }); } public LuResult Edit(string id, LuUsersEditDbo user) { throw new NotImplementedException(); } public LuResult Login(string username, string password) { var userRes = FindByUsername(username); if (userRes.Status == LuStatus.NotFound) { return LuResult.Error(LuStatus.LoginError, $"unknown username; username: {username}", "Invalid username or password"); } if (!userRes) { return userRes.To(); } if (userRes.Data.Password == null) { return LuResult.Error(LuStatus.LoginError, $"null password; username: {username}", "Invalid username or password"); } if (!VerifyPasswordHash(password, userRes.Data.Password, userRes.Data.Salt)) { return LuResult.Error(LuStatus.LoginError, $"invalid password; username: {username}", "Invalid username or password"); } var tokenRes = _luTokensBusiness.GenerateToken(userRes.Data.ToLite()); if (!tokenRes) { return tokenRes.To(); } return LuResult.Ok(new LuUsersLoginResultDbo { Token = tokenRes.Data, User = userRes.Data.ToLite() }); } public LuResult Logout(string token) { if (token == null) { return LuResult.Ok(true); } return _luTokensBusiness.UnRegisterToken(token).To(usersToken => true); } public LuResult Me() { return LuResult.Ok(_luLoggedUserAccessor.GetLoggedUser()); } LuResult ILuCrudInterface.DeleteSingleById(string id, Func returnFunc) { var loggedUser = _luLoggedUserAccessor.GetLoggedUser(); if (id == Guid.Empty.ToDbo()) { return LuResult.Error(LuStatus.InputError, $"loggedUser: {loggedUser.Username}", "Can not remove anonymous user"); } if (id == loggedUser.Id) { return LuResult.Error(LuStatus.InputError, $"loggedUser: {loggedUser.Username}", "Can not remove yourself"); } return base.DeleteSingleById(id, returnFunc); } public LuResult> Sessions(LuPaginatedRequestDbo paginatedRequestDbo) { return _luTokensBusiness.GetTokensForUser(_luLoggedUserAccessor.GetLoggedUser().ToLite(), paginatedRequestDbo); } } }