/// <summary>
        /// Verifies that the signature header matches that of the actual body.
        /// </summary>
        protected virtual async Task <bool> VerifySignature(string id, HttpRequestMessage request)
        {
            string secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

            // Get the expected hash from the signature header
            string signatureHeaderValue = GetRequestHeader(request, SignatureHeaderName);

            byte[] expectedHash;
            try
            {
                expectedHash = EncodingUtilities.FromHex(signatureHeaderValue);
            }
            catch (Exception ex)
            {
                string msg = string.Format(CultureInfo.CurrentCulture, InstagramReceiverResources.Receiver_BadHeaderEncoding, SignatureHeaderName);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(msg, ex);
                HttpResponseMessage invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                throw new HttpResponseException(invalidEncoding);
            }

            // Get the actual hash of the request body concatenated with the request URI
            byte[] actualHash;
            byte[] secret = Encoding.UTF8.GetBytes(secretKey);
            using (var hasher = new HMACSHA1(secret))
            {
                byte[] data = await request.Content.ReadAsByteArrayAsync();

                actualHash = hasher.ComputeHash(data);
            }

            // Now verify that the provided hash matches the expected hash.
            return(WebHookReceiver.SecretEqual(expectedHash, actualHash));
        }
Beispiel #2
0
 public DropboxWebHookReceiverTests()
 {
     byte[] secret = Encoding.UTF8.GetBytes(TestSecret);
     using (var hasher = new HMACSHA256(secret))
     {
         byte[] data     = Encoding.UTF8.GetBytes(TestContent);
         byte[] testHash = hasher.ComputeHash(data);
         _testSignature = EncodingUtilities.ToHex(testHash);
     }
 }
 public TrelloWebHookReceiverTests()
 {
     byte[] secret = Encoding.UTF8.GetBytes(TestSecret);
     using (var hasher = new HMACSHA1(secret))
     {
         byte[] data       = Encoding.UTF8.GetBytes(TestContent);
         byte[] requestUri = Encoding.UTF8.GetBytes(TestAddress);
         byte[] combo      = new byte[data.Length + requestUri.Length];
         Buffer.BlockCopy(data, 0, combo, 0, data.Length);
         Buffer.BlockCopy(requestUri, 0, combo, data.Length, requestUri.Length);
         byte[] testHash = hasher.ComputeHash(combo);
         _signature = EncodingUtilities.ToBase64(testHash, uriSafe: false);
     }
 }
Beispiel #4
0
        private static string GetSignatureHeader(string content)
        {
            var secret = Encoding.UTF8.GetBytes(TestSecret);

            using (var hasher = new HMACSHA256(secret))
            {
                var fullContent = $"{TestTimestamp}.{content}";
                var data        = Encoding.UTF8.GetBytes(fullContent);
                var testHash    = hasher.ComputeHash(data);
                var signature   = EncodingUtilities.ToHex(testHash);

                return($"  {StripeWebHookReceiver.TimestampKey}={TestTimestamp},  " +
                       $"{StripeWebHookReceiver.SignatureKey}={signature}  ");
            }
        }
        /// <summary>
        /// Verifies that the signature header matches that of the actual body.
        /// </summary>
        protected virtual async Task VerifySignature(string id, HttpRequestMessage request)
        {
            var secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

            // Get the expected hash from the signature header
            var header = GetRequestHeader(request, SignatureHeaderName);
            var values = header.SplitAndTrim('=');

            if (values.Length != 2 || !string.Equals(values[0], SignatureHeaderKey, StringComparison.OrdinalIgnoreCase))
            {
                var message = string.Format(CultureInfo.CurrentCulture, GitHubReceiverResources.Receiver_BadHeaderValue, SignatureHeaderName, SignatureHeaderKey, "<value>");
                request.GetConfiguration().DependencyResolver.GetLogger().Error(message);
                var invalidHeader = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                throw new HttpResponseException(invalidHeader);
            }

            byte[] expectedHash;
            try
            {
                expectedHash = EncodingUtilities.FromHex(values[1]);
            }
            catch (Exception ex)
            {
                var message = string.Format(CultureInfo.CurrentCulture, GitHubReceiverResources.Receiver_BadHeaderEncoding, SignatureHeaderName);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(message, ex);
                var invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                throw new HttpResponseException(invalidEncoding);
            }

            // Get the actual hash of the request body
            byte[] actualHash;
            var    secret = Encoding.UTF8.GetBytes(secretKey);

            using (var hasher = new HMACSHA1(secret))
            {
                var data = await request.Content.ReadAsByteArrayAsync();

                actualHash = hasher.ComputeHash(data);
            }

            // Now verify that the provided hash matches the expected hash.
            if (!WebHookReceiver.SecretEqual(expectedHash, actualHash))
            {
                var badSignature = CreateBadSignatureResponse(request, SignatureHeaderName);
                throw new HttpResponseException(badSignature);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Verifies that the signature header matches that of the actual body.
        /// </summary>
        protected virtual async Task <bool> VerifySignature(string id, HttpRequestMessage request)
        {
            // Get the expected hash from the signature and app key headers
            string signatureHeaderValue = GetRequestHeader(request, SignatureHeaderName);
            string keyHeaderValue       = GetRequestHeader(request, KeyHeaderName);

            // Lookup which secret to use based on key header value
            IDictionary <string, string> lookupTable = await GetSecretLookupTable(id, request);

            string secretKey;

            if (!lookupTable.TryGetValue(keyHeaderValue, out secretKey))
            {
                string msg = string.Format(CultureInfo.CurrentCulture, PusherReceiverResources.Receiver_SecretNotFound, KeyHeaderName, keyHeaderValue);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(msg);
                HttpResponseMessage invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                throw new HttpResponseException(invalidEncoding);
            }

            byte[] expectedHash;
            try
            {
                expectedHash = EncodingUtilities.FromHex(signatureHeaderValue);
            }
            catch (Exception ex)
            {
                string msg = string.Format(CultureInfo.CurrentCulture, PusherReceiverResources.Receiver_BadHeaderEncoding, SignatureHeaderName);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(msg, ex);
                HttpResponseMessage invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                throw new HttpResponseException(invalidEncoding);
            }

            // Get the actual hash of the request body
            byte[] actualHash;
            byte[] secret = Encoding.UTF8.GetBytes(secretKey);
            using (var hasher = new HMACSHA256(secret))
            {
                byte[] data = await request.Content.ReadAsByteArrayAsync();

                actualHash = hasher.ComputeHash(data);
            }

            // Now verify that the provided hash matches the expected hash.
            return(WebHookReceiver.SecretEqual(expectedHash, actualHash));
        }
Beispiel #7
0
        public async Task ReceiveAsync_ReturnError_IfPostHasInvalidSignature()
        {
            // Arrange
            Initialize(TestSecret);
            string invalid = EncodingUtilities.ToHex(Encoding.UTF8.GetBytes("你好世界"));

            _postRequest.Headers.Add(DropboxWebHookReceiver.SignatureHeaderName, invalid);

            // Act
            HttpResponseMessage actual = await ReceiverMock.Object.ReceiveAsync(TestId, RequestContext, _postRequest);

            // Assert
            HttpError error = await actual.Content.ReadAsAsync <HttpError>();

            Assert.Equal("The WebHook signature provided by the 'X-Dropbox-Signature' header field does not match the value expected by the 'DropboxWebHookReceiverProxy' receiver. WebHook request is invalid.", error.Message);
            ReceiverMock.Protected()
            .Verify <Task <HttpResponseMessage> >("ExecuteWebHookAsync", Times.Never(), TestId, RequestContext, _postRequest, ItExpr.IsAny <IEnumerable <string> >(), ItExpr.IsAny <object>());
        }
        public async Task ReceiveAsync_Throws_IfPostHasInvalidSignature()
        {
            // Arrange
            Initialize(TestSecret);
            string invalid = EncodingUtilities.ToHex(Encoding.UTF8.GetBytes("invalid"));

            _postRequest.Headers.Add(CustomWebHookReceiver.SignatureHeaderName, "sha256=" + invalid);

            // Act
            HttpResponseException ex = await Assert.ThrowsAsync <HttpResponseException>(() => ReceiverMock.Object.ReceiveAsync(TestId, RequestContext, _postRequest));

            // Assert
            HttpError error = await ex.Response.Content.ReadAsAsync <HttpError>();

            Assert.Equal("The WebHook signature provided by the 'ms-signature' header field does not match the value expected by the 'CustomWebHookReceiverProxy' receiver. WebHook request is invalid.", error.Message);
            ReceiverMock.Protected()
            .Verify <Task <HttpResponseMessage> >("ExecuteWebHookAsync", Times.Never(), TestId, RequestContext, _postRequest, ItExpr.IsAny <IEnumerable <string> >(), ItExpr.IsAny <object>());
        }
Beispiel #9
0
        /// <summary>
        /// Gets the event data for this ID from the authenticated source so that we know that it is valid.
        /// </summary>
        protected virtual async Task <JObject> GetEventDataAsync(HttpRequestMessage request, string id, string notificationId)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (id == null)
            {
                throw new ArgumentNullException("id");
            }
            if (notificationId == null)
            {
                throw new ArgumentNullException("notificationId");
            }

            // Create HTTP request for requesting authoritative event data from Stripe
            string secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

            string             address = string.Format(CultureInfo.InvariantCulture, EventUriTemplate, notificationId);
            HttpRequestMessage req     = new HttpRequestMessage(HttpMethod.Get, address);

            byte[] challenge = Encoding.UTF8.GetBytes(secretKey + ":");
            req.Headers.Authorization = new AuthenticationHeaderValue("Basic", EncodingUtilities.ToBase64(challenge, uriSafe: false));

            using (HttpResponseMessage rsp = await _httpClient.SendAsync(req))
            {
                if (!rsp.IsSuccessStatusCode)
                {
                    string msg = string.Format(CultureInfo.CurrentCulture, StripeReceiverResources.Receiver_BadId, notificationId);
                    request.GetConfiguration().DependencyResolver.GetLogger().Error(msg);
                    HttpResponseMessage badId = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                    throw new HttpResponseException(badId);
                }

                JObject result = await rsp.Content.ReadAsAsync <JObject>();

                return(result);
            }
        }
        /// <summary>
        /// Verifies that the signature header matches that of the actual body.
        /// </summary>
        protected virtual async Task <bool> VerifySignature(HttpRequestMessage request, string id)
        {
            var secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

            // Get the expected hash from the signature header
            var signatureHeaderValue = GetRequestHeader(request, SignatureHeaderName);

            byte[] expectedHash;
            try
            {
                expectedHash = EncodingUtilities.FromBase64(signatureHeaderValue);
            }
            catch (Exception ex)
            {
                var message = string.Format(CultureInfo.CurrentCulture, TrelloResources.Receiver_BadHeaderEncoding, SignatureHeaderName);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(message, ex);
                var invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                throw new HttpResponseException(invalidEncoding);
            }

            // Get the actual hash of the request body concatenated with the request URI
            byte[] actualHash;
            var    secret = Encoding.UTF8.GetBytes(secretKey);

            using (var hasher = new HMACSHA1(secret))
            {
                var data = await request.Content.ReadAsByteArrayAsync();

                var requestUri    = Encoding.UTF8.GetBytes(request.RequestUri.AbsoluteUri);
                var combinedBytes = new byte[data.Length + requestUri.Length];
                Buffer.BlockCopy(data, 0, combinedBytes, 0, data.Length);
                Buffer.BlockCopy(requestUri, 0, combinedBytes, data.Length, requestUri.Length);
                actualHash = hasher.ComputeHash(combinedBytes);
            }

            // Now verify that the provided hash matches the expected hash.
            return(WebHookReceiver.SecretEqual(expectedHash, actualHash));
        }
Beispiel #11
0
        /// <summary>
        /// Adds a SHA 256 signature to the <paramref name="body"/> and adds it to the <paramref name="request"/> as an
        /// HTTP header to the <see cref="HttpRequestMessage"/> along with the entity body.
        /// </summary>
        /// <param name="workItem">The current <see cref="WebHookWorkItem"/>.</param>
        /// <param name="request">The request to add the signature to.</param>
        /// <param name="body">The body to sign and add to the request.</param>
        protected virtual void SignWebHookRequest(WebHookWorkItem workItem, HttpRequestMessage request, JObject body)
        {
            if (workItem == null)
            {
                throw new ArgumentNullException(nameof(workItem));
            }
            if (workItem.WebHook == null)
            {
                string msg = string.Format(CultureInfo.CurrentCulture, CustomResources.Sender_BadWorkItem, this.GetType().Name, "WebHook");
                throw new ArgumentException(msg, "workItem");
            }
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (body == null)
            {
                throw new ArgumentNullException(nameof(body));
            }

            byte[] secret = Encoding.UTF8.GetBytes(workItem.WebHook.Secret);
            using (var hasher = new HMACSHA256(secret))
            {
                string serializedBody = body.ToString();
                request.Content = new StringContent(serializedBody, Encoding.UTF8, "application/json");

                byte[] data        = Encoding.UTF8.GetBytes(serializedBody);
                byte[] sha256      = hasher.ComputeHash(data);
                string headerValue = string.Format(CultureInfo.InvariantCulture, SignatureHeaderValueTemplate, EncodingUtilities.ToHex(sha256));
                request.Headers.Add(SignatureHeaderName, headerValue);
            }
        }
Beispiel #12
0
        /// <summary>
        /// Verifies that the signature header matches that of the actual body.
        /// </summary>
        protected virtual async Task <bool> VerifySignature(HttpRequestMessage request, string id)
        {
            // 1. Ensure configuration for this receiver and id exists.
            var secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

            // 2. Get the timestamp and expected signatures from the signature header. Header is a comma-separated set
            // of key=value pairs.
            var    signatureHeaderValue = GetRequestHeader(request, SignatureHeaderName);
            var    pairs              = signatureHeaderValue.SplitAndTrim(',');
            string timestamp          = null;
            var    expectedSignatures = new List <string>();

            foreach (var pair in pairs)
            {
                var keyValuePair = pair.SplitAndTrim('=');
                if (keyValuePair.Length != 2)
                {
                    var message = string.Format(
                        CultureInfo.CurrentCulture,
                        StripeReceiverResources.Receiver_InvalidHeaderFormat,
                        SignatureHeaderName);
                    request.GetConfiguration().DependencyResolver.GetLogger().Error(message);

                    var invalidHeader = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                    throw new HttpResponseException(invalidHeader);
                }

                if (string.Equals(keyValuePair[0], SignatureKey, StringComparison.OrdinalIgnoreCase))
                {
                    expectedSignatures.Add(keyValuePair[1]);
                }
                else if (string.IsNullOrEmpty(timestamp) &&
                         string.Equals(keyValuePair[0], TimestampKey, StringComparison.OrdinalIgnoreCase))
                {
                    timestamp = keyValuePair[1];
                }
            }

            if (string.IsNullOrEmpty(timestamp) || expectedSignatures.Count == 0)
            {
                var message = string.Format(
                    CultureInfo.CurrentCulture,
                    StripeReceiverResources.Receiver_HeaderMissingValue,
                    SignatureHeaderName,
                    TimestampKey,
                    SignatureKey);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(message);

                var invalidHeader = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                throw new HttpResponseException(invalidHeader);
            }

            // 3. Get the actual hash of the timestamp and request body.
            var secret = Encoding.UTF8.GetBytes(secretKey);
            var prefix = Encoding.UTF8.GetBytes(timestamp + ".");

            byte[] actualHash;
            using (var hasher = new HMACSHA256(secret))
            {
                hasher.TransformBlock(
                    inputBuffer: prefix,
                    inputOffset: 0,
                    inputCount: prefix.Length,
                    outputBuffer: null,
                    outputOffset: 0);

                var data = await request.Content.ReadAsByteArrayAsync();

                actualHash = hasher.ComputeHash(data);
            }

            // 4. Verify that the actual hash matches one of the expected hashes.
            foreach (var expectedSignature in expectedSignatures)
            {
                // While this looks repetitious compared to hex-encoding actualHash (once), a single v1 entry in the
                // header is the normal case. Expect multiple signatures only when rolling secret keys.
                byte[] expectedHash;
                try
                {
                    expectedHash = EncodingUtilities.FromHex(expectedSignature);
                }
                catch (Exception ex)
                {
                    var message = string.Format(
                        CultureInfo.CurrentCulture,
                        StripeReceiverResources.Receiver_BadSignatureEncoding,
                        SignatureHeaderName,
                        SignatureKey);
                    request.GetConfiguration().DependencyResolver.GetLogger().Error(message, ex);

                    var invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                    throw new HttpResponseException(invalidEncoding);
                }

                if (SecretEqual(expectedHash, actualHash))
                {
                    return(true);
                }
            }

            return(false);
        }
Beispiel #13
0
        internal static void SignWebHookRequest(WebHook webHook, HttpRequestMessage request, JObject body)
        {
            byte[] secret = Encoding.UTF8.GetBytes(webHook.Secret);
            using (var hasher = new HMACSHA256(secret))
            {
                string serializedBody = body.ToString();
                request.Content = new StringContent(serializedBody, Encoding.UTF8, "application/json");

                byte[] data        = Encoding.UTF8.GetBytes(serializedBody);
                byte[] sha256      = hasher.ComputeHash(data);
                string headerValue = string.Format(CultureInfo.InvariantCulture, SignatureHeaderValueTemplate, EncodingUtilities.ToHex(sha256));
                request.Headers.Add(SignatureHeaderName, headerValue);
            }
        }