Apigateway/ApiGateway/CustomLogic.cs
2022-11-02 11:31:23 -05:00

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