public void VerifyCertificateUrlTest() { // samples from // https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-web-service var validUrls = new string[] { "https://s3.amazonaws.com/echo.api/echo-api-cert.pem", "https://s3.amazonaws.com:443/echo.api/echo-api-cert.pem", "https://s3.amazonaws.com/echo.api/../echo.api/echo-api-cert.pem" }; var invalidUrls = new string[] { "http://s3.amazonaws.com/echo.api/echo-api-cert.pem", "https://notamazon.com/echo.api/echo-api-cert.pem", "https://s3.amazonaws.com/EcHo.aPi/echo-api-cert.pem", "https://s3.amazonaws.com/invalid.path/echo-api-cert.pem", "https://s3.amazonaws.com:563/echo.api/echo-api-cert.pem" }; foreach (var validUrl in validUrls) { Assert.True(SpeechletRequestSignatureVerifier.VerifyCertificateUrl(validUrl)); } foreach (var invalidUrl in invalidUrls) { Assert.False(SpeechletRequestSignatureVerifier.VerifyCertificateUrl(invalidUrl)); } }
public async Task <SpeechletRequestEnvelope> GetRequestAsync(string content, string chainUrl, string signature) { var validationResult = SpeechletRequestValidationResult.OK; if (string.IsNullOrEmpty(chainUrl)) { validationResult |= SpeechletRequestValidationResult.NoCertHeader; } if (string.IsNullOrEmpty(signature)) { validationResult |= SpeechletRequestValidationResult.NoSignatureHeader; } // attempt to verify signature only if we were able to locate certificate and signature headers if (validationResult == SpeechletRequestValidationResult.OK) { var alexaBytes = Encoding.UTF8.GetBytes(content); if (!await SpeechletRequestSignatureVerifier.VerifyRequestSignatureAsync(alexaBytes, signature, chainUrl)) { validationResult |= SpeechletRequestValidationResult.InvalidSignature; } } SpeechletRequestEnvelope result = null; try { result = SpeechletRequestEnvelope.FromJson(content); } catch (Exception ex) when(ex is Newtonsoft.Json.JsonReaderException || ex is InvalidCastException || ex is FormatException) { validationResult |= SpeechletRequestValidationResult.InvalidJson; } var success = false; // attempt to verify timestamp only if we were able to parse request body if (result != null) { var now = DateTime.UtcNow; // reference time for this request if (!SpeechletRequestTimestampVerifier.VerifyRequestTimestamp(result, now)) { validationResult |= SpeechletRequestValidationResult.InvalidTimestamp; } success = speechlet?.OnRequestValidation(validationResult, now, result) ?? (validationResult == SpeechletRequestValidationResult.OK); } if (!success) { throw new SpeechletValidationException(validationResult); } return(result); }
public void VerifyUrl( string urlToValidate, bool isValid, string reason) { Assert.IsTrue( SpeechletRequestSignatureVerifier.IsValidUrl(urlToValidate) == isValid, reason); }
/// <summary> /// Processes Alexa request AND validates request signature /// </summary> /// <param name="httpRequest"></param> /// <returns></returns> public async virtual Task <HttpResponseMessage> GetResponseAsync(HttpRequestMessage httpRequest) { if (!httpRequest.Headers.Contains(Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER) || !httpRequest.Headers.Contains(Sdk.SIGNATURE_REQUEST_HEADER)) { return(new HttpResponseMessage(HttpStatusCode.BadRequest)); // Request signature absent } string chainUrl = httpRequest.Headers.GetValues(Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER).First(); string signature = httpRequest.Headers.GetValues(Sdk.SIGNATURE_REQUEST_HEADER).First(); var alexaBytes = await httpRequest.Content.ReadAsByteArrayAsync(); Debug.WriteLine(httpRequest.ToLogString()); if (!(await SpeechletRequestSignatureVerifier.VerifyRequestSignatureAsync(alexaBytes, signature, chainUrl))) { return(new HttpResponseMessage(HttpStatusCode.BadRequest)); // Failed signature verification } var alexaContent = UTF8Encoding.UTF8.GetString(alexaBytes); string alexaResponse = await ProcessRequestAsync(alexaContent); HttpResponseMessage httpResponse; if (alexaResponse == null) { httpResponse = new HttpResponseMessage(HttpStatusCode.InternalServerError); } else if (alexaResponse == String.Empty) { httpResponse = new HttpResponseMessage(HttpStatusCode.BadRequest); } else { httpResponse = new HttpResponseMessage(HttpStatusCode.OK); httpResponse.Content = new StringContent(alexaResponse, Encoding.UTF8, "application/json"); Debug.WriteLine(httpResponse.ToLogString()); } return(httpResponse); }
/// <summary> /// Processes Alexa request AND validates request signature /// </summary> /// <param name="httpRequest"></param> /// <returns></returns> public virtual HttpResponseMessage GetResponse(HttpRequestMessage httpRequest) { SpeechletRequestValidationResult validationResult = SpeechletRequestValidationResult.OK; DateTime now = DateTime.UtcNow; // reference time for this request string chainUrl = null; if (!httpRequest.Headers.Contains(Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER) || String.IsNullOrEmpty(chainUrl = httpRequest.Headers.GetValues(Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER).First())) { validationResult = validationResult | SpeechletRequestValidationResult.NoCertHeader; } string signature = null; if (!httpRequest.Headers.Contains(Sdk.SIGNATURE_REQUEST_HEADER) || String.IsNullOrEmpty(signature = httpRequest.Headers.GetValues(Sdk.SIGNATURE_REQUEST_HEADER).First())) { validationResult = validationResult | SpeechletRequestValidationResult.NoSignatureHeader; } var alexaBytes = AsyncHelpers.RunSync <byte[]>(() => httpRequest.Content.ReadAsByteArrayAsync()); Debug.WriteLine(httpRequest.ToLogString()); // attempt to verify signature only if we were able to locate certificate and signature headers if (validationResult == SpeechletRequestValidationResult.OK) { if (!SpeechletRequestSignatureVerifier.VerifyRequestSignature(alexaBytes, signature, chainUrl)) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidSignature; } } SpeechletRequestEnvelope alexaRequest = null; try { var alexaContent = UTF8Encoding.UTF8.GetString(alexaBytes); alexaRequest = SpeechletRequestEnvelope.FromJson(alexaContent); } catch (Newtonsoft.Json.JsonReaderException) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidJson; } catch (InvalidCastException) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidJson; } // attempt to verify timestamp only if we were able to parse request body if (alexaRequest != null) { if (!SpeechletRequestTimestampVerifier.VerifyRequestTimestamp(alexaRequest, now)) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidTimestamp; } } if (alexaRequest == null || !OnRequestValidation(validationResult, now, alexaRequest)) { return(new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = validationResult.ToString() }); } string alexaResponse = DoProcessRequest(alexaRequest); HttpResponseMessage httpResponse; if (alexaResponse != null) { httpResponse = new HttpResponseMessage(HttpStatusCode.OK); httpResponse.Content = new StringContent(alexaResponse, Encoding.UTF8, "application/json"); // Debug.WriteLine(httpResponse.ToLogString()); } else { httpResponse = new HttpResponseMessage(HttpStatusCode.InternalServerError); } return(httpResponse); }
public AlexaScheduleSkillController(AlexaTwinRinksSkillRequestProcessor service, SpeechletRequestSignatureVerifier verifier) { _service = service; _reqVerifier = verifier; }
/// <summary> /// Processes Alexa request AND validates request signature /// </summary> /// <returns></returns> public virtual string GetResponse(Dictionary <string, string[]> Headers, byte[] Content, out HttpStatusCode HttpStatusCode) { SpeechletRequestValidationResult validationResult = SpeechletRequestValidationResult.OK; DateTime now = DateTime.UtcNow; // reference time for this request string chainUrl = null; if (!Headers.ContainsKey(Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER) || String.IsNullOrEmpty(chainUrl = Headers[Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER].First())) { validationResult = validationResult | SpeechletRequestValidationResult.NoCertHeader; } string signature = null; if (!Headers.ContainsKey(Sdk.SIGNATURE_REQUEST_HEADER) || String.IsNullOrEmpty(signature = Headers[Sdk.SIGNATURE_REQUEST_HEADER].First())) { validationResult = validationResult | SpeechletRequestValidationResult.NoSignatureHeader; } // attempt to verify signature only if we were able to locate certificate and signature headers if (validationResult == SpeechletRequestValidationResult.OK) { if (!SpeechletRequestSignatureVerifier.VerifyRequestSignature(Content, signature, chainUrl)) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidSignature; } } SpeechletRequestEnvelope alexaRequest = null; try { var alexaContent = UTF8Encoding.UTF8.GetString(Content); alexaRequest = SpeechletRequestEnvelope.FromJson(alexaContent); } catch (Newtonsoft.Json.JsonReaderException) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidJson; } catch (InvalidCastException) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidJson; } // attempt to verify timestamp only if we were able to parse request body if (alexaRequest != null) { if (!SpeechletRequestTimestampVerifier.VerifyRequestTimestamp(alexaRequest, now)) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidTimestamp; } } if (alexaRequest == null || !OnRequestValidation(validationResult, now, alexaRequest)) { HttpStatusCode = HttpStatusCode.BadRequest; return(validationResult.ToString()); } string alexaResponse = DoProcessRequest(alexaRequest); if (alexaResponse == null) { HttpStatusCode = HttpStatusCode.InternalServerError; return(null); } else { HttpStatusCode = HttpStatusCode.OK; return(alexaResponse); } }
/// <summary> /// Processes Alexa request AND validates request signature /// </summary> /// <param name="httpRequest"></param> /// <returns></returns> public virtual TResponse GetResponse(T httpRequest) { var validationResult = SpeechletRequestValidationResult.OK; var now = DateTime.UtcNow; // reference time for this request string chainUrl = null; if (!httpRequest.Headers.Contains(Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER) || string.IsNullOrEmpty( chainUrl = httpRequest.Headers.GetValue(Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER).First())) { validationResult = validationResult | SpeechletRequestValidationResult.NoCertHeader; } string signature = null; if (!httpRequest.Headers.Contains(Sdk.SIGNATURE_REQUEST_HEADER) || string.IsNullOrEmpty(signature = httpRequest.Headers.GetValue(Sdk.SIGNATURE_REQUEST_HEADER).First())) { validationResult = validationResult | SpeechletRequestValidationResult.NoSignatureHeader; } var alexaBytes = AsyncHelpers.RunSync(() => httpRequest.Content.ReadAsByteArrayAsync()); var alexaContent = Encoding.UTF8.GetString(alexaBytes); //Debug.WriteLine(httpRequest.ToLogString()); //todo // attempt to verify signature only if we were able to locate certificate and signature headers if (validationResult == SpeechletRequestValidationResult.OK) { if (!SpeechletRequestSignatureVerifier.VerifyRequestSignature(alexaBytes, signature, chainUrl)) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidSignature; } } SpeechletRequestEnvelope alexaRequest = null; try { alexaRequest = SpeechletRequestEnvelope.FromJson(alexaContent); } catch (JsonReaderException) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidJson; } catch (InvalidCastException) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidJson; } // attempt to verify timestamp only if we were able to parse request body if (alexaRequest != null) { if (!SpeechletRequestTimestampVerifier.VerifyRequestTimestamp(alexaRequest, now)) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidTimestamp; } } if ((alexaRequest == null) || !OnRequestValidation(validationResult, now, alexaRequest)) { var responseFactory = new TResponseFactory(); return(responseFactory.BadRequest(validationResult.ToString())); } var alexaResponse = DoProcessRequest(alexaRequest); if (alexaResponse == null) { var responseFactory = new TResponseFactory(); return(responseFactory.InternalServerError()); } else { var responseFactory = new TResponseFactory(); return(responseFactory.Ok(alexaResponse)); } }