using LdapLoginLib; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; using MSAdminUsuarios.Context; using Newtonsoft.Json.Linq; using Security; using System.IdentityModel.Tokens.Jwt; using System.Reflection.Metadata; using System.Security.Claims; using System.Text; namespace MSAdminUsuarios.Controllers { [ApiController] [Route("[controller]")] public class AuthController : ControllerBase { private readonly ModelContext _context; private readonly Encripter _encript = new(); private readonly LDAP _ldap; public AuthController(ModelContext context) { _context = context; var loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); }); var logger = loggerFactory.CreateLogger(); _ldap = new LDAP(logger); } [HttpPost("Login")] public IActionResult Login([FromBody] LoginModel login) { try { if (!_encript.IsValid) return BadRequest("Lectura inválida"); if (login.TX_LOGINNAME_USUMS == null) return BadRequest("Es necesario ingresar un usuario"); if ( string.IsNullOrEmpty(login.TX_LOGINNAME_USUMS?.Trim()) && string.IsNullOrEmpty(login.TX_PKDOC_USUMS?.Trim()) && string.IsNullOrEmpty(login.TX_CORREO_USUMS?.Trim()) ) { throw new Exception("Es necesario ingresar un usuario."); } if (login.TX_PASSWORD_USUMS == null) return BadRequest("Es necesario ingresar una contraseña."); USUARIO? userldap = _context.USUARIOSMs.FirstOrDefault(u => u.TX_LOGINNAME_USUMS == login.TX_LOGINNAME_USUMS); if (userldap == null) return BadRequest("Nombre de usuario no encontrado."); if (userldap.NU_ESTADO_USUMS != 1) return BadRequest("Usuarios inactivo o bloqueado."); if (userldap.BL_VIENELDAP_USUMS == 1) { //bool boolldap = LoginLib.Login(login.TX_LOGINNAME_USUMS, login.TX_PASSWORD_USUMS); bool loggedWithLdap = _ldap.Login( username: login.TX_LOGINNAME_USUMS, document: login.TX_PKDOC_USUMS, email: login.TX_CORREO_USUMS, password: login.TX_PASSWORD_USUMS ); if (loggedWithLdap == true) { string token = Token(userldap); return Ok(new { token = token, user = userldap.TX_PKDOC_USUMS, ldap = 1 }); } else { return BadRequest(); } }else if(userldap.BL_VIENELDAP_USUMS != 1) //return BadRequest(new ResLoginExt("No eres un usuario interno.", true, userldap.NU_ESTADO_USUMS)); { /*USUARIO? user = _context.USUARIOSMs.FirstOrDefault(u => u.TX_LOGINNAME_USUMS == login.TX_LOGINNAME_USUMS && u.TX_PASSWORD_USUMS == _encript.EncryptPwd(login.TX_PASSWORD_USUMS)); if (user == null) return BadRequest("Usuario o contraseña incorrectos");*/ //if (userldap.BL_VIENELDAP_USUMS != 1) return BadRequest("No eres un usuario interno"); /*string token = Token(user); return Ok(new { token = token, user = user.TX_PKDOC_USUMS, primera = user.NU_INICIO_PRIMERAVEZ_USUMS, ldap = 0 });*/ }else { return BadRequest("Error"); } } catch (Exception e) { return BadRequest(e.Message); } } /*[HttpPost("CambiarClave_old")] public IActionResult CambiarClave([FromBody] USUARIO us) { try { USUARIO? user = _context.USUARIOSMs.FirstOrDefault(u => us.NU_PK_USUMS == u.NU_PK_USUMS); if (user == null) return BadRequest("Usuario no encontrado."); string newPass = _encript.EncryptPwd(us.TX_PASSWORD_USUMS!); user.TX_PASSWORD_USUMS = newPass; _context.USUARIOSMs.Update(user); _context.SaveChanges(); return Ok("Contrase�a actualizada correctamente"); } catch (Exception e) { return Conflict(e.Message); } }*/ [HttpPost("Proveedor")] public IActionResult LoginProveedores([FromBody] LoginModel login) { try { if (!_encript.IsValid) return BadRequest(new ResLoginExt("Lectura inv�lida")); if (login.TX_LOGINNAME_USUMS == null) return BadRequest(new ResLoginExt("Es necesario ingresar un usuario")); if (login.TX_PASSWORD_USUMS == null) return BadRequest(new ResLoginExt("Es necesario ingresar una contrase�a")); USUARIO? userExist = _context.USUARIOSMs.FirstOrDefault(u => u.TX_LOGINNAME_USUMS == login.TX_LOGINNAME_USUMS); if (userExist == null) return BadRequest(new ResLoginExt("Usuario o contrase�a incorrectos")); USUARIO? user = _context.USUARIOSMs.FirstOrDefault(u => u.TX_LOGINNAME_USUMS == login.TX_LOGINNAME_USUMS && u.TX_PASSWORD_USUMS == _encript.EncryptPwd(login.TX_PASSWORD_USUMS)); if (user == null) return BadRequest(new ResLoginExt("Usuario o contraseña incorrectos", true, userExist.NU_ESTADO_USUMS)); if (user.NU_ESTADO_USUMS != 1) return BadRequest(new ResLoginExt("Usuario inactivo, bloqueado o eliminado.", true, user.NU_ESTADO_USUMS)); if (user.BL_VIENELDAP_USUMS != 0) return BadRequest(new ResLoginExt("No eres un usuario externo.", true, user.NU_ESTADO_USUMS)); string token = Token(user); return Ok(new ResLoginExt("Bienvenido al sistema.", true, user.NU_ESTADO_USUMS, token, user.NU_INICIO_PRIMERAVEZ_USUMS, user.TX_PKDOC_USUMS, user.BL_VIENELDAP_USUMS)); } catch (Exception e) { return BadRequest(e.Message); } } [HttpPatch("RenovarToken")] public IActionResult RefreshToken([FromBody] string token) { try { #warning este metodo se debe revisar, des-encriptado no se debe permitir! JwtSecurityTokenHandler handler = new(); JwtSecurityToken tkn = handler.ReadJwtToken(Encripter.Descypher(token)); int pk = Int32.Parse(tkn.Claims.FirstOrDefault(c => c.Type == "pk").Value); USUARIO? user = _context.USUARIOSMs.FirstOrDefault(u => u.NU_PK_USUMS == pk); if (user == null) return BadRequest("No se encuentra usuario"); string newToken = Token(user); return Ok(newToken); } catch(Exception ex) { return BadRequest(ex.Message); } } [HttpGet("Encriptar")] public IActionResult Encriptar(string text, int tipo) { if (!_encript.IsValid) return BadRequest("Lectura inv�lida"); if (tipo == 0) return Ok(_encript.EncryptPwd(text)); return Ok(_encript.EncryptHashTkn(text)); } [HttpGet("Desencriptar")] public IActionResult Desencriptar(string text, int tipo) { if (!_encript.IsValid) return BadRequest("Lectura inv�lida"); if (tipo == 0) return Ok(_encript.DecryptPwd(text)); return Ok(_encript.DecryptHashTkn(text)); } [HttpGet("TknCambioClave")] public IActionResult ObtenerTokenCambioClave(int pkUs) { try { return Ok(TokenCambioClave(pkUs)); } catch (Exception e) { return BadRequest(e.Message); } } [HttpPost("pruebaUsuario")] public string Token(USUARIO user) { List perfilesPorUsuario = (from perf in _context.PERFILESPORUSUARIOs where perf.TX_FKDOC_USUMS == user.TX_PKDOC_USUMS && perf.NU_FK_PFL != null && perf.BL_ESTADO_PFLXUSU == 1 select perf).ToList(); List perfiles = perfilesPorUsuario.Select(p => p.NU_FK_PFL).ToList(); List permisos = (from perfXUs in perfilesPorUsuario join perm in _context.PERMISOSMs on perfXUs.NU_FK_PFL equals perm.NU_FK_PFL where perm.BL_ESTADO_PMS == 1 select perm).ToList(); Dictionary perfilesPorPermiso = new(); foreach (PERMISO p in permisos) { string key = p.NU_FK_MS.ToString(); string val = p.NU_FK_PFL.ToString(); if (perfilesPorPermiso.ContainsKey(key)) { string antVal = perfilesPorPermiso[key]; perfilesPorPermiso.Remove(key); perfilesPorPermiso.Add(key, antVal + "," + val); } else { perfilesPorPermiso.Add(key, val); } } perfiles.Add(-1); //Security key debe ser un environment variable seguro var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Encripter.HashKey)); var signingCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256); string nombres = ""; string apellidos = ""; if (user.TX_PRIMERNOM_USUMS != null) nombres += user.TX_PRIMERNOM_USUMS; if (user.TX_SEGUNDONOM_USUMS != null) nombres += " " + user.TX_SEGUNDONOM_USUMS; if (user.TX_PRIMERAPELL_USUMS != null) apellidos += user.TX_PRIMERAPELL_USUMS; if (user.TX_SEGUNDOAPELL_USUMS != null) apellidos += " " + user.TX_SEGUNDOAPELL_USUMS; nombres = nombres.Trim(); apellidos = apellidos.Trim(); if (nombres == "") nombres = "N"; if (apellidos == "") apellidos = "A"; int tipo_doc = user.NU_TIPODOC_USUMS == null ? -1 : (int)user.NU_TIPODOC_USUMS; ClaimsIdentity claims = new ClaimsIdentity(new List { new Claim("user", user.TX_PKDOC_USUMS), new Claim("nombres", nombres), new Claim("apellidos", apellidos), new Claim("tipo_doc", tipo_doc.ToString()), new Claim("pk", user.NU_PK_USUMS.ToString()), new Claim("sedes", user.TX_SEDES_USUMS == null ? "" : user.TX_SEDES_USUMS), new Claim("TX_NOMBRE_PVD", user.TX_NOMBRE_PVD ?? "{}"), new Claim("uid", user.TX_UUID_USUMS.ToString()) }); foreach (int p in perfiles) { claims.AddClaim(new Claim("perfiles", p.ToString(), ClaimValueTypes.String)); } //foreach (PERMISO p in permisos) //{ // claims.AddClaim(new Claim("permisos", Encripter.Encrypt(p.NU_FK_MS.ToString()))); //} foreach (KeyValuePair p in perfilesPorPermiso) { string key = p.Key; string val = p.Value; claims.AddClaim(new Claim("permisos", _encript.EncryptHashTkn(key) + "::" + val)); } var securityTokenDescriptor = new SecurityTokenDescriptor { Subject = claims, Expires = DateTime.Now.AddDays(20), SigningCredentials = signingCredentials }; var jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); var securityToken = jwtSecurityTokenHandler.CreateToken(securityTokenDescriptor); var token = jwtSecurityTokenHandler.WriteToken(securityToken); return Encripter.Cypher(token); } [HttpPatch("BloquearUsuario")] public IActionResult BloquearUsuario([FromBody] string usuario) { try { if (usuario == null) throw new Exception("Usuario no encontrado"); USUARIO? user = _context.USUARIOSMs.FirstOrDefault(u => u.TX_LOGINNAME_USUMS == usuario); if (user == null) throw new Exception("Usuario no encontrado"); //user.NU_BLOQUEO_USUMS = 0; user.NU_ESTADO_USUMS = 2; _context.USUARIOSMs.Update(user); _context.SaveChanges(); //return Ok(new { message = "Su cuenta ha sido bloqueada debido a demasiados intentos fallidos" }); //return Ok("Su cuenta ha sido bloqueada debido a demasiados intentos fallidos"); return Ok(new ResLoginExt("Su cuenta ha sido bloqueada debido a demasiados intentos fallidos.", true)); } catch (Exception ex) { //return BadRequest(new { message = ex.Message }); //return BadRequest(ex.Message); return BadRequest(new ResLoginExt(ex.Message, true)); } } [HttpPost("CambiarClave")] public IActionResult CambiarClave([FromBody] CambiarClaveModel model) { if (model.NewPassword != model.ConfirmPassword) { return BadRequest("Las contraseñas no coinciden."); } try { if (model == null) throw new Exception("No se recibieron datos"); USUARIO? user = _context.USUARIOSMs.FirstOrDefault(u => u.TX_LOGINNAME_USUMS == model.User); if (user == null) return BadRequest("Usuario no encontrado."); string newPass = _encript.EncryptPwd(model.NewPassword!); user.TX_PASSWORD_USUMS = newPass; user.NU_INICIO_PRIMERAVEZ_USUMS = 1; _context.USUARIOSMs.Update(user); _context.SaveChanges(); //return Ok("Contrase�a restablecida con éxito."); //return Ok(new { message = "Contrase�a restablecida con éxito." }); return Ok(new ResLoginExt("Contrase�a restablecida con éxito.", true)); } catch (Exception ex) { //return Conflict(e.Message); //return BadRequest(new { message = ex.Message }); return BadRequest(ex.Message); } } string TokenCambioClave(int pkUser) { USUARIO? user = _context.USUARIOSMs.FirstOrDefault(u => pkUser == u.NU_PK_USUMS); if (user == null) throw new Exception("Usuario no encontrado"); //Security key debe ser un environment variable seguro var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Encripter.HashKey)); var signingCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256); ClaimsIdentity claims = new ClaimsIdentity(new List { new Claim("user", user.TX_PKDOC_USUMS), new Claim("loginName", user.TX_LOGINNAME_USUMS), new Claim("pk", user.NU_PK_USUMS.ToString()) }); var securityTokenDescriptor = new SecurityTokenDescriptor { Subject = claims, Expires = DateTime.UtcNow.AddMinutes(20), SigningCredentials = signingCredentials }; var jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); var securityToken = jwtSecurityTokenHandler.CreateToken(securityTokenDescriptor); var token = jwtSecurityTokenHandler.WriteToken(securityToken); return Encripter.Cypher(token); } } public class LoginModel { public string? TX_LOGINNAME_USUMS { get; set; } public string? TX_CORREO_USUMS { get; set; } public string? TX_PKDOC_USUMS { get; set; } public string? TX_PASSWORD_USUMS { get; set; } } public class ResLoginExt { public ResLoginExt(string _message, bool _exist = false, int? _estado = null, string? _token = "", int? _primera = null, string? _user = "", int? _ldap = null) { Message = _message; Token = _token; Existe = _exist; Estado = _estado; Primera = _primera; User = _user; Ldap = _ldap; } public bool Existe { get; set; } public int? Estado { get; set; } public string? Token { get; set; } public string Message { get; set; } = null!; public int? Primera { get; set; } public string? User { get; set; } public int? Ldap { get; set; } } public class CambiarClaveModel { public string User { get; set; } public string NewPassword { get; set; } public string ConfirmPassword { get; set; } } static class Options { } }