Example #1
0
        protected virtual async Task EnsureValidCode(HttpRequestMessage request, string id)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            EnsureSecureConnection(request);

            NameValueCollection queryParameters = request.RequestUri.ParseQueryString();
            string code = queryParameters[CodeQueryParameter];

            if (string.IsNullOrEmpty(code))
            {
                string msg = string.Format(CultureInfo.CurrentCulture, ReceiverResources.Receiver_NoCode, CodeQueryParameter);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(msg);
                HttpResponseMessage noCode = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                throw new HttpResponseException(noCode);
            }

            string secretKey = await this.GetReceiverConfig(request, Name, id, CodeMinLength, CodeMaxLength);

            if (!WebHookReceiver.SecretEqual(code, secretKey))
            {
                string msg = string.Format(CultureInfo.CurrentCulture, ReceiverResources.Receiver_BadCode, CodeQueryParameter);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(msg);
                HttpResponseMessage invalidCode = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                throw new HttpResponseException(invalidCode);
            }
        }
        /// <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));
        }
Example #3
0
        /// <inheritdoc />
        public override async Task <HttpResponseMessage> ReceiveAsync(string id, HttpRequestContext context, HttpRequestMessage request)
        {
            if (id == null)
            {
                throw new ArgumentNullException("id");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            if (request.Method == HttpMethod.Post)
            {
                EnsureSecureConnection(request);

                // Read the request entity body
                NameValueCollection data = await ReadAsFormDataAsync(request);

                // Verify that the token is correct
                string token     = data[TokenParameter];
                string secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

                if (!WebHookReceiver.SecretEqual(token, secretKey))
                {
                    string msg = string.Format(CultureInfo.CurrentCulture, SlackReceiverResources.Receiver_BadToken, TokenParameter);
                    context.Configuration.DependencyResolver.GetLogger().Error(msg);
                    HttpResponseMessage invalidCode = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                    return(invalidCode);
                }

                // Get the action
                string action = data[ActionParameter];
                if (string.IsNullOrEmpty(action))
                {
                    string msg = string.Format(CultureInfo.CurrentCulture, SlackReceiverResources.Receiver_BadBody, ActionParameter);
                    context.Configuration.DependencyResolver.GetLogger().Error(msg);
                    HttpResponseMessage badType = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                    return(badType);
                }

                // Get the subtext by removing the trigger word
                string text = data[TextParameter];
                data[SubtextParameter] = GetSubtext(action, text);

                // Call registered handlers
                return(await ExecuteWebHookAsync(id, context, request, new string[] { action }, data));
            }
            else
            {
                return(CreateBadMethodResponse(request));
            }
        }
Example #4
0
        public void SecretEqual_ComparesStringsCorrectly(string inputA, string inputB, bool expected)
        {
            // Arrange
            Initialize(TestSecret);

            // Act
            bool actual = WebHookReceiver.SecretEqual(inputA, inputB);

            // Assert
            Assert.Equal(expected, actual);
        }
Example #5
0
        public void SecretEqual_ComparesByteArraysCorrectly(byte[] inputA, byte[] inputB, bool expected)
        {
            // Arrange
            Initialize(TestSecret);

            // Act
            var actual = WebHookReceiver.SecretEqual(inputA, inputB);

            // Assert
            Assert.Equal(expected, actual);
        }
        /// <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);
            }
        }
Example #7
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));
        }
        /// <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));
        }
        /// <inheritdoc />
        public override async Task <HttpResponseMessage> ReceiveAsync(string id, HttpRequestContext context, HttpRequestMessage request)
        {
            if (id == null)
            {
                throw new ArgumentNullException(nameof(id));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (request.Method == HttpMethod.Post)
            {
                EnsureSecureConnection(request);

                // Read the request entity body
                var data = await ReadAsXmlAsync(request);

                var notifications = new SalesforceNotifications(data);

                // Ensure that the organization ID matches the expected value.
                var orgId  = GetShortOrgId(notifications.OrganizationId);
                var secret = await GetReceiverConfig(request, ReceiverConfigName, id, 15, 18);

                var secretKey = GetShortOrgId(secret);
                if (!WebHookReceiver.SecretEqual(orgId, secretKey))
                {
                    var message = string.Format(CultureInfo.CurrentCulture, SalesforceReceiverResources.Receiver_BadValue, "OrganizationId");
                    context.Configuration.DependencyResolver.GetLogger().Error(message);
                    var fault     = string.Format(CultureInfo.InvariantCulture, ReadResource("Microsoft.AspNet.WebHooks.Messages.FaultResponse.xml"), message);
                    var invalidId = GetXmlResponse(request, HttpStatusCode.BadRequest, fault);
                    return(invalidId);
                }

                // Get the action
                var action = notifications.ActionId;
                if (string.IsNullOrEmpty(action))
                {
                    var message = string.Format(CultureInfo.CurrentCulture, SalesforceReceiverResources.Receiver_BadBody, "ActionId");
                    context.Configuration.DependencyResolver.GetLogger().Error(message);
                    var fault   = string.Format(CultureInfo.InvariantCulture, ReadResource("Microsoft.AspNet.WebHooks.Messages.FaultResponse.xml"), message);
                    var badType = GetXmlResponse(request, HttpStatusCode.BadRequest, fault);
                    return(badType);
                }

                // Call registered handlers
                var response = await ExecuteWebHookAsync(id, context, request, new string[] { action }, notifications);

                // Add SOAP response content if not already present or isn't XML. Ignore current (e.g. JSON) content.
                if (response?.Content == null || !response.Content.IsXml())
                {
                    // Ignore redirects because SOAP 1.1 doesn't mention them and they're corner cases in SOAP.
                    var statusCode = response?.StatusCode ?? HttpStatusCode.OK;
                    if (statusCode >= (HttpStatusCode)200 && statusCode < (HttpStatusCode)300)
                    {
                        var success = ReadResource("Microsoft.AspNet.WebHooks.Messages.NotificationResponse.xml");
                        response = GetXmlResponse(request, statusCode, success);
                    }
                    else
                    {
                        // Move failure information into a SOAP fault response. Fault contains code soapenv:Client and
                        // that must be transmitted with HTTP status 400, Bad Request according to SOAP 1.2 (mixing
                        // that sensible choice into this SOAP 1.1 implementation).
                        var resource    = ReadResource("Microsoft.AspNet.WebHooks.Messages.FaultResponse.xml");
                        var faultString = string.Format(
                            CultureInfo.CurrentCulture,
                            SalesforceReceiverResources.Receiver_HandlerFailed,
                            statusCode,
                            response.ReasonPhrase);

                        var failure = string.Format(CultureInfo.InvariantCulture, resource, faultString);
                        response = GetXmlResponse(request, HttpStatusCode.BadRequest, failure);
                    }
                }

                return(response);
            }
            else
            {
                return(CreateBadMethodResponse(request));
            }
        }
        /// <inheritdoc />
        public override async Task <HttpResponseMessage> ReceiveAsync(string id, HttpRequestContext context, HttpRequestMessage request)
        {
            if (id == null)
            {
                throw new ArgumentNullException(nameof(id));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (request.Method == HttpMethod.Post)
            {
                EnsureSecureConnection(request);

                // Read the request entity body
                var data = await ReadAsFormDataAsync(request);

                // Verify that the token is correct
                var token     = data[TokenParameter];
                var secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

                if (!WebHookReceiver.SecretEqual(token, secretKey))
                {
                    var message = string.Format(CultureInfo.CurrentCulture, SlackReceiverResources.Receiver_BadToken, TokenParameter);
                    context.Configuration.DependencyResolver.GetLogger().Error(message);
                    var invalidCode = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                    return(invalidCode);
                }

                // Get the action by looking for either trigger_word or command parameter
                var action = string.Empty;
                if (data[TriggerParameter] != null)
                {
                    // Trigger parameter was supplied
                    // Get the subtext by removing the trigger word
                    action = data[TriggerParameter];
                    var text = data[TextParameter];
                    data[SubtextParameter] = GetSubtext(action, text);
                }
                else if (data[CommandParameter] != null)
                {
                    // Command parameter was supplied
                    action = data[CommandParameter];
                }
                else
                {
                    // Trigger was omitted as optional
                    // Set the subtext to the full text
                    action = data[TextParameter];
                    data[SubtextParameter] = data[TextParameter];
                }

                if (string.IsNullOrEmpty(action))
                {
                    var message = string.Format(CultureInfo.CurrentCulture, SlackReceiverResources.Receiver_BadBody, CommandParameter, TriggerParameter);
                    context.Configuration.DependencyResolver.GetLogger().Error(message);
                    var badType = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                    return(badType);
                }

                // Call registered handlers
                return(await ExecuteWebHookAsync(id, context, request, new string[] { action }, data));
            }
            else
            {
                return(CreateBadMethodResponse(request));
            }
        }
Example #11
0
        /// <inheritdoc />
        public override async Task <HttpResponseMessage> ReceiveAsync(string id, HttpRequestContext context, HttpRequestMessage request)
        {
            if (id == null)
            {
                throw new ArgumentNullException(nameof(id));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (request.Method == HttpMethod.Post)
            {
                EnsureSecureConnection(request);

                // Read the request entity body
                var data = await ReadAsXmlAsync(request);

                var notifications = new SalesforceNotifications(data);

                // Ensure that the organization ID matches the expected value.
                var orgId  = GetShortOrgId(notifications.OrganizationId);
                var secret = await GetReceiverConfig(request, ReceiverConfigName, id, 15, 18);

                var secretKey = GetShortOrgId(secret);
                if (!WebHookReceiver.SecretEqual(orgId, secretKey))
                {
                    var message = string.Format(CultureInfo.CurrentCulture, SalesforceReceiverResources.Receiver_BadValue, "OrganizationId");
                    context.Configuration.DependencyResolver.GetLogger().Error(message);
                    var fault     = string.Format(CultureInfo.InvariantCulture, ReadResource("Microsoft.AspNet.WebHooks.Messages.FaultResponse.xml"), message);
                    var invalidId = GetXmlResponse(request, HttpStatusCode.BadRequest, fault);
                    return(invalidId);
                }

                // Get the action
                var action = notifications.ActionId;
                if (string.IsNullOrEmpty(action))
                {
                    var message = string.Format(CultureInfo.CurrentCulture, SalesforceReceiverResources.Receiver_BadBody, "ActionId");
                    context.Configuration.DependencyResolver.GetLogger().Error(message);
                    var fault   = string.Format(CultureInfo.InvariantCulture, ReadResource("Microsoft.AspNet.WebHooks.Messages.FaultResponse.xml"), message);
                    var badType = GetXmlResponse(request, HttpStatusCode.BadRequest, fault);
                    return(badType);
                }

                // Call registered handlers
                var response = await ExecuteWebHookAsync(id, context, request, new string[] { action }, notifications);

                // Add SOAP response if not already present
                if (response == null || response.Content == null || !response.Content.IsXml())
                {
                    var success = ReadResource("Microsoft.AspNet.WebHooks.Messages.NotificationResponse.xml");
                    response = GetXmlResponse(request, HttpStatusCode.OK, success);
                }
                return(response);
            }
            else
            {
                return(CreateBadMethodResponse(request));
            }
        }
Example #12
0
        /// <inheritdoc />
        public override async Task <HttpResponseMessage> ReceiveAsync(string id, HttpRequestContext context, HttpRequestMessage request)
        {
            if (id == null)
            {
                throw new ArgumentNullException("id");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            if (request.Method == HttpMethod.Post)
            {
                EnsureSecureConnection(request);

                // Read the request entity body
                XElement data = await ReadAsXmlAsync(request);

                SalesforceNotifications notifications = new SalesforceNotifications(data);

                // Ensure that the organization ID matches the expected value.
                string orgId  = GetShortOrgId(notifications.OrganizationId);
                string secret = await GetReceiverConfig(request, ReceiverConfigName, id, 15, 18);

                string secretKey = GetShortOrgId(secret);
                if (!WebHookReceiver.SecretEqual(orgId, secretKey))
                {
                    string msg = string.Format(CultureInfo.CurrentCulture, SalesforceReceiverResources.Receiver_BadValue, "OrganizationId");
                    context.Configuration.DependencyResolver.GetLogger().Error(msg);
                    HttpResponseMessage invalidId = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                    return(invalidId);
                }

                // Get the action
                string action = notifications.ActionId;
                if (string.IsNullOrEmpty(action))
                {
                    string msg = string.Format(CultureInfo.CurrentCulture, SalesforceReceiverResources.Receiver_BadBody, "ActionId");
                    context.Configuration.DependencyResolver.GetLogger().Error(msg);
                    HttpResponseMessage badType = request.CreateErrorResponse(HttpStatusCode.BadRequest, msg);
                    return(badType);
                }

                // Call registered handlers
                HttpResponseMessage response = await ExecuteWebHookAsync(id, context, request, new string[] { action }, notifications);

                // Add SOAP response if not already present
                if (response == null || response.Content == null || !response.Content.IsXml())
                {
                    response = request.CreateResponse();
                    string ack = ReadResource("Microsoft.AspNet.WebHooks.Messages.NotificationResponse.xml");
                    response.Content = new StringContent(ack, Encoding.UTF8, "application/xml");
                }
                return(response);
            }
            else
            {
                return(CreateBadMethodResponse(request));
            }
        }