using System; using System.Security.Claims; using System.IdentityModel.Tokens.Jwt; using Microsoft.AspNetCore.Http; using Microsoft.IdentityModel.Tokens; using SNote.Server.Security; namespace SNote.Server.Security; public static class AuthHelper { public static string? GetAuthenticatedUser(HttpContext context, CertificateManager certificateManager) { var token = GetBearerToken(context); if (string.IsNullOrEmpty(token)) return null; try { var principal = ValidateToken(token, certificateManager); // Verify it has a Name claim and is not just a server token var isServer = principal.HasClaim(c => c.Type == "IsServer" && c.Value == "true"); if (isServer) return null; return principal.Identity?.Name; } catch { return null; } } public static bool IsServerAuthenticated(HttpContext context, CertificateManager certificateManager) { var token = GetBearerToken(context); if (string.IsNullOrEmpty(token)) return false; try { var principal = ValidateToken(token, certificateManager); return principal.HasClaim(c => c.Type == "IsServer" && c.Value == "true"); } catch { return false; } } public static bool IsServerTokenValid(HttpContext context, PeerCache peerCache) { var serverUrl = context.Request.Headers["X-Server-Url"].ToString(); var serverToken = context.Request.Headers["X-Server-Token"].ToString(); if (string.IsNullOrEmpty(serverUrl) || string.IsNullOrEmpty(serverToken)) { return false; } return peerCache.VerifySessionToken(serverUrl, serverToken); } // Helper to generate a server token for outgoing sync requests public static string GenerateServerToken(CertificateManager certificateManager) { var cert = certificateManager.GetCertificate(); var privateKey = new X509SecurityKey(cert); var claims = new[] { new Claim(ClaimTypes.Name, "SNoteServerNetwork"), new Claim("IsServer", "true") }; var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(claims), Expires = DateTime.UtcNow.AddMinutes(15), // Short-lived for security SigningCredentials = new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256) }; var tokenHandler = new JwtSecurityTokenHandler(); var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } private static string? GetBearerToken(HttpContext context) { var authHeader = context.Request.Headers["Authorization"].ToString(); if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { return null; } return authHeader.Substring("Bearer ".Length).Trim(); } private static ClaimsPrincipal ValidateToken(string token, CertificateManager certificateManager) { var cert = certificateManager.GetCertificate(); var publicKey = new X509SecurityKey(cert); var validationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = publicKey, ValidateIssuer = false, ValidateAudience = false, ClockSkew = TimeSpan.FromMinutes(5) }; var handler = new JwtSecurityTokenHandler(); return handler.ValidateToken(token, validationParameters, out _); } }