229 lines
8.7 KiB
C#
229 lines
8.7 KiB
C#
using JwtAuthManager;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using Ocelot.Configuration;
|
|
using Ocelot.Middleware;
|
|
using Security;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Security.Claims;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace ApiGateway
|
|
{
|
|
public static class CustomLogic
|
|
{
|
|
//private static readonly int _SEMILLA = 1262;
|
|
private static readonly Encripter _encript = new();
|
|
|
|
public static bool Authorize(HttpContext ctx)
|
|
{
|
|
// Solo para test
|
|
string seguimiento = ctx.Request.Headers["Potato"];
|
|
var route2 = ctx.Items.DownstreamRequest(); //Solo el path del request
|
|
var route3 = ctx.Items.DownstreamRoute(); //Datos full del request
|
|
var calledUrl = ctx.Items.DownstreamRoute().UpstreamPathTemplate.OriginalValue;
|
|
|
|
var isLogin = calledUrl == "/Ext/Login" ;
|
|
var isExtLogin = calledUrl == "/Auth/Login";
|
|
|
|
// Excepcion para login, no requiere token
|
|
if (String.Equals(calledUrl, "/Ext/Login") ||
|
|
String.Equals(calledUrl, "/Auth/Login"))
|
|
return true;
|
|
|
|
//if (isLogin == true || isExtLogin == true) return true;
|
|
|
|
try
|
|
{
|
|
string path = ctx.Request.Path;
|
|
|
|
string authString = ctx.Request.Headers["Authorization"];
|
|
|
|
//Perfil seleccionado, no obligatorio para login
|
|
string? signature = ctx.Request.Headers["Signature"];
|
|
signature = Base64Decode(signature);
|
|
|
|
|
|
if (authString.IsNullOrEmpty()) throw new Exception("Nel wey, no hay token");
|
|
|
|
|
|
string? jwtDescifrado = DesCifrar(authString.Replace("Bearer ", ""));
|
|
if (jwtDescifrado.IsNullOrEmpty()) throw new Exception("Nel wey, token inválido");
|
|
|
|
|
|
var jwtToken = new JwtSecurityToken(jwtDescifrado);
|
|
if (VerifyToken(jwtToken.RawData) == false) throw new Exception("Firma inválida");
|
|
|
|
|
|
//Claims dentro del .json
|
|
DownstreamRoute? route = (DownstreamRoute?)ctx.Items["DownstreamRoute"];
|
|
if (route == null || route.RouteClaimsRequirement.Count == 0) return true;
|
|
|
|
//flag for authorization // Para iterar multples roles, no usados ya que se usa solo con 1
|
|
//bool auth = false;
|
|
|
|
//where are stored the claims of the jwt token
|
|
|
|
//Claims del token
|
|
Claim[] claims = jwtToken.Claims.ToArray<Claim>();
|
|
|
|
//where are stored the required claims for the route
|
|
Dictionary<string, string> required = route.RouteClaimsRequirement;
|
|
Regex reor = new Regex(@"[^,\s+$ ][^\,]*[^,\s+$ ]");
|
|
MatchCollection matches;
|
|
|
|
Regex reand = new Regex(@"[^&\s+$ ][^\&]*[^&\s+$ ]");
|
|
MatchCollection matchesand;
|
|
//int cont = 0;
|
|
foreach (KeyValuePair<string, string> claim in required)
|
|
{
|
|
matches = reor.Matches(claim.Value);
|
|
foreach (Match match in matches)
|
|
{
|
|
matchesand = reand.Matches(match.Value);
|
|
//cont = 0;
|
|
foreach (Match m in matchesand) //m = claim dentro dle json (value)
|
|
{
|
|
//Si permite cualquier permiso
|
|
if (String.Equals("any", m.Value)) return true;
|
|
|
|
|
|
foreach (Claim cl in claims) // Claim (key:value) desde el token
|
|
{
|
|
|
|
if (cl.Type == claim.Key && String.Equals(claim.Key, "permisos"))
|
|
{
|
|
string separador = "::";
|
|
|
|
int index = cl.Value.LastIndexOf(separador);
|
|
string newPermiso = cl.Value;
|
|
string permisoRoles = cl.Value;
|
|
if (index >= 0)
|
|
newPermiso = cl.Value[..index];
|
|
|
|
permisoRoles = cl.Value.Substring(index + separador.Length);
|
|
|
|
var rolesLst = permisoRoles.Split(',');
|
|
|
|
// Excepcion de rol Seleccionado para Externo
|
|
if(String.Equals(newPermiso, m.Value) &&
|
|
String.Equals(_encript.DecryptHashTkn(newPermiso), "externo"))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//Si no hay perfil seleccionado
|
|
if (signature.IsNullOrEmpty())
|
|
throw new Exception("Falta el perfil, no mames");
|
|
|
|
bool aplicaRolSeleccionado = rolesLst.Any(signature!.Contains);
|
|
|
|
//Aqui remuevo los :: teniendo en cuenta key == permisos cl.Value
|
|
//if (cl.Value == m.Value)
|
|
if (String.Equals(newPermiso, m.Value) && aplicaRolSeleccionado == true)
|
|
{
|
|
return true;
|
|
//cont++; //NO NECESARIO porque solo hay 1 permiso por request
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//if (cont == matchesand.Count)
|
|
//{
|
|
// return true;
|
|
// // break;
|
|
//}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
ctx.Items.SetError(new UnauthenticatedError(e.Message));
|
|
return false;
|
|
}
|
|
|
|
///
|
|
//return true;
|
|
///
|
|
|
|
}
|
|
|
|
|
|
public static bool VerifyToken(string token)
|
|
{
|
|
if(_encript.IsValid == false) return false;
|
|
|
|
var validationParameters = new TokenValidationParameters()
|
|
{
|
|
ValidateIssuer = false,
|
|
ValidateAudience = false,
|
|
ValidateIssuerSigningKey = true,
|
|
//IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(JwtTokenHandler.JWT_SECURITY_KEY))
|
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Encripter.HashKey))
|
|
};
|
|
|
|
var tokenHandler = new JwtSecurityTokenHandler();
|
|
SecurityToken validatedToken = null;
|
|
|
|
try
|
|
{
|
|
tokenHandler.ValidateToken(token, validationParameters, out validatedToken);
|
|
}
|
|
catch (SecurityTokenException)
|
|
{
|
|
return false;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
|
|
var logger = loggerFactory.CreateLogger("");
|
|
//something else happened
|
|
logger.LogInformation(e.ToString());
|
|
|
|
return false;
|
|
//throw;
|
|
}
|
|
//... manual validations return false if anything untoward is discovered
|
|
return validatedToken != null;
|
|
}
|
|
|
|
public static string? DesCifrar(string value)
|
|
{
|
|
if (_encript.IsValid == false) return null;
|
|
try
|
|
{
|
|
string? b64Decrypted = Base64Decode(value);
|
|
if (b64Decrypted.IsNullOrEmpty()) return null;
|
|
|
|
string decryptedText = "";
|
|
for (int i = 0; i < b64Decrypted!.Length; i++)
|
|
{
|
|
int encrypted = (int)b64Decrypted[i];
|
|
int decryption = encrypted - _encript.getSemilla();
|
|
decryptedText += Char.ConvertFromUtf32(decryption);
|
|
}
|
|
return decryptedText;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static string? Base64Decode(string base64EncodedData)
|
|
{
|
|
try
|
|
{
|
|
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
|
|
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|