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 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); }
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); }