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());
}
}
}