Initial commit
This commit is contained in:
100
PartSource/Filters/HmacAuthenticationAttribute.cs
Normal file
100
PartSource/Filters/HmacAuthenticationAttribute.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user