using System; using System.Security.Claims; using System.Threading.Tasks; using BlueWest.Cryptography; using BlueWest.Data.Application; using Duende.IdentityServer.Extensions; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Identity; namespace BlueWest.WebApi.Context.Users { internal class AuthManager : IAuthManager { private readonly ApplicationUserManager _userManager; private readonly IHasher _hasher; private readonly IJwtFactory _jwtFactory; private readonly ISessionCache _sessionCache; /// /// Auth manager constructor /// /// /// /// /// public AuthManager( ApplicationUserManager userManager, IHasher hasher, IJwtFactory jwtFactory, ISessionCache sessionCache) { _userManager = userManager; _hasher = hasher; _jwtFactory = jwtFactory; _sessionCache = sessionCache; } private async Task GetSessionToken(LoginRequest loginRequest) { var uuid = loginRequest.GetUuid(); var hashUuid = GetHashFromUuid(uuid); var sessionToken = await _sessionCache.GetSessionTokenByIdAsync(hashUuid); if (sessionToken != null) return sessionToken; return null; } private string GetHashFromUuid(string uuid) { return _hasher.CreateHash(uuid, BaseCryptoItem.HashAlgorithm.SHA2_512); } private SessionToken GetNewSessionToken(LoginRequest loginRequest, ApplicationUser user, string token) { long unixTime = ((DateTimeOffset)DateTimeOffset.Now).ToUnixTimeMilliseconds();; var newToken = new SessionToken { Id = GetHashFromUuid(loginRequest.GetUuid()), UserId = user.Id, CreatedDate = unixTime, IsValid = true, AccessToken = token }; return newToken; } public bool SessionTokenIsValid(SessionToken token) { var nowMilliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds(); var isExpired = token.CreatedDate + token.ValidFor > nowMilliseconds; if (isExpired) { token.IsValid = false; _sessionCache.SaveAsync(); } return token.IsValid; } public async Task<(bool, string, ClaimsIdentity)> GetSessionTokenId(LoginRequest loginRequest) { var user = await _userManager.FindByEmailAsync(loginRequest.Email); if (user == null) return (false, string.Empty, null); if (!await _userManager.CheckPasswordAsync(user, loginRequest.Password)) return (false, string.Empty, null); var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme); identity.AddClaim(new Claim(ClaimTypes.Email, user.Email)); // Session var sessionToken = await GetSessionToken(loginRequest); if (sessionToken != null) { if (SessionTokenIsValid(sessionToken)) { return (true, sessionToken.Id, identity); } } var (success, bearerToken) = await GenerateBearerToken(identity, user); var newSessionToken = GetNewSessionToken(loginRequest, user, bearerToken); await _sessionCache.AddSessionToken(newSessionToken); return (success, newSessionToken.Id, identity); } private async Task<(bool, string)> GenerateBearerToken(ClaimsIdentity identity, ApplicationUser user) { var jwtToken = await _jwtFactory.GenerateEncodedToken(user.Id, user.UserName); var completed = await _userManager.SetAuthenticationTokenAsync(user, SessionConstants.ApiNamePolicy, SessionConstants.ApiNamePolicy, jwtToken.Token); return (completed == IdentityResult.Success, jwtToken.Token); } public async Task<(bool, string)> GetBearerTokenBySessionTokenId(string sessionId) { if (sessionId.IsNullOrEmpty()) return (false, string.Empty); var bearer = await _sessionCache.GetBearerByAccessTokenId(sessionId); return (bearer != string.Empty, bearer); } /// public async Task VerifyLoginByEmailAsync(string email, string password) { var user = await _userManager.FindByEmailAsync(email); if (user == null) { return false; } return await _userManager.CheckPasswordAsync(user, password); } private RegisterViewModel FromSignupToUser(RegisterViewModel signupDto) { var pwd = signupDto.Password; var hash = _hasher.CreateHash(pwd, BaseCryptoItem.HashAlgorithm.SHA3_512); signupDto.Password = hash; return signupDto; } public async Task CreateUserAsync(RegisterViewModel userSignupDto) { RegisterViewModel userToCreate = FromSignupToUser(userSignupDto); return await _userManager.CreateAsync(userToCreate.ToUser()); } } }