using System; using System.Security.Claims; using System.Threading.Tasks; using BlueWest.Cryptography; using BlueWest.Data.Application; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using static BlueWest.WebApi.Context.Users.AuthConsts; 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); return sessionToken; } private string GetHashFromUuid(string uuid) { return _hasher.CreateHash(uuid, BaseCryptoItem.HashAlgorithm.SHA2_512); } private SessionToken GetNewSessionToken(LoginRequest loginRequest, ApplicationUser user, string token) { long timeNow = DateTimeOffset.Now.ToUnixTimeMilliseconds(); var newToken = new SessionToken { Id = GetHashFromUuid(loginRequest.GetUuid()), UserId = user.Id, CreatedDate = timeNow, IsValid = true, ValidFor = SessionConstants.DefaultSessionMaxAge.Milliseconds, AccessToken = token }; return newToken; } public bool SessionTokenIsValid(SessionToken token) { var hasChanges = token.Validate(); if (hasChanges) { _sessionCache.SaveAsync(); } return token.IsValid; } public async Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequest(LoginRequest loginRequest) { var user = await _userManager.FindByEmailAsync(loginRequest.Email); if (user == null) return NegativeToken; if (!await _userManager.CheckPasswordAsync(user, loginRequest.Password)) return NegativeToken; var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme); identity.AddClaim(new Claim(ClaimTypes.Email, user.Email)); var sessionToken = await GetSessionToken(loginRequest); if (sessionToken == null || !SessionTokenIsValid(sessionToken)) { var (success, bearerToken) = await GenerateBearerToken(identity, user); var newSessionToken = GetNewSessionToken(loginRequest, user, bearerToken); await _sessionCache.AddSessionToken(newSessionToken); var tokenUnique = new SessionTokenUnique(newSessionToken); return OkAuth(tokenUnique, identity, success); } var response = new SessionTokenUnique(sessionToken); return OkAuth(response, 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 VerifyLoginByEmailAsync(string email, string password) { var user = await _userManager.FindByEmailAsync(email); return user != null && await _userManager.CheckPasswordAsync(user, password); } public async Task CreateUserAsync(RegisterViewModel userSignupDto) { userSignupDto.Password = _hasher.CreateHash(userSignupDto.Password, BaseCryptoItem.HashAlgorithm.SHA3_512);; var newUser = userSignupDto.ToUser(); return await _userManager.CreateAsync(newUser); } } }