268 lines
10 KiB
C#
268 lines
10 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.Filters;
|
|
using Microsoft.Extensions.Primitives;
|
|
using ServiceShared.Models.Response.Exception;
|
|
using ServiceShared;
|
|
using ServiceShared.Crypto;
|
|
using System.Text;
|
|
using ServiceShared.Https;
|
|
using ServiceOutside.Controllers;
|
|
using ServiceShared.Models.Response;
|
|
using ServiceShared.Database;
|
|
|
|
namespace ServiceOutside.Filter
|
|
{
|
|
public class TrustedHeader : ActionFilterAttribute, IAsyncResultFilter, IAsyncAuthorizationFilter
|
|
{
|
|
/// <summary>
|
|
/// If log type is debug, request headers will be printed out in the console
|
|
/// </summary>
|
|
private static Log.Types _LogType = Log.Types.INFO;
|
|
|
|
/// <summary>
|
|
/// DbContext to check maintenance state of service
|
|
/// </summary>
|
|
private static DbContext _DbContext = null;
|
|
|
|
/// <summary>
|
|
/// Sets the log type
|
|
/// </summary>
|
|
/// <param name="Log.Types">Log.Types</param>
|
|
public static void SetLog(Log.Types logType)
|
|
{
|
|
_LogType = logType;
|
|
}
|
|
|
|
public static void SetDbContext(DbContext dbContext)
|
|
{
|
|
_DbContext = dbContext;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates request header
|
|
/// </summary>
|
|
/// <param name="context">Current context</param>
|
|
/// <returns></returns>
|
|
public virtual async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
|
{
|
|
if (context.HttpContext == null ||
|
|
context.HttpContext.Request == null ||
|
|
context.HttpContext.Request.Headers == null ||
|
|
context.HttpContext.Request.Body == null ||
|
|
context.HttpContext.Request.ContentLength <= 0 ||
|
|
!context.HttpContext.Request.Headers.ContainsKey("User-Agent") ||
|
|
!context.HttpContext.Request.Headers.ContainsKey("Content-Type") ||
|
|
!context.HttpContext.Request.Headers.ContainsKey("Client-Hash") ||
|
|
!context.HttpContext.Request.Headers.ContainsKey("Client-Key") ||
|
|
!context.HttpContext.Request.IsHttps)
|
|
{
|
|
context.Result = new JsonResult(new InvalidClientException());
|
|
return;
|
|
}
|
|
|
|
// User Agent validator
|
|
StringValues userAgent = new StringValues();
|
|
if (!context.HttpContext.Request.Headers.TryGetValue("User-Agent", out userAgent) ||
|
|
!Request.ValidUserAgent(userAgent))
|
|
{
|
|
context.Result = new JsonResult(new InvalidClientException());
|
|
return;
|
|
}
|
|
|
|
// Content Type validator
|
|
StringValues contentType = new StringValues();
|
|
if (!context.HttpContext.Request.Headers.TryGetValue("Content-Type", out contentType) ||
|
|
contentType.ToString() != "application/json")
|
|
{
|
|
context.Result = new JsonResult(new InvalidClientException());
|
|
return;
|
|
}
|
|
|
|
// Client hash validator
|
|
StringValues clientHash = new StringValues();
|
|
if (!context.HttpContext.Request.Headers.TryGetValue("Client-Hash", out clientHash) ||
|
|
!Request.ValidHeaderHash(clientHash.ToString()))
|
|
{
|
|
context.Result = new JsonResult(new InvalidClientException());
|
|
return;
|
|
}
|
|
|
|
// Client Public Key validator
|
|
StringValues clientKey = new StringValues();
|
|
if (!context.HttpContext.Request.Headers.TryGetValue("Client-Key", out clientKey))
|
|
{
|
|
context.Result = new JsonResult(new InvalidClientException());
|
|
return;
|
|
}
|
|
|
|
if (_DbContext != null && _DbContext.GetMaintenance())
|
|
{
|
|
context.HttpContext.Response.StatusCode = 503;
|
|
context.Result = new JsonResult(new MaintenanceException());
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// check if valid base64 encoded
|
|
byte[] publicKey = Convert.FromBase64String(clientKey.ToString());
|
|
}
|
|
catch
|
|
{
|
|
context.Result = new JsonResult(new InvalidClientException());
|
|
}
|
|
|
|
// Check if client signature in headers
|
|
if (context.RouteData != null &&
|
|
context.RouteData.Values != null &&
|
|
context.RouteData.Values.ContainsKey("controller"))
|
|
{
|
|
string controllerName = (string)context.RouteData.Values["controller"];
|
|
|
|
if(!string.IsNullOrEmpty(controllerName) && controllerName.ToLower() != "exchange")
|
|
{
|
|
if(!context.HttpContext.Request.Headers.ContainsKey("Client-Signature") ||
|
|
!context.HttpContext.Request.Headers.ContainsKey("Client-Signature-Key"))
|
|
{
|
|
context.Result = new JsonResult(new InvalidClientException());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Logs request in debug mode
|
|
/// </summary>
|
|
/// <param name="context"></param>
|
|
/// <param name="next"></param>
|
|
/// <returns></returns>
|
|
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
|
|
{
|
|
if(_LogType == Log.Types.DEBUG)
|
|
{
|
|
string headers = "";
|
|
|
|
foreach (var header in context.HttpContext.Request.Headers)
|
|
{
|
|
headers += header.Key + "=" + header.Value + "\r\n";
|
|
}
|
|
|
|
string? message = "";
|
|
|
|
if (context != null &&
|
|
context.HttpContext != null &&
|
|
context.HttpContext.Connection != null &&
|
|
context.HttpContext.Connection.RemoteIpAddress != null)
|
|
{
|
|
message = context.HttpContext.Connection.RemoteIpAddress.ToString() + " " +
|
|
context.ActionDescriptor.DisplayName + "\r\nHeaders:" + headers;
|
|
|
|
}
|
|
|
|
Log.Debug(message);
|
|
}
|
|
|
|
await next();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds Trusted Headers to the response
|
|
/// </summary>
|
|
/// <param name="context"></param>
|
|
public override void OnActionExecuted(ActionExecutedContext context)
|
|
{
|
|
base.OnActionExecuted(context);
|
|
|
|
if (context != null && context.HttpContext != null && context.HttpContext.Response != null &&
|
|
context.HttpContext.Response.Headers != null && context.Controller != null)
|
|
{
|
|
BaseController controller = (BaseController)context.Controller;
|
|
string signatureData = null;
|
|
|
|
if(context.Result != null)
|
|
{
|
|
JsonResult jsonResult = (JsonResult)context.Result;
|
|
|
|
if(jsonResult != null && jsonResult.Value != null && jsonResult.Value.GetType() == typeof(EncryptedResponse))
|
|
{
|
|
EncryptedResponse encryptedResponse = ((EncryptedResponse)jsonResult.Value);
|
|
|
|
if(!string.IsNullOrEmpty(encryptedResponse.encrypted_content))
|
|
{
|
|
signatureData = encryptedResponse.encrypted_content;
|
|
}
|
|
else
|
|
{
|
|
signatureData = encryptedResponse.descriptor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// User Agent
|
|
if(!context.HttpContext.Response.Headers.ContainsKey("User-Agent"))
|
|
{
|
|
context.HttpContext.Response.Headers.Add("User-Agent", "BefundAppServer");
|
|
}
|
|
else
|
|
{
|
|
context.HttpContext.Response.Headers["User-Agent"] = "BefundAppServer";
|
|
}
|
|
|
|
// Content Type
|
|
if (!context.HttpContext.Response.Headers.ContainsKey("Content-Type"))
|
|
{
|
|
context.HttpContext.Response.Headers.Add("Content-Type", "application/json");
|
|
}
|
|
else
|
|
{
|
|
context.HttpContext.Response.Headers["Content-Type"] = "application/json";
|
|
}
|
|
|
|
// Server Hash
|
|
if (!context.HttpContext.Response.Headers.ContainsKey("Server-Hash"))
|
|
{
|
|
context.HttpContext.Response.Headers.Add("Server-Hash", Request.GeServerHash());
|
|
}
|
|
else
|
|
{
|
|
context.HttpContext.Response.Headers["Server-Hash"] = Request.GeServerHash();
|
|
}
|
|
|
|
// Server Key
|
|
if (!context.HttpContext.Response.Headers.ContainsKey("Server-Key"))
|
|
{
|
|
context.HttpContext.Response.Headers.Add("Server-Key", controller.GetServerPublicKey());
|
|
}
|
|
else
|
|
{
|
|
context.HttpContext.Response.Headers["Server-Key"] = controller.GetServerPublicKey();
|
|
}
|
|
|
|
if(!string.IsNullOrEmpty(signatureData))
|
|
{
|
|
// Server Signature
|
|
if (!context.HttpContext.Response.Headers.ContainsKey("Server-Signature"))
|
|
{
|
|
context.HttpContext.Response.Headers.Add("Server-Signature", controller.GetServerSignature(signatureData));
|
|
}
|
|
else
|
|
{
|
|
context.HttpContext.Response.Headers["Server-Signature"] = controller.GetServerSignature(signatureData);
|
|
}
|
|
|
|
// Server Signature Key
|
|
if (!context.HttpContext.Response.Headers.ContainsKey("Server-Signature-Key"))
|
|
{
|
|
context.HttpContext.Response.Headers.Add("Server-Signature-Key", controller.GetServerSignatureKey());
|
|
}
|
|
else
|
|
{
|
|
context.HttpContext.Response.Headers["Server-Signature-Key"] = controller.GetServerSignatureKey();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|