ThomasPe / Alexa.NET.Security

This is a library to authenticate requests sent to an Alexa .NET backend
MIT License
10 stars 6 forks source link

The skill end-point is not accepting valid signed requests. Please make sure that your signature URL validation is correct. #5

Closed rahulbagal closed 5 years ago

rahulbagal commented 5 years ago

I am using this package in my MVC WebAPI project. ( Framework 4.7.2 ) I implemented the signature verification. The skill works with my API but when I do a functional test before certification submission and getting The skill end-point is not accepting valid signed requests. Please make sure that your signature URL validation is correct.

        [HttpPost]
        public async Task<SkillResponse> HandleResponse([FromBody]SkillRequest input)
        {
            Log.Information("POST request received");
            string json = JsonConvert.SerializeObject(input, Formatting.Indented);

            // Validate request signature 
            bool isValid = await ValidateRequest(ControllerContext.Request, input);
            if (!isValid)
            {
                throw new HttpResponseException(System.Net.HttpStatusCode.BadRequest);
            }
            else
            {
                Log.Information($"Signature validated");
            }

ValidateRequest function


        private static async Task<bool> ValidateRequest(HttpRequestMessage request,  SkillRequest skillRequest )
        {
            try {
                IEnumerable<string> urlheader = request.Headers.GetValues("SignatureCertChainUrl");

                string signatureChainUrl = string.Empty;
                if (urlheader != null)
                {
                    signatureChainUrl = urlheader.FirstOrDefault() ?? string.Empty;
                }

                if (string.IsNullOrWhiteSpace(signatureChainUrl))
                {
                    Log.Error("Validation failed. Empty SignatureCertChainUrl header");
                    return false;
                }

                Uri certUrl;
                try
                {
                    certUrl = new Uri(signatureChainUrl);
                }
                catch
                {
                    Log.Error($"Validation failed. SignatureChainUrl not valid: {signatureChainUrl}");
                    return false;
                }

                IEnumerable<string> signatureheader = request.Headers.GetValues("Signature");
                string signature = string.Empty;
               // string signatureBase64 = string.Empty;
                if (signatureheader != null)
                {
                    signature =  signatureheader.FirstOrDefault();
                   // signatureBase64 = Base64Encode(signature);
                }

                if (string.IsNullOrWhiteSpace(signature))
                {
                    Log.Error("Validation failed - Empty Signature header");
                    return false;
                }

                StreamReader reader = new StreamReader(HttpContext.Current.Request.InputStream);
                reader.BaseStream.Position = 0;
                string requestFromPost = reader.ReadToEnd();

                if (string.IsNullOrWhiteSpace(requestFromPost))
                {
                    Log.Error("Validation failed - the JSON is empty");
                    return false;
                }

                bool isTimestampValid = RequestVerification.RequestTimestampWithinTolerance(skillRequest);
                bool valid = await RequestVerification.Verify(signature, certUrl, requestFromPost);

                if (!valid )
                {
                    Log.Error("signature Validation failed - RequestVerification failed");
                    return false;
                }
                if (!isTimestampValid)
                {
                    Log.Error("isTimestampValid Validation failed - RequestVerification failed");
                    return false;
                }

                return true;
            }
            catch (Exception e ) {
                Log.Error(e.Message);
                return false;
            }
        }

Do you see any issue with code? Alexa documentation is not helping.

rahulbagal commented 5 years ago

On careful review of IIS logs, I realized on certain functional test requests of Alexa, the skill was throwing HTTP 500 error. Adding a larger try-catch to handle it solved the issue. Nothing related to this library. Great library & I am happy with it. Thank you!

troops579 commented 4 years ago

Please post final working code sample.