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