using System; using System.Security.Principal; using System.Threading.Tasks; using BO.AppServer.Business.Mapper; using BO.AppServer.Data.Entity; using BO.AppServer.Metadata.Configuration; using BO.AppServer.Metadata.Dto; using BO.AppServer.Metadata.Enums; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Quadarax.Foundation.Core.Business; using Quadarax.Foundation.Core.Data.Interface.Entity.Dto; using Quadarax.Foundation.Core.Exceptions; namespace BO.AppServer.Business.Services { public class AccessService : AbstractService { private const string CS_SESSION_MAGIC = "magic"; private const string CS_SESSION_TOKEN = "token"; private SignInManager _manSignIn; private readonly UserManager _manUsers; private readonly UserRepo _repoUsers; private readonly IHttpContextAccessor _context; private readonly Configuration _configuration; public AccessService(IOptions config, SignInManager manSignIn, UserManager manUsers, UserRepo repoUsers, IPrincipal currentPrincipal, ILoggerFactory logger, IHttpContextAccessor context) : base(currentPrincipal, logger) { _configuration = config.Value; _manUsers = manUsers ?? throw new ArgumentNullException(nameof(manUsers)); _repoUsers = repoUsers ?? throw new ArgumentNullException(nameof(repoUsers)); _context = context ?? throw new ArgumentNullException(nameof(context)); _manSignIn = manSignIn ?? throw new ArgumentNullException(nameof(manSignIn)); } public void OpenMagic(string magic) { _context.HttpContext.Session.SetString(CS_SESSION_MAGIC , magic); CheckMagic(); _context.HttpContext.Session.SetString(CS_SESSION_TOKEN , "TKN" + Guid.NewGuid().ToString("N")); } public string GetToken() { return _context.HttpContext.Session.GetString(CS_SESSION_TOKEN); } public void CheckMagic() { if (!_configuration.Api.Console.MagicKeys.Contains(_context.HttpContext.Session.GetString(CS_SESSION_MAGIC))) throw new UnauthorizedAccessException("Wrong magic key to access to BO.AppServer api!"); } public void CheckToken(string token) { if (string.IsNullOrEmpty(token) || _context.HttpContext.Session.GetString(CS_SESSION_TOKEN) != token) throw new UnauthorizedAccessException("Wrong token to access to BO.AppServer api!"); } public async Task> Login(string userName, string userPassword, RoleEnum loginForRole) { var idtUser = await _manUsers.FindByNameAsync(userName); if (idtUser == null) { return new ResultValueDto(new CodeException(1201, $"User '{userName}' doesn't exists!")); } var isApproved = await _manUsers.IsInRoleAsync(idtUser, loginForRole.ToString()); if (!isApproved) { return new ResultValueDto(new CodeException(1200, $"User '{userName}' has no permission to login in. Access denied!")); } var user = _repoUsers.GetByIfReference(idtUser.Id); if (!user.IsEnabled) { Log.LogWarning($"User '{userName}' is disabled for log-in!"); return new ResultValueDto(new CodeException(1202, $"User '{userName}' is disabled for log-in!")); } var result = await _manSignIn.PasswordSignInAsync(userName, userPassword, false, lockoutOnFailure: false); if (result.Succeeded) { user.LastLogged = DateTime.Now; _repoUsers.Set(user); _repoUsers.Commit(); Log.LogInformation($"User '{userName}' [{user.Id}/{idtUser.Id}] logged in."); return new ResultValueDto(user.Map()); } if (result.RequiresTwoFactor) { Log.LogWarning($"Two-factor sign for '{userName}' is set but not supported. Contact administrator."); return new ResultValueDto(new Exception( $"Two-factor sign for '{userName}' is set but not supported. Contact administrator.")); } if (result.IsLockedOut) { Log.LogWarning($"User '{userName}' is locked out."); return new ResultValueDto(new CodeException(1202, $"User '{userName}' is locked out!")); } Log.LogWarning($"Invalid login attempt for user '{userName}'."); return new ResultValueDto(new CodeException(1203, $"Invalid login attempt for user '{userName}'.")); } } }