Asked by:
Test Method for HMAC authentication for we api

Question
-
User1306218145 posted
Dear all,
How can I write test method for HMAC Authentication for web api. Find the implementation of the class below;
using System; using System.Web; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using System.Web.Http.Filters; using System.Security.Principal; using System.Web.Http.Results; using System.Net.Http.Headers; using System.Text; using System.Security.Cryptography; using System.Web.Http; using System.Net; using System.Configuration; using XYZ.ABC.Contracts; using System.Web.Mvc; namespace XYZ.ABC.Client.Filters { public class HMACSecuredAttribute : Attribute, IAuthenticationFilter { private readonly IKeyManager _manager; public HMACSecuredAttribute() { this._manager = DependencyResolver.Current.GetService(typeof(IKeyManager)) as IKeyManager; } public bool AllowMultiple => false; private bool isValidAppId = false; private readonly UInt64 requestTimeOutInSeconds = UInt64.Parse(ConfigurationManager.AppSettings["requestTimeOutInSeconds"].ToString()); public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) { var req = context.Request; if(req.Headers.Authorization != null) { var rawAuthzHeader = req.Headers.Authorization.Parameter.ToString(); var autherizationHeaderArray = GetAutherizationHeaderValues(rawAuthzHeader); if (autherizationHeaderArray != null) { var APPId = autherizationHeaderArray[0]; var incomingBase64Signature = autherizationHeaderArray[1]; var nonce = autherizationHeaderArray[2]; var requestTimeStamp = autherizationHeaderArray[3]; var isValid = isValidRequest(req, APPId, incomingBase64Signature, nonce, requestTimeStamp); if (isValid.Result) { var currentPrincipal = new GenericPrincipal(new GenericIdentity(APPId), null); context.Principal = currentPrincipal; } else { context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request); } } else { context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request); } } else { } return Task.FromResult(0); } public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) { context.Result = new ResultWithChallenge(context.Result); return Task.FromResult(0); } private string[] GetAutherizationHeaderValues(string rawAuthzHeader) { var credArray = rawAuthzHeader.Split(':'); if (credArray.Length == 4) { return credArray; } else { return null; } } private async Task<bool> isValidRequest(HttpRequestMessage req, string APPId, string incomingBase64Signature, string nonce, string requestTimeStamp) { string requestContentBase64String = ""; string requestUri = HttpUtility.UrlEncode(req.RequestUri.AbsoluteUri.ToLower()); string requestHttpMethod = req.Method.Method; isValidAppId = _manager.IsValidAppId(APPId); if (!isValidAppId) { return false; } var sharedKey = _manager.ValidateKey(APPId); if (isReplayRequest(nonce, requestTimeStamp)) { return false; } byte[] hash = await ComputeHash(req.Content); if (hash != null) { requestContentBase64String = Convert.ToBase64String(hash); } string data = String.Format("{0}{1}{2}{3}{4}{5}", APPId, requestHttpMethod, requestUri, requestTimeStamp, nonce, requestContentBase64String); var secretKeyBytes = Convert.FromBase64String(sharedKey); byte[] signature = Encoding.UTF8.GetBytes(data); using (HMACSHA256 hmac = new HMACSHA256(secretKeyBytes)) { byte[] signatureBytes = hmac.ComputeHash(signature); return (incomingBase64Signature.Equals(Convert.ToBase64String(signatureBytes), StringComparison.Ordinal)); } } private bool isReplayRequest(string nonce, string requestTimeStamp) { if (System.Runtime.Caching.MemoryCache.Default.Contains(nonce)) { return true; } DateTime epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc); TimeSpan currentTs = DateTime.UtcNow - epochStart; var serverTotalSeconds = Convert.ToUInt64(currentTs.TotalSeconds); var requestTotalSeconds = Convert.ToUInt64(requestTimeStamp); if ((serverTotalSeconds - requestTotalSeconds) > requestTimeOutInSeconds) { return true; } System.Runtime.Caching.MemoryCache.Default.Add(nonce, requestTimeStamp, DateTimeOffset.UtcNow.AddSeconds(requestTimeOutInSeconds)); return false; } private static async Task<byte[]> ComputeHash(HttpContent httpContent) { using (MD5 md5 = MD5.Create()) { byte[] hash = null; var content = await httpContent.ReadAsByteArrayAsync(); if (content.Length != 0) { hash = md5.ComputeHash(content); } return hash; } } } public class ResultWithChallenge : IHttpActionResult { private readonly string authenticationScheme = "amx"; private readonly IHttpActionResult next; public ResultWithChallenge(IHttpActionResult next) { this.next = next; } public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) { var response = await next.ExecuteAsync(cancellationToken); if (response.StatusCode == HttpStatusCode.Unauthorized) { response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue(authenticationScheme)); } return response; } } }
Kindly not that the authentication is attribute based.
Thanks in advance
Friday, June 1, 2018 10:32 AM
All replies
-
User1306218145 posted
Please i really need help on this
Friday, June 1, 2018 11:41 AM -
User1120430333 posted
Please i really need help on this
Not everything is unit testable. Not everything is considered a unit test.
https://www.artima.com/weblogs/viewpost.jsp?thread=126923
Maybe, you need to try and do a integration test.
Friday, June 1, 2018 2:52 PM