using System; using System.Linq; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; namespace TechSec602.Integration { /// /// C# Global.asax implementation example for 602TechSec integration /// This runs early in the application lifecycle for maximum security coverage /// public class GlobalAsaxExample : HttpApplication { private static TechSec602Client _techSecClient; protected void Application_Start() { // Initialize the client once at application startup _techSecClient = new TechSec602Client(); // Optional: Perform health check at startup Task.Run(async () => { var isHealthy = await _techSecClient.HealthCheckAsync(); if (!isHealthy) { // Log warning or alert that security service is unavailable System.Diagnostics.Debug.WriteLine("602TechSec service is not responding"); } }); } /// /// Early request verification - runs for every request before processing /// protected void Application_BeginRequest() { // Perform verification early in the pipeline var result = _techSecClient.VerifyCurrentRequestAsync().Result; if (!result.IsAllowed) { // Block the request Response.StatusCode = 403; Response.StatusDescription = "Forbidden"; Response.ContentType = "application/json"; Response.Write($@"{{""error"": ""Access denied"", ""reason"": ""{result.Reason}""}}"); Response.End(); } } protected void Application_End() { // Clean up resources _techSecClient?.Dispose(); } } /// /// C# HTTP Module implementation for more granular control /// Add to web.config: <add name="TechSec602SecurityModule" type="YourNamespace.TechSec602SecurityModule"/> /// public class TechSec602SecurityModule : IHttpModule { private TechSec602Client _techSecClient; public void Init(HttpApplication context) { _techSecClient = new TechSec602Client(); context.BeginRequest += OnBeginRequest; } private void OnBeginRequest(object sender, EventArgs e) { var context = ((HttpApplication)sender).Context; // Skip verification for certain paths if needed if (ShouldSkipVerification(context.Request.Path)) { return; } // Perform async verification Task.Run(async () => { var result = await _techSecClient.VerifyCurrentRequestAsync(); if (!result.IsAllowed) { context.Response.StatusCode = 403; context.Response.ContentType = "application/json"; context.Response.Write($@"{{""error"": ""Access denied"", ""reason"": ""{result.Reason}""}}"); context.Response.End(); } }).Wait(); } private bool ShouldSkipVerification(string path) { // Skip verification for static resources, health checks, etc. string[] skipPaths = { "/favicon.ico", "/robots.txt", "/health", "/ping" }; return skipPaths.Any(skip => path.StartsWith(skip, StringComparison.OrdinalIgnoreCase)); } public void Dispose() { _techSecClient?.Dispose(); } } /// /// C# Action Filter for controller-level protection /// Usage: [TechSec602Authorize] on controllers or actions /// public class TechSec602AuthorizeAttribute : ActionFilterAttribute { private static readonly TechSec602Client _client = new TechSec602Client(); public override void OnActionExecuting(ActionExecutingContext filterContext) { var result = _client.VerifyCurrentRequestAsync().Result; if (!result.IsAllowed) { filterContext.Result = new HttpStatusCodeResult(403, result.Reason); } base.OnActionExecuting(filterContext); } } /// /// C# Manual verification helper for specific use cases /// public static class TechSec602Helper { private static readonly TechSec602Client _client = new TechSec602Client(); /// /// Verify specific URL and IP combination. /// For proxy scenarios, provide both the direct IP and forwarded IP. /// /// The URL to verify /// The direct connection IP address /// Optional X-Forwarded-For IP. When provided, BOTH IPs are checked against blocklists. public static async Task VerifyAsync(string url, string ipAddress, string forwardedForIp = null) { return await _client.VerifyRequestAsync(url, ipAddress, forwardedForIp); } /// /// Verify current request /// public static async Task VerifyCurrentAsync() { return await _client.VerifyCurrentRequestAsync(); } /// /// Quick synchronous check (use sparingly). /// For proxy scenarios, provide both the direct IP and forwarded IP. /// /// The URL to verify /// The direct connection IP address /// Optional X-Forwarded-For IP. When provided, BOTH IPs are checked against blocklists. public static bool IsRequestAllowed(string url, string ipAddress, string forwardedForIp = null) { return _client.VerifyRequest(url, ipAddress, forwardedForIp).IsAllowed; } } } // ASP.NET Core Middleware Example (for newer applications) namespace TechSec602.AspNetCore { using Microsoft.AspNetCore.Http; using System.Threading.Tasks; public class TechSec602Middleware { private readonly RequestDelegate _next; private readonly TechSec602Client _client; public TechSec602Middleware(RequestDelegate next, TechSec602Config config) { _next = next; _client = new TechSec602Client(config); } public async Task InvokeAsync(HttpContext context) { var url = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}{context.Request.QueryString}"; var ipAddress = context.Connection.RemoteIpAddress?.ToString(); // Extract X-Forwarded-For IP for proxy/load balancer scenarios string forwardedForIp = null; if (context.Request.Headers.TryGetValue("X-Forwarded-For", out var forwardedValues)) { forwardedForIp = forwardedValues.FirstOrDefault()?.Split(',').FirstOrDefault()?.Trim(); } // Both IPs are checked - request is blocked if EITHER IP is on a blocklist var result = await _client.VerifyRequestAsync(url, ipAddress, forwardedForIp); if (!result.IsAllowed) { context.Response.StatusCode = 403; context.Response.ContentType = "application/json"; await context.Response.WriteAsync($@"{{""error"": ""Access denied"", ""reason"": ""{result.Reason}""}}"); return; } await _next(context); } } // Extension method for easy registration public static class TechSec602MiddlewareExtensions { public static IApplicationBuilder UseTechSec602(this IApplicationBuilder builder, TechSec602Config config) { return builder.UseMiddleware(config); } } }