-
-
Save tsjdev-apps/128ba6213e041db01a9c7c4894202e7d to your computer and use it in GitHub Desktop.
Validate an Alexa Request within Azure Functions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Alexa.NET.Request; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.Azure.WebJobs.Extensions.Http; | |
using Microsoft.Extensions.Logging; | |
using System; | |
using System.Threading.Tasks; | |
namespace AlexaFunctionsApp | |
{ | |
public static class SkillRequestExtension | |
{ | |
public static async Task<bool> ValidateRequestAsync(this SkillRequest skillRequest, HttpRequest request, ILogger log) | |
{ | |
// get signature certification chain url | |
var signatureCertChainUrl = GetSignatureCertChainUrlFromRequest(request); | |
if (signatureCertChainUrl == null) | |
{ | |
log.LogError("Validation failed, because of incorrect SignatureCertChainUrl"); | |
return false; | |
} | |
// get signature header | |
var signature = GetSignatureFromRequest(request); | |
if (string.IsNullOrWhiteSpace(signature)) | |
{ | |
log.LogError("Validation failed, because of empty signature"); | |
return false; | |
} | |
// get body | |
var body = await GetBodyFromRequestAsync(request); | |
if (string.IsNullOrWhiteSpace(body)) | |
{ | |
log.LogError("Validation failed, because of empty body"); | |
return false; | |
} | |
// validate timestamp | |
if (!IsTimestampValid(skillRequest)) | |
{ | |
log.LogError("Validation failed, because timestamp is not valid"); | |
return false; | |
} | |
// validate signature, signaturecertchainurl and body | |
if (!await IsRequestValid(signature, signatureCertChainUrl, body)) | |
{ | |
log.LogError("Validation failed, because verification of request failed"); | |
return false; | |
} | |
return true; | |
} | |
private static Uri GetSignatureCertChainUrlFromRequest(HttpRequest httpRequest) | |
{ | |
httpRequest.Headers.TryGetValue("SignatureCertChainUrl", out var signatureCertChainUrlAsString); | |
if (string.IsNullOrWhiteSpace(signatureCertChainUrlAsString)) | |
return null; | |
Uri signatureCertChainUrl; | |
try | |
{ | |
signatureCertChainUrl = new Uri(signatureCertChainUrlAsString); | |
} | |
catch | |
{ | |
return null; | |
} | |
return signatureCertChainUrl; | |
} | |
private static string GetSignatureFromRequest(HttpRequest httpRequest) | |
{ | |
httpRequest.Headers.TryGetValue("Signature", out var signature); | |
return signature; | |
} | |
private static async Task<string> GetBodyFromRequestAsync(HttpRequest httpRequest) | |
{ | |
httpRequest.Body.Position = 0; | |
var body = await httpRequest.ReadAsStringAsync(); | |
httpRequest.Body.Position = 0; | |
return body; | |
} | |
private static bool IsTimestampValid(SkillRequest skillRequest) | |
{ | |
return RequestVerification.RequestTimestampWithinTolerance(skillRequest); | |
} | |
private static async Task<bool> IsRequestValid(string signature, Uri signatureCertChainUrl, string body) | |
{ | |
return await RequestVerification.Verify(signature, signatureCertChainUrl, body); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment