101 lines
4.2 KiB
C#
101 lines
4.2 KiB
C#
using Ninject;
|
|
using Ninject.Modules;
|
|
using Ninject.Parameters;
|
|
using PartSource.Entities.Models;
|
|
using PartSource.Services;
|
|
using System;
|
|
using System.Configuration;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Security.Cryptography;
|
|
using System.Security.Principal;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Web.Http;
|
|
using System.Web.Http.Filters;
|
|
|
|
namespace PartSource.Filters
|
|
{
|
|
public class HmacAuthenticationAttribute : Attribute, IAuthenticationFilter, IFilter
|
|
{
|
|
private readonly SecurityService _securityService;
|
|
|
|
public bool AllowMultiple { get { return false; } }
|
|
|
|
public HmacAuthenticationAttribute()
|
|
{
|
|
_securityService = new StandardKernel().Get<SecurityService>();
|
|
}
|
|
|
|
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
|
|
{
|
|
if (context.Request.Headers.Date.HasValue)
|
|
{
|
|
DateTimeOffset? date = context.Request.Headers.Date;
|
|
DateTimeOffset timestamp = date.Value;
|
|
if (ValidateTimestamp(timestamp))
|
|
{
|
|
if (context.Request.Headers.Authorization == null)
|
|
{
|
|
context.ErrorResult = new HmacErrorResult(HttpStatusCode.Unauthorized);
|
|
return;
|
|
}
|
|
|
|
string[] authParams = context.Request.Headers.Authorization.Parameter.Split(':');
|
|
ApiClient client = await _securityService.GetApiClientByKeyAsync(authParams[0]);
|
|
if (client == null || !client.Active)
|
|
{
|
|
context.ErrorResult = (IHttpActionResult)new HmacErrorResult(HttpStatusCode.Unauthorized);
|
|
return;
|
|
}
|
|
byte[] secret = Encoding.UTF8.GetBytes(client.Secret);
|
|
StringBuilder builder = new StringBuilder();
|
|
builder.Append((object)secret);
|
|
builder.Append((object)context.Request.Method);
|
|
StringBuilder stringBuilder = builder;
|
|
date = context.Request.Headers.Date;
|
|
string str = date.Value.ToString("r");
|
|
stringBuilder.Append(str);
|
|
if (context.Request.Method != HttpMethod.Get)
|
|
{
|
|
using (MD5CryptoServiceProvider md5Provider = new MD5CryptoServiceProvider())
|
|
builder.Append((object)md5Provider.ComputeHash(Encoding.UTF8.GetBytes(await context.Request.Content.ReadAsStringAsync())));
|
|
}
|
|
byte[] numArray;
|
|
using (HMACSHA1 hmacshA1 = new HMACSHA1(secret))
|
|
{
|
|
numArray = Encoding.UTF8.GetBytes(builder.ToString());
|
|
numArray = hmacshA1.ComputeHash(numArray);
|
|
}
|
|
if (Convert.ToBase64String(numArray) == authParams[1])
|
|
{
|
|
string[] roles = new string[1] { "ValidUser" };
|
|
context.Principal = (IPrincipal)new GenericPrincipal((IIdentity)new GenericIdentity(client.AppName), roles);
|
|
return;
|
|
}
|
|
context.ErrorResult = (IHttpActionResult)new HmacErrorResult(HttpStatusCode.Unauthorized);
|
|
return;
|
|
}
|
|
}
|
|
|
|
context.ErrorResult = (IHttpActionResult)new HmacErrorResult(HttpStatusCode.Unauthorized);
|
|
}
|
|
|
|
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
|
|
{
|
|
return new Task(null);
|
|
}
|
|
|
|
private bool ValidateTimestamp(DateTimeOffset timestamp)
|
|
{
|
|
if (int.TryParse(ConfigurationManager.AppSettings["ClockDriftThresholdMinutes"], out int result) && DateTimeOffset.UtcNow.AddMinutes((double)(result * -1)) < timestamp)
|
|
{
|
|
return timestamp < DateTimeOffset.UtcNow.AddMinutes((double)result);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|