You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
PortfolioLink/backend/JwtAuthenticationMiddelware.cs

105 lines
4.4 KiB

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Hasher;
public class JwtAuthenticationMiddleware
{
private readonly RequestDelegate _next;
private readonly IConfiguration _configuration;
private readonly ILogger _logger;
public JwtAuthenticationMiddleware(RequestDelegate next, IConfiguration configuration, ILogger<JwtAuthenticationMiddleware> logger)
{
_next = next;
_configuration = configuration;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
_logger.LogDebug($"Request cookies: {context.Request.Cookies}");
// Read the Authorization and UserFingerprint cookies
context.Request.Cookies.TryGetValue("__Secure-Authorization", out string token);
context.Request.Cookies.TryGetValue("__Secure-UserFingerprint", out string fingerprint);
if (!string.IsNullOrEmpty(token) && !string.IsNullOrEmpty(fingerprint))
{
// Validate the JWT and fingerprint
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = _configuration["JwtSettings:issuer"],
ValidAudience = _configuration["JwtSettings:audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtSettings:SecretKey"])),
ClockSkew = TimeSpan.Zero
};
try
{
var tokenHandler = new JwtSecurityTokenHandler();
tokenHandler.ValidateToken(token, validationParameters, out SecurityToken validatedToken);
// Extract claims from the validated token
var jwtToken = (JwtSecurityToken)validatedToken;
var claims = jwtToken.Claims;
// Validate the fingerprint
var fingerprintClaim = claims.FirstOrDefault(c => c.Type == "Fingerprint");
if (fingerprintClaim != null)
{
var hashedFingerprint = fingerprintClaim.Value;
_logger.LogDebug($"HashedFp: {hashedFingerprint} | Cookie Fp: {fingerprintClaim}");
// Verify the fingerprint here, based on how you generate the fingerprint hash
// If the fingerprint is valid, set the User property with the claims
if (FingerPrinter.ValidateFingerpint(fingerprint,hashedFingerprint))
{
// Record the claims so that they can be accessed by controllers
context.User = new ClaimsPrincipal(new ClaimsIdentity(claims.Select(c => c.Type == "Auth" ? new Claim(ClaimTypes.Role, c.Value) : c), "Jwt"));
}
}
// Validate signed headers
string payloadSig = context.Request.Headers["X-Payload-Signature"];
// Read the request body content
string payload;
using (var streamReader = new StreamReader(context.Request.Body))
{
payload = await streamReader.ReadToEndAsync();
}
string clientPublicKey = claims.FirstOrDefault(c => c.Type == "ClientPublicKey").Value;
_logger.LogDebug($"PayloadSig: {payloadSig} | payload: {payload} | Key: {clientPublicKey}");
//FIXME This could use some testing
try
{
bool validSig = KeyHelper.validateSignature(payloadSig, payload, clientPublicKey);
_logger.LogDebug($"Valid sig!");
}
catch
{
_logger.LogDebug($"INVALID sig!");
}
}
catch (SecurityTokenValidationException)
{
//FIXME Log the validation error or perform necessary actions
_logger.LogWarning("Invlaid JWT Exception!");
}
}
// Call the next middleware in the pipeline
await _next(context);
}
}