Skip to content

Commit 2870994

Browse files
authored
Merge pull request #101 from umbraco/feature/shopify-signature-validation
Shopify header signature validation
2 parents aebe99d + 1cf9161 commit 2870994

File tree

2 files changed

+56
-5
lines changed

2 files changed

+56
-5
lines changed
Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,36 @@
11
using Microsoft.AspNetCore.Mvc;
2+
using Umbraco.Cms.Integrations.OAuthProxy.Filters;
23

34
namespace Umbraco.Cms.Integrations.OAuthProxy.Controllers
45
{
5-
[ApiController]
6-
public class ShopifyComplianceController : Controller
6+
[ApiController]
7+
public class ShopifyComplianceController : Controller
78
{
89
/// <summary>
910
/// Handles customer data requests from Shopify
1011
/// </summary>
1112
/// <returns></returns>
1213
[HttpPost]
1314
[Route("/shopify-compliance/v1/customer/data-request")]
14-
public IActionResult CustomerDataRequest() => Ok();
15+
[SignatureValidation]
16+
public IActionResult CustomerDataRequest() => Ok();
1517

1618
/// <summary>
1719
/// Handles customer data erasure requests from Shopify
1820
/// </summary>
1921
/// <returns></returns>
2022
[HttpPost]
2123
[Route("/shopify-compliance/v1/customer/data-redact")]
22-
public IActionResult CustomerDataRedact() => Ok();
24+
[SignatureValidation]
25+
public IActionResult CustomerDataRedact() => Ok();
2326

2427
/// <summary>
2528
/// Handles shop data erasure requests from Shopify
2629
/// </summary>
2730
/// <returns></returns>
2831
[HttpPost]
2932
[Route("/shopify-compliance/v1/shop/data-redact")]
30-
public IActionResult ShopDataRedact() => Ok();
33+
[SignatureValidation]
34+
public IActionResult ShopDataRedact() => Ok();
3135
}
3236
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.AspNetCore.Mvc.Filters;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Options;
5+
using System;
6+
using System.IO;
7+
using System.Linq;
8+
using System.Security.Cryptography;
9+
using System.Text;
10+
using System.Threading.Tasks;
11+
using Umbraco.Cms.Integrations.OAuthProxy.Configuration;
12+
13+
namespace Umbraco.Cms.Integrations.OAuthProxy.Filters
14+
{
15+
public class SignatureValidationAttribute : ActionFilterAttribute
16+
{
17+
private const string HeaderKey = "X-Shopify-Hmac-Sha256";
18+
19+
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
20+
{
21+
var appSettings = context.HttpContext.RequestServices.GetService<IOptions<AppSettings>>().Value;
22+
23+
var hmacHeaderValues = context.HttpContext.Request.Headers
24+
.FirstOrDefault(kvp => kvp.Key.Equals(HeaderKey, StringComparison.OrdinalIgnoreCase)).Value;
25+
26+
if (hmacHeaderValues.Count == 0)
27+
{
28+
context.Result = new UnauthorizedResult();
29+
return;
30+
}
31+
32+
string hmacHeader = hmacHeaderValues.First();
33+
34+
HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(appSettings.ShopifyClientSecret));
35+
36+
var bodyStream = new StreamReader(context.HttpContext.Request.Body);
37+
string requestBody = await bodyStream.ReadToEndAsync();
38+
string hash = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(requestBody)));
39+
40+
if (hash != hmacHeader)
41+
{
42+
context.Result = new UnauthorizedResult();
43+
return;
44+
}
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)