/// <summary> /// MD5 hashes the specified body stream and compares it with the Content-MD5 string. /// </summary> /// <param name="contentMd5">The Content-MD5 string to compare the body hash to.</param> /// <param name="bodyContent">The body to hash and compare.</param> /// <returns><c>true</c> if equal; otherwise, <c>false</c>.</returns> /// <exception cref="ArgumentException">The body content stream does not support seeking or reading.</exception> public bool IsValidContentMd5(string contentMd5, Stream bodyContent) { if (bodyContent == null) { return(string.IsNullOrEmpty(contentMd5)); } if (!bodyContent.CanSeek) { throw new ArgumentException("The body content stream does not support seeking.", nameof(bodyContent)); } if (!bodyContent.CanRead) { throw new ArgumentException("The body content stream does not support reading.", nameof(bodyContent)); } if (string.IsNullOrEmpty(contentMd5)) { return(bodyContent.Length == 0); } string newContentMd5 = HmacSigner.CreateBase64Md5Hash(bodyContent); return(contentMd5 == newContentMd5); }
public void OnAuthorization(AuthorizationContext filterContext) { if (filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)) { return; } IHmacConfiguration configuration = _configurationManager.Get("Example"); IHmacSigner signer = new HmacSigner(configuration, _keyRepository); IHmacValidator validator = new HmacValidator(configuration, signer); HmacValidationResult result = validator.ValidateHttpRequest(filterContext.HttpContext.Request); if (result.ResultCode == HmacValidationResultCode.Ok) { return; } HttpResponseBase response = filterContext.HttpContext.Response; validator.AddWwwAuthenticateHeader(response, configuration.AuthorizationScheme); response.Headers.Add("X-Auth-ErrorCode", result.ResultCode.ToString()); response.StatusCode = (int)HttpStatusCode.Unauthorized; response.Write(result.ErrorMessage); response.End(); }
public void ShouldFailValidationDueToMissingKey() { // Arrange Mock <IHmacKeyRepository> mockKeyRepo = new Mock <IHmacKeyRepository>(); mockKeyRepo.Setup(r => r.GetHmacKeyForUsername(It.IsAny <string>())).Returns((string)null); IHmacConfiguration configuration = CreateConfiguration(); IHmacSigner signer = new HmacSigner(configuration, mockKeyRepo.Object); HmacValidator validator = new HmacValidator(configuration, signer); DateTimeOffset dateTimeOffset = DateTimeOffset.UtcNow.AddMinutes(-3); string dateString = dateTimeOffset.ToString(HmacConstants.DateHeaderFormat, _dateHeaderCulture); HttpRequestBase request = CreateRequest(dateString); HmacSignatureData signatureData = signer.GetSignatureDataFromHttpRequest(request); signatureData.Key = "TestKey"; string signature = signer.CreateSignature(signatureData); request.Headers[HmacConstants.AuthorizationHeaderName] = string.Format( HmacConstants.AuthorizationHeaderFormat, configuration.AuthorizationScheme, signature); // Act HmacValidationResult result = validator.ValidateHttpRequest(request); // Assert Assert.IsNotNull(result); Assert.IsNotNull(result.ErrorMessage); Assert.AreEqual(result.ResultCode, HmacValidationResultCode.KeyMissing); }
public void ShouldCreateCanonicalizedUriString() { // Arrange IHmacConfiguration configuration = new HmacConfiguration { SignatureEncoding = "UTF-8" }; HmacSigner signer = new HmacSigner(configuration, _keyRepository); const string uriString = " HTTP://WWW.EXAMPLE.DOMAIN/Test?Key=Value "; const string expectedUriString = "http://www.example.domain:80/Test?Key=Value"; const string uriString2 = " httpS://WWW.EXAMPLE.DOMAIN:3000/Test?Key=Value "; const string expectedUriString2 = "https://www.example.domain:3000/Test?Key=Value"; const string uriString3 = " TEST://WWW.EXAMPLE.DOMAIN/Test?Key=Value "; const string expectedUriString3 = "test://www.example.domain:-1/Test?Key=Value"; const string relativeUriString = "/Test?Key=Value"; Uri relativeUri = new Uri(relativeUriString, UriKind.Relative); // Act string result1 = signer.CreateCanonicalizedUriString(uriString); string result2 = signer.CreateCanonicalizedUriString(uriString2); string result3 = signer.CreateCanonicalizedUriString(uriString3); string result4 = signer.CreateCanonicalizedUriString(relativeUri); // Assert Assert.AreEqual(expectedUriString, result1); Assert.AreEqual(expectedUriString2, result2); Assert.AreEqual(expectedUriString3, result3); Assert.AreEqual(relativeUriString, result4); }
public void ShouldCreateSignature() { // Arrange IHmacConfiguration configuration = CreateConfiguration(); HmacSigner signer = new HmacSigner(configuration, _keyRepository); HmacSignatureData signatureData = new HmacSignatureData { Key = _keyRepository.Key, HttpMethod = "POST", ContentMd5 = _base64Md5Hash, ContentType = ContentType, Date = "Wed, 30 Dec 2015 12:30:45 GMT", Username = _keyRepository.Username, RequestUri = Url, Headers = new NameValueCollection { { "X-Custom-Test-Header-1", "Test1" }, { "X-Custom-Test-Header-2", "Test2" } } }; const string expectedSignature = "CSDWHwt5sOWkBKS5mSNWrgJaXREQB6CKywVyB/A4IDQ65h3gzR9/Uutug34ikpcW3JlnVyAL+xbu/eNaq99q/Q=="; HmacSignatureData signatureData2 = new HmacSignatureData { Key = _keyRepository.Key }; const string expectedSignature2 = "QwPLzI1RUBRyYerrolY3+4Mzuw8Z07YfxnpP9va2ckH/I7UvdPBMkcaomWOaC5pZym9x+t/BA/2VTP6pjje1DQ=="; // Act string signature = signer.CreateSignature(signatureData); string signature2 = signer.CreateSignature(signatureData2); // Assert Assert.IsNotNull(signature); Assert.AreEqual(expectedSignature, signature); Assert.IsNotNull(signature2); Assert.AreEqual(expectedSignature2, signature2); }
public void ShouldFailValidationDueToMissingDate() { // Arrange IHmacConfiguration configuration = CreateConfiguration(); IHmacSigner signer = new HmacSigner(configuration, _keyRepository); HmacValidator validator = new HmacValidator(configuration, signer); DateTimeOffset dateTimeOffset = DateTimeOffset.UtcNow.AddMinutes(-3); string dateString = dateTimeOffset.ToString(HmacConstants.DateHeaderFormat, _dateHeaderCulture); HttpRequestBase request = CreateRequest(dateString); HmacSignatureData signatureData = signer.GetSignatureDataFromHttpRequest(request); string signature = signer.CreateSignature(signatureData); request.Headers[HmacConstants.AuthorizationHeaderName] = string.Format( HmacConstants.AuthorizationHeaderFormat, configuration.AuthorizationScheme, signature); request.Headers.Remove(HmacConstants.DateHeaderName); // Act HmacValidationResult result = validator.ValidateHttpRequest(request); // Assert Assert.IsNotNull(result); Assert.IsNotNull(result.ErrorMessage); Assert.AreEqual(result.ResultCode, HmacValidationResultCode.DateMissing); }
public void ShouldFailToValidateContentMd5() { // Arrange IHmacConfiguration configuration = CreateConfiguration(); IHmacSigner signer = new HmacSigner(configuration, _keyRepository); HmacValidator validator = new HmacValidator(configuration, signer); const string incorrectBody = Body + "Modified"; byte[] incorrectBodyBytes = Encoding.UTF8.GetBytes(incorrectBody); Stream incorrectBodyStream = new MemoryStream(incorrectBodyBytes); // Act bool stringIsValidBase64 = validator.IsValidContentMd5(_base64Md5Hash, incorrectBody, Encoding.UTF8); bool stringIsValidByteArray = validator.IsValidContentMd5(_md5Hash, incorrectBody, Encoding.UTF8); bool bytesAreValidBase64 = validator.IsValidContentMd5(_base64Md5Hash, incorrectBodyBytes); bool bytesAreValidByteArray = validator.IsValidContentMd5(_md5Hash, incorrectBodyBytes); bool streamIsValidBase64 = validator.IsValidContentMd5(_base64Md5Hash, incorrectBodyStream); bool streamIsValidByteArray = validator.IsValidContentMd5(_md5Hash, incorrectBodyStream); incorrectBodyStream.Dispose(); // Assert Assert.IsFalse(stringIsValidBase64); Assert.IsFalse(stringIsValidByteArray); Assert.IsFalse(bytesAreValidBase64); Assert.IsFalse(bytesAreValidByteArray); Assert.IsFalse(streamIsValidBase64); Assert.IsFalse(streamIsValidByteArray); }
/// <summary> /// Validates an entire HTTP request message. /// </summary> /// <param name="request">The HTTP request to validate.</param> /// <returns>The result of the validation as a <see cref="HmacValidationResult"/> object.</returns> /// <remarks> /// The following validation logic is used: /// - The Date header must be present if a maximum request age is configured, but cannot be older than the configured value; /// - The username header must be present when the user header name has been configured; /// - The key must be found for the request; /// - The Authorization header must be present, must have the correct authorization scheme and must contain a signature; /// - The signature created from the extracted signature data must match the one on the Authorization header. /// /// In case the request contains a body: /// - The Content-MD5 header value must match an MD5 hash of the body, if Content-MD5 validation was enabled in the configuration. /// </remarks> /// <exception cref="ArgumentNullException">The request is null.</exception> /// <exception cref="HmacConfigurationException">One or more of the configuration parameters are invalid.</exception> public virtual HmacValidationResult ValidateHttpRequest(HttpRequestMessage request) { if (request == null) { throw new ArgumentNullException(nameof(request), "The request cannot be null."); } HmacRequestWrapper requestWrapper = new HmacRequestWrapper(request); HmacSignatureData signatureData = HmacSigner.GetSignatureDataFromHttpRequest(request); return(ValidateHttpRequest(requestWrapper, signatureData)); }
/// <summary> /// MD5 hashes the specified body byte array and compares it with the Content-MD5 string. /// </summary> /// <param name="contentMd5">The Content-MD5 string to compare the body hash to.</param> /// <param name="bodyContent">The body to hash and compare.</param> /// <returns><c>true</c> if equal; otherwise, <c>false</c>.</returns> public bool IsValidContentMd5(string contentMd5, byte[] bodyContent) { if (string.IsNullOrEmpty(contentMd5)) { return(bodyContent.IsNullOrEmpty()); } if (bodyContent.IsNullOrEmpty()) { return(false); } string newContentMd5 = HmacSigner.CreateBase64Md5Hash(bodyContent); return(contentMd5 == newContentMd5); }
public void ShouldSetAuthorizationHeader() { // Arrange const string signature = "TEST_SIGNATURE"; IHmacConfiguration configuration = CreateConfiguration(); HttpRequestBase request = CreateRequest(string.Empty); HmacSigner signer = new HmacSigner(configuration, _keyRepository); // Act signer.SetAuthorizationHeader(request, signature); string headerValue = request.Headers["Authorization"]; // Assert Assert.IsNotNull(headerValue); Assert.AreEqual("HMAC TEST_SIGNATURE", headerValue); }
public void ShouldAddWwwAuthenticateHeader() { // Arrange const string headerValue = "HMAC_TEST"; IHmacConfiguration configuration = CreateConfiguration(); HttpResponseBase response = CreateResponse(string.Empty); HmacSigner signer = new HmacSigner(configuration, _keyRepository); HmacValidator validator = new HmacValidator(configuration, signer); // Act validator.AddWwwAuthenticateHeader(response, headerValue); string actualHeaderValue = response.Headers["WWW-Authenticate"]; // Assert Assert.IsNotNull(actualHeaderValue); Assert.AreEqual(headerValue, actualHeaderValue); }
public void ShouldFailToValidateSignature() { // Arrange IHmacConfiguration configuration = CreateConfiguration(); IHmacSigner signer = new HmacSigner(configuration, _keyRepository); HmacValidator validator = new HmacValidator(configuration, signer); const string signatureString1 = "SIGNATURE_STRING"; const string signatureString2 = "SIGNATURE_STRING_DIFFERENT"; byte[] signatureBytes1 = Encoding.UTF8.GetBytes(signatureString1); byte[] signatureBytes2 = Encoding.UTF8.GetBytes(signatureString2); // Act bool isValidString = validator.IsValidSignature(signatureString1, signatureString2); bool isValidByteArray = validator.IsValidSignature(signatureBytes1, signatureBytes2); // Assert Assert.IsFalse(isValidString); Assert.IsFalse(isValidByteArray); }
public void ShouldFailToValidateRequestDate() { // Arrange IHmacConfiguration configuration = CreateConfiguration(); IHmacSigner signer = new HmacSigner(configuration, _keyRepository); HmacValidator validator = new HmacValidator(configuration, signer); DateTimeOffset dateTimeOffset = DateTimeOffset.UtcNow.AddMinutes(-6); string dateString = dateTimeOffset.ToString(HmacConstants.DateHeaderFormat, _dateHeaderCulture); DateTime dateTime = dateTimeOffset.UtcDateTime; // Act bool isValidDateTimeOffset = validator.IsValidRequestDate(dateTimeOffset); bool isValidDateString = validator.IsValidRequestDate(dateString, HmacConstants.DateHeaderFormat); bool isValidDateTime = validator.IsValidRequestDate(dateTime); // Assert Assert.IsFalse(isValidDateString); Assert.IsFalse(isValidDateTime); Assert.IsFalse(isValidDateTimeOffset); }
public void ShouldFailValidationDueToInvalidAuthorization() { // Arrange IHmacConfiguration configuration = CreateConfiguration(); IHmacSigner signer = new HmacSigner(configuration, _keyRepository); HmacValidator validator = new HmacValidator(configuration, signer); DateTimeOffset dateTimeOffset = DateTimeOffset.UtcNow.AddMinutes(-3); string dateString = dateTimeOffset.ToString(HmacConstants.DateHeaderFormat, _dateHeaderCulture); HttpRequestBase request = CreateRequest(dateString); request.Headers[HmacConstants.AuthorizationHeaderName] = "blahblah"; // Act HmacValidationResult result = validator.ValidateHttpRequest(request); // Assert Assert.IsNotNull(result); Assert.IsNotNull(result.ErrorMessage); Assert.AreEqual(result.ResultCode, HmacValidationResultCode.AuthorizationInvalid); }
public void ShouldCreateBase64Md5Hash() { // Arrange IHmacConfiguration configuration = new HmacConfiguration { SignatureEncoding = "UTF-8" }; HmacSigner signer = new HmacSigner(configuration, _keyRepository); // Act string base64Md5HashFromString = signer.CreateBase64Md5Hash(Body, Encoding.UTF8); string base64Md5HashFromBytes = signer.CreateBase64Md5Hash(_bodyBytes); string base64Md5HashFromStream = signer.CreateBase64Md5Hash(_bodyStream); // Assert Assert.IsNotNull(base64Md5HashFromString); Assert.AreEqual(_base64Md5Hash, base64Md5HashFromString); Assert.IsNotNull(base64Md5HashFromBytes); Assert.AreEqual(_base64Md5Hash, base64Md5HashFromBytes); Assert.IsNotNull(base64Md5HashFromStream); Assert.AreEqual(_base64Md5Hash, base64Md5HashFromStream); }
public async Task PostWorkflowTest_DuplicateKeys_On_KeyData() { // Arrange var client = _Factory.CreateClient(); await using var inputStream = Assembly.GetExecutingAssembly().GetEmbeddedResourceStream("Resources.payload-duplicate-keys-keydata.json"); var data = inputStream.ToArray(); var signature = HttpUtility.UrlEncode(HmacSigner.Sign(_Key, data)); var content = new ByteArrayContent(data); content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); // Act var result = await client.PostAsync($"v1/postkeys?sig={signature}", content); // Assert var items = await _DbContext.TemporaryExposureKeys.ToListAsync(); Assert.AreEqual(0, items.Count); }
/// <summary> /// MD5 hashes the specified body and compares it with the Content-MD5 string. /// </summary> /// <param name="contentMd5">The Content-MD5 string to compare the body hash to.</param> /// <param name="bodyContent">The body to hash and compare.</param> /// <param name="encoding">The encoding to use when converting the body content into bytes.</param> /// <returns><c>true</c> if equal; otherwise, <c>false</c>.</returns> /// <exception cref="ArgumentNullException">The encoding is null.</exception> public bool IsValidContentMd5(string contentMd5, string bodyContent, Encoding encoding) { if (encoding == null) { throw new ArgumentNullException(nameof(encoding), "The encoding cannot be null."); } if (string.IsNullOrEmpty(contentMd5)) { return(string.IsNullOrEmpty(bodyContent)); } if (string.IsNullOrEmpty(bodyContent)) { return(false); } string newContentMd5 = HmacSigner.CreateBase64Md5Hash(bodyContent, encoding); return(contentMd5 == newContentMd5); }
public async Task PostWorkflowTest_InvalidSignature() { // Arrange var client = _Factory.CreateClient(); await using var inputStream = Assembly.GetExecutingAssembly().GetEmbeddedResourceStream("Resources.payload.json"); var data = inputStream.ToArray(); var signature = HttpUtility.UrlEncode(HmacSigner.Sign(new byte[] { 0 }, data)); var content = new ByteArrayContent(data); content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); // Act var result = await client.PostAsync($"v1/postkeys?sig={signature}", content); // Assert var items = await _DbContext.TemporaryExposureKeys.ToListAsync(); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Empty(items); }
public void ShouldCreateCanonicalizedHeaderString() { // Arrange IHmacConfiguration configuration = new HmacConfiguration { SignatureEncoding = "UTF-8", SignatureDataSeparator = "\n" }; HmacSigner signer = new HmacSigner(configuration, _keyRepository); NameValueCollection headers = new NameValueCollection { { " X-Test-Header-1 ", " Value2 " }, { " X-Test-Header-1 ", " Value4" }, { "X-Test-Header-2", "value3" }, { " x-test-headeR-1 ", "Value1" } }; const string expectedHeaderString = "x-test-header-1:Value2,Value4,Value1\nx-test-header-2:value3"; // Act string headerString = signer.CreateCanonicalizedHeadersString(headers); // Assert Assert.IsNotNull(headerString); Assert.AreEqual(expectedHeaderString, headerString); }
public void ShouldGetSignatureDataFromHttpRequest() { // Arrange IHmacConfiguration configuration = CreateConfiguration(); string dateString = CreateHttpDateString(); HttpRequestBase request = CreateRequest(dateString); HmacSigner signer = new HmacSigner(configuration, _keyRepository); // Act HmacSignatureData signatureData = signer.GetSignatureDataFromHttpRequest(request); // Assert Assert.IsNotNull(signatureData); Assert.AreEqual(_keyRepository.Key, signatureData.Key); Assert.AreEqual(request.HttpMethod, signatureData.HttpMethod); Assert.AreEqual(_base64Md5Hash, signatureData.ContentMd5); Assert.AreEqual(ContentType, signatureData.ContentType); Assert.AreEqual(dateString, signatureData.Date); Assert.AreEqual(_keyRepository.Username, signatureData.Username); Assert.AreEqual(Url, signatureData.RequestUri); Assert.IsNotNull(signatureData.Headers); Assert.IsTrue(signatureData.Headers.Count > 0); }
public void ShouldValidateContentMd5() { // Arrange IHmacConfiguration configuration = CreateConfiguration(); IHmacSigner signer = new HmacSigner(configuration, _keyRepository); HmacValidator validator = new HmacValidator(configuration, signer); // Act bool stringIsValidBase64 = validator.IsValidContentMd5(_base64Md5Hash, Body, Encoding.UTF8); bool stringIsValidByteArray = validator.IsValidContentMd5(_md5Hash, Body, Encoding.UTF8); bool bytesAreValidBase64 = validator.IsValidContentMd5(_base64Md5Hash, _bodyBytes); bool bytesAreValidByteArray = validator.IsValidContentMd5(_md5Hash, _bodyBytes); bool streamIsValidBase64 = validator.IsValidContentMd5(_base64Md5Hash, _bodyStream); bool streamIsValidByteArray = validator.IsValidContentMd5(_md5Hash, _bodyStream); // Assert Assert.IsTrue(stringIsValidBase64); Assert.IsTrue(stringIsValidByteArray); Assert.IsTrue(bytesAreValidBase64); Assert.IsTrue(bytesAreValidByteArray); Assert.IsTrue(streamIsValidBase64); Assert.IsTrue(streamIsValidByteArray); }
public async Task PostWorkflowTest(string file, int keyCount, int mm, int dd) { _fakeTimeProvider.Value = new DateTime(2020, mm, dd, 0, 0, 0, DateTimeKind.Utc); // Arrange var client = _factory.CreateClient(); await using var inputStream = Assembly.GetExecutingAssembly().GetEmbeddedResourceStream(file); var data = inputStream.ToArray(); var args = new StandardJsonSerializer().Deserialize <PostTeksArgs>(Encoding.UTF8.GetString(data)); await WriteBucket(Convert.FromBase64String(args.BucketId)); var tekDates = args.Keys .OrderBy(x => x.RollingStartNumber) .Select(x => new { x, Date = x.RollingStartNumber.FromRollingStartNumber() }); foreach (var i in tekDates) { Trace.WriteLine($"RSN:{i.x.RollingStartNumber} Date:{i.Date:yyyy-MM-dd}."); } var signature = HttpUtility.UrlEncode(HmacSigner.Sign(new byte[32], data)); var content = new ByteArrayContent(data); content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); // Act var result = await client.PostAsync($"v1/postkeys?sig={signature}", content); // Assert var items = await _workflowDbProvider.CreateNew().TemporaryExposureKeys.ToListAsync(); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(keyCount, items.Count); }
public void ShouldCreateMd5Hash() { // Arrange IHmacConfiguration configuration = new HmacConfiguration { SignatureEncoding = "UTF-8" }; HmacSigner signer = new HmacSigner(configuration, _keyRepository); // Act byte[] md5HashFromString = signer.CreateMd5Hash(Body, Encoding.UTF8); byte[] md5HashFromBytes = signer.CreateMd5Hash(_bodyBytes); byte[] md5HashFromStrean = signer.CreateMd5Hash(_bodyStream); // Assert Assert.IsNotNull(md5HashFromString); Assert.AreEqual(_md5Hash.Length, md5HashFromString.Length); Assert.IsTrue(_md5Hash.SequenceEqual(md5HashFromString)); Assert.IsNotNull(md5HashFromBytes); Assert.AreEqual(_md5Hash.Length, md5HashFromBytes.Length); Assert.IsTrue(_md5Hash.SequenceEqual(md5HashFromBytes)); Assert.IsNotNull(md5HashFromStrean); Assert.AreEqual(_md5Hash.Length, md5HashFromStrean.Length); Assert.IsTrue(_md5Hash.SequenceEqual(md5HashFromStrean)); }
private HmacValidationResult ValidateHttpRequest(HmacRequestWrapper request, HmacSignatureData signatureData) { if (string.IsNullOrEmpty(HmacConfiguration.AuthorizationScheme)) { throw new HmacConfigurationException("The AuthorizationScheme cannot be null or empty."); } // Note: the Content-MD5 and Content-Type headers are only required if the request contains a body // If configured, the request date is validated to prevent replay attacks if (HmacConfiguration.MaxRequestAge.HasValue) { if (!request.Date.HasValue) { return(new HmacValidationResult(HmacValidationResultCode.DateMissing, "The request date was not found.")); } if (!IsValidRequestDate(request.Date.Value)) { return(new HmacValidationResult(HmacValidationResultCode.DateInvalid, "The request date is invalid.")); } } // The username is always required when the header has been configured if (!string.IsNullOrEmpty(HmacConfiguration.UserHeaderName) && string.IsNullOrEmpty(signatureData.Username)) { return(new HmacValidationResult(HmacValidationResultCode.UsernameMissing, "The username is required but was not found.")); } // The key must be found if (string.IsNullOrEmpty(signatureData.Key)) { return(new HmacValidationResult(HmacValidationResultCode.KeyMissing, "The key was not found.")); } // If configured, an MD5 hash of the body is generated and compared with the Content-MD5 header value to check if the body hasn't been altered if (HmacConfiguration.ValidateContentMd5 && !IsValidContentMd5(signatureData.ContentMd5, request.Content)) { if (string.IsNullOrEmpty(signatureData.ContentMd5)) { return(new HmacValidationResult(HmacValidationResultCode.BodyHashMissing, "The MD5 body hash was not found.")); } return(new HmacValidationResult(HmacValidationResultCode.BodyHashMismatch, "The body content differs.")); } // The Authorization header is always required and should contain the scheme and signature IList <string> authorizations = request.Headers.GetValues(HmacConstants.AuthorizationHeaderName); string authorization; if (authorizations == null || string.IsNullOrEmpty(authorization = authorizations.FirstOrDefault())) { return(new HmacValidationResult(HmacValidationResultCode.AuthorizationMissing, "The signature was not found.")); } string[] authorizationParts = authorization.Split(' '); if (authorizationParts.Length < 2 || authorizationParts[0] != HmacConfiguration.AuthorizationScheme) { return(new HmacValidationResult(HmacValidationResultCode.AuthorizationInvalid, "The signature was not correctly specified.")); } // Finally, the signature from the Authorization header should match the newly created signature string signature = authorizationParts[1]; string newSignature = HmacSigner.CreateSignature(signatureData); if (!IsValidSignature(signature, newSignature)) { return(new HmacValidationResult(HmacValidationResultCode.SignatureMismatch, "The signature does not match.")); } return(HmacValidationResult.Ok); }