Partner Center-webhooks
Gäller för: Partnercenter | Partnercenter som drivs av 21Vianet | Partnercenter för Microsoft Cloud for US Government
Lämpliga roller: Faktureringsadministratör | Administratörsagent | Försäljningsagent | Helpdesk-agent
Med Api:erna för Partnercenter Webhook kan partner registrera sig för resursändringshändelser. Dessa händelser levereras i form av HTTP-POST:er till partnerns registrerade URL. För att ta emot en händelse från Partnercenter skapar partnern en callback där Partnercenter kan POST:a resursändringshändelsen. Händelsen är digitalt signerad så att partnern kan verifiera att den har skickats från Partnercenter. Webhook-meddelanden utlöses endast till den miljö som har den senaste konfigurationen för säljsamarbete.
Partnercenter stöder följande Webhook-händelser.
Azure-bedrägerihändelse upptäckt ("azure-fraud-event-detected")
Den här händelsen utlöses när Azure-bedrägerihändelsen identifieras.
Godkänd händelse för delegerad administratörsrelation ("dap-admin-relationship-approved")
Den här händelsen utlöses när delegerade administratörsbehörigheter godkänns av kundhyresgästen.
Relationshändelse där återförsäljare accepterats av kund ("reseller-relationship-accepted-by-customer")
Den här händelsen utlöses när kunden godkänner återförsäljarrelationen.
Indirekt återförsäljarrelation accepterad av kund ("indirect-reseller-relationship-accepted-by-customer")
Den här händelsen utlöses när kunden godkänner det indirekta återförsäljarförhållandet.
Händelse: Avslutad relation med delegerad administratör ("dap-admin-relationship-terminated")
Den här händelsen utlöses när kunden avslutar delegerade administratörsprivilegier.
Dap-administratörsrelation avslutad av Microsoft-händelse ("dap-admin-relationship-terminated-by-microsoft")
Den här händelsen utlöses när Microsoft avslutar DAP mellan partner- och kundens klientorganisation när DAP är inaktiv i mer än 90 dagar.
Aktivering av granulär administratörsåtkomsttilldelningshändelse ("granular-admin-access-assignment-activated")
Den här händelsen utlöses när partnern aktiverar granular Delegated Admin Privileges-åtkomsttilldelningen när Microsoft Entra-rollerna har tilldelats till specifika säkerhetsgrupper.
Händelse för skapad granulär administratörsåtkomsttilldelning ("granular-admin-access-assignment-created")
Den här händelsen utlöses när partnern skapar åtkomsttilldelningen för detaljerade delegerade administratörsbehörigheter. Partner kan tilldela kundgodkända Microsoft Entra-roller till specifika säkerhetsgrupper.
Granulär administratörsåtkomsttilldelning borttagen händelse ("granular-admin-access-assignment-deleted")
Den här händelsen inträffar när partnern tar bort åtkomsttilldelning av granulära delegerade administratörsprivilegier.
Uppdaterad händelse för granulär administratörsåtkomsttilldelning ("granular-admin-access-assignment-updated")
Den här händelsen utlöses när partnern uppdaterar åtkomsttilldelningen Granular Delegated Admin Privileges.
Aktivering av granulärt administratörsrelationshändelse ("granular-admin-relationship-activated")
Den här händelsen genereras när granulära delegerade administratörsbehörigheter skapas och är aktiva för att kunden ska godkänna.
Godkänd händelse för granulär administratörsrelation ("granular-admin-relationship-approved")
Den här händelsen utlöses när kundens klientorganisation godkänner de granulära delegerade administratörsbehörigheterna.
Händelse för att granulärt administratörsförhållande har upphört ("granular-admin-relationship-expired")
Den här händelsen utlöses när de granulära delegerade administratörsbehörigheterna har upphört att gälla.
Granulär administratörsrelationsskapande händelse ("granular-admin-relationship-created")
Den här händelsen utlöses när granulära delegerade administratörsbehörigheter skapas.
Uppdaterad händelse för granulär administratörsrelation ("granular-admin-relationship-updated")
Den här händelsen utlöses när antingen kunden eller partnern uppdaterar de granulära delegerade administratörsbehörigheterna.
Automatiskt förlängd händelse för granulär administratörsrelation ("granular-admin-relationship-auto-extended")
Den här händelsen utlöses när systemet automatiskt utökar de detaljerade delegerade administratörsbehörigheterna.
Händelse för avslutande av granulär administratörsrelation ("granular-admin-relationship-terminated")
Den här händelsen utlöses när partner- eller kundklientorganisationen avslutar de granulära delegerade administratörsbehörigheterna.
Ny handelsmigrering har slutförts ("new-commerce-migration-completed")
Den här händelsen utlöses när den nya handelsmigreringen har slutförts.
Ny handelsmigrering har skapats ("new-commerce-migration-created")
Den här händelsen utlöses när den nya handelsmigreringen skapas.
Ny handelsmigrering misslyckades ("new-commerce-migration-failed")
Den här händelsen utlöses när den nya handelsmigreringen misslyckas.
Skapa överföring ("create-transfer")
Den här händelsen utlöses när överföringen skapas.
Uppdateringsöverföring ("update-transfer")
Den här händelsen utlöses när överföringen uppdateras.
Fullständig överföring ("complete-transfer")
Den här händelsen utlöses när överföringen har slutförts.
Överföring som upphör ("expire-transfer")
Den här händelsen utlöses när överföringen har upphört att gälla.
Misslyckad överföring ("fail-transfer")
Den här händelsen utlöses när överföringen misslyckas.
Nytt handelsmigreringsschema misslyckades ("new-commerce-migration-schedule-failed")
Den här händelsen utlöses när det nya handelsmigreringsschemat misslyckas.
Hänvisningsskapad händelse ("referral-created")
Den här händelsen utlöses när hänvisningen skapas.
Uppdaterad händelse för hänvisning ("referral-updated")
Den här händelsen utlöses när hänvisningen uppdateras.
Relaterad referens skapad händelse ("related-referral-created")
Den här händelsen utlöses när den relaterade hänvisningen skapas.
Händelse för uppdaterad relaterad referens ("related-referral-updated")
Den här händelsen utlöses när den relaterade hänvisningen uppdateras.
Prenumerationen är aktiv händelse ("prenumerationen-aktiv")
Den här händelsen utlöses när prenumerationen aktiveras.
Anmärkning
Webhooken "Subscription Active" och den motsvarande aktivitetslogghändelsen är för närvarande endast tillgängliga för Sandbox-klienter.
Väntande händelse för prenumeration ("prenumeration väntar")
Den här händelsen utlöses när motsvarande order har tagits emot på ett lyckat sätt och prenumerationsskapandet väntar.
Anmärkning
Prenumeration-väntar-webhooken och motsvarande aktivitetsloggshändelse är för närvarande endast tillgängliga för Sandbox-användare.
Förnyad prenumerationshändelse ("prenumeration förnyad")
Den här händelsen utlöses när prenumerationen slutför förnyelsen.
Anmärkning
Prenumerationsförnyelse webhooken och motsvarande aktivitetslogghändelse är för närvarande endast tillgängliga för Sandbox-kunder.
Uppdaterad händelse för prenumeration ("prenumerationen har uppdaterats")
Den här händelsen utlöses när prenumerationen ändras. Dessa händelser genereras när det sker en intern ändring utöver när ändringar görs via Partnercenter-API:et.
Anmärkning
Det finns en fördröjning på upp till 48 timmar mellan tiden då en prenumeration ändras och när händelsen Prenumerationsuppdaterad utlöses.
Testhändelse ("test-skapad")
Den här händelsen gör det möjligt för dig att självregistrera och testa din registrering genom att begära ett testevent och sedan spåra dess förlopp. Du kan se de felmeddelanden som tas emot från Microsoft när du försöker leverera händelsen. Den här begränsningen gäller endast för "testskapade" händelser. Data som är äldre än sju dagar rensas.
Tröskelvärdet överskred händelsen ("usagerecords-thresholdExceeded")
Den här händelsen utlöses när mängden Microsoft Azure-användning för alla kunder överskrider deras användningsbudget (deras tröskelvärde). Mer information finns i (Ange en Azure-utgiftsbudget för dina kunder/partnercenter/set-an-azure-spending-budget-for-your-customers).
Framtida Webhook-händelser läggs till för resurser som ändras i systemet som partnern inte har kontroll över, och ytterligare uppdateringar kommer att göras för att få dessa händelser så nära "realtid" som möjligt. Feedback från partner om vilka händelser som tillför värde till verksamheten är användbart för att avgöra vilka nya händelser som ska läggas till.
En fullständig lista över Webhook-händelser som stöds av Partnercenter finns i Webhook-händelser i Partnercenter.
Förutsättningar
- Autentiseringsuppgifter enligt beskrivningen i Partnercenter-autentisering. Det här scenariot stöder autentisering med både fristående app- och App+User-autentiseringsuppgifter.
Ta emot händelser från Partnercenter
Om du vill ta emot händelser från Partnercenter måste du exponera en offentligt tillgänglig slutpunkt. Eftersom den här slutpunkten exponeras måste du verifiera att kommunikationen kommer från Partnercenter. Alla Webhook-händelser som du får är digitalt signerade med ett certifikat som kedjar till Microsoft Root. En länk till certifikatet som används för att signera händelsen finns också. På så sätt kan certifikatet förnyas utan att du behöver distribuera om eller konfigurera om tjänsten. Partnercenter gör 10 försök att leverera händelsen. Om händelsen fortfarande inte levereras efter 10 försök flyttas den till en offlinekö och inga ytterligare försök görs vid leveransen.
Följande exempel visar en händelse som publicerats från Partnercenter.
POST /webhooks/callback
Content-Type: application/json
Authorization: Signature VOhcjRqA4f7u/4R29ohEzwRZibZdzfgG5/w4fHUnu8FHauBEVch8m2+5OgjLZRL33CIQpmqr2t0FsGF0UdmCR2OdY7rrAh/6QUW+u+jRUCV1s62M76jbVpTTGShmrANxnl8gz4LsbY260LAsDHufd6ab4oejerx1Ey9sFC+xwVTa+J4qGgeyIepeu4YCM0oB2RFS9rRB2F1s1OeAAPEhG7olp8B00Jss3PQrpLGOoAr5+fnQp8GOK8IdKF1/abUIyyvHxEjL76l7DVQN58pIJg4YC+pLs8pi6sTKvOdSVyCnjf+uYQWwmmWujSHfyU37j2Fzz16PJyWH41K8ZXJJkw==
X-MS-Certificate-Url: https://3psostorageacct.blob.core.windows.net/cert/pcnotifications-dispatch.microsoft.com.cer
X-MS-Signature-Algorithm: rsa-sha256
Host: api.partnercenter.microsoft.com
Accept-Encoding: gzip, deflate
Content-Length: 195
{
"EventName": "test-created",
"ResourceUri": "http://localhost:16722/v1/webhooks/registration/test",
"ResourceName": "test",
"AuditUri": null,
"ResourceChangeUtcDate": "2017-11-16T16:19:06.3520276+00:00"
}
Anmärkning
Auktoriseringshuvudet har ett schema med "Signatur". Det här är en base64-kodad signatur för innehållet.
Så här autentiserar du återanropet
Följ dessa steg för att autentisera motringningshändelsen som tagits emot från Partnercenter:
- Kontrollera att de nödvändiga rubrikerna finns (auktorisering, x-ms-certificate-url, x-ms-signature-algorithm).
- Ladda ned certifikatet som används för att signera innehållet (x-ms-certificate-url).
- Verifiera certifikatkedjan.
- Verifiera certifikatets "organisation".
- Läs innehållet med UTF8-kodning i en buffert.
- Skapa en RSA-kryptoprovider.
- Kontrollera att data matchar det som signerades med den angivna hash-algoritmen (till exempel SHA256).
- Om verifieringen lyckas bearbetar du meddelandet.
Anmärkning
Som standard skickas signaturtoken i ett auktoriseringshuvud. Om du anger SignatureTokenToMsSignatureHeader till true i din registrering skickas signaturtoken i rubriken x-ms-signature i stället.
Händelsemodell
I följande tabell beskrivs egenskaperna för en PartnerCenter-händelse.
Egenskaper
Name | beskrivning |
---|---|
EventName | Namnet på händelsen. I formuläret {resource}-{action}. Till exempel ”test-skapat”. |
ResourceUri | URI:n för resursen som ändrades. |
ResourceName | Namnet på resursen som ändrades. |
AuditUrl | Valfritt. URI:n för revisionsposten. |
ResursÄndringUtcDatum | Datum och tid, i UTC-format, när resursändringen inträffade. |
Exempel
Följande exempel visar strukturen för en PartnerCenter-händelse.
{
"EventName": "test-created",
"ResourceUri": "http://api.partnercenter.microsoft.com/webhooks/v1/registration/validationEvents/c0bfd694-3075-4ec5-9a3c-733d3a890a1f",
"ResourceName": "test",
"AuditUri": null,
"ResourceChangeUtcDate": "2017-11-16T16:19:06.3520276+00:00"
}
Webhook-API:er
Autentisering
Alla anrop till Webhook-API:erna autentiseras med hjälp av ägartoken i auktoriseringshuvudet. Hämta en åtkomsttoken för att få åtkomst till https://api.partnercenter.microsoft.com
. Den här token är samma token som används för att komma åt resten av Partnercenter-API:erna.
Hämta en lista över händelser
Returnerar en lista över de händelser som för närvarande stöds av Webhook-API:erna.
Resurs-URL
https://api.partnercenter.microsoft.com/webhooks/v1/registration/events
Exempel på begäran
GET /webhooks/v1/registration/events
content-type: application/json
authorization: Bearer eyJ0e.......
accept: */*
host: api.partnercenter.microsoft.com
Svarsexempel
HTTP/1.1 200
Status: 200
Content-Length: 183
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
MS-CorrelationId: aaaa0000-bb11-2222-33cc-444444dddddd
MS-RequestId: 79419bbb-06ee-48da-8221-e09480537dfc
X-Locale: en-US
[ "subscription-updated", "test-created", "usagerecords-thresholdExceeded" ]
Registrera dig för att ta emot händelser
Registrerar en hyresgäst för att ta emot de angivna händelserna.
Resurs-URL
https://api.partnercenter.microsoft.com/webhooks/v1/registration
Exempel på begäran
POST /webhooks/v1/registration
Content-Type: application/json
Authorization: Bearer eyJ0e.....
Accept: */*
Host: api.partnercenter.microsoft.com
Accept-Encoding: gzip, deflate
Content-Length: 219
{
"WebhookUrl": "{{YourCallbackUrl}}",
"WebhookEvents": ["subscription-updated", "test-created"]
}
Svarsexempel
HTTP/1.1 200
Status: 200
Content-Length: 346
Content-Type: application/json; charset=utf-8
content-encoding: gzip
Vary: Accept-Encoding
MS-CorrelationId: bbbb1111-cc22-3333-44dd-555555eeeeee
MS-RequestId: f04b1b5e-87b4-4d95-b087-d65fffec0bd2
{
"SubscriberId": "e82cac64-dc67-4cd3-849b-78b6127dd57d",
"WebhookUrl": "{{YourCallbackUrl}}",
"WebhookEvents": [ "subscription-updated", "test-created" ]
}
Visa en registrering
Returnerar Webhooks-händelseregistreringen för en hyresgäst.
Resurs-URL
https://api.partnercenter.microsoft.com/webhooks/v1/registration
Exempel på begäran
GET /webhooks/v1/registration
Content-Type: application/json
Authorization: Bearer ...
Accept: */*
Host: api.partnercenter.microsoft.com
Accept-Encoding: gzip, deflate
Svarsexempel
HTTP/1.1 200
Status: 200
Content-Length: 341
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
MS-CorrelationId: cccc2222-dd33-4444-55ee-666666ffffff
MS-RequestId: ca30367d-4b24-4516-af08-74bba6dc6657
X-Locale: en-US
{
"WebhookUrl": "{{YourCallbackUrl}}",
"WebhookEvents": ["subscription-updated", "test-created"]
}
Uppdatera en händelseregistrering
Uppdaterar en befintlig händelseregistrering.
Resurs-URL
https://api.partnercenter.microsoft.com/webhooks/v1/registration
Exempel på begäran
PUT /webhooks/v1/registration
Content-Type: application/json
Authorization: Bearer eyJ0eXAiOR...
Accept: */*
Host: api.partnercenter.microsoft.com
Accept-Encoding: gzip, deflate
Content-Length: 258
{
"WebhookUrl": "{{YourCallbackUrl}}",
"WebhookEvents": ["subscription-updated", "test-created"]
}
Svarsexempel
HTTP/1.1 200
Status: 200
Content-Length: 346
Content-Type: application/json; charset=utf-8
content-encoding: gzip
Vary: Accept-Encoding
MS-CorrelationId: bbbb1111-cc22-3333-44dd-555555eeeeee
MS-RequestId: f04b1b5e-87b4-4d95-b087-d65fffec0bd2
{
"SubscriberId": "e82cac64-dc67-4cd3-849b-78b6127dd57d",
"WebhookUrl": "{{YourCallbackUrl}}",
"WebhookEvents": [ "subscription-updated", "test-created" ]
}
Skicka en testhändelse för att verifiera din registrering
Genererar en testhändelse för att verifiera Webhooks-registreringen. Det här testet är avsett att verifiera att du kan ta emot händelser från Partnercenter. Data för dessa händelser tas bort sju dagar efter att den första händelsen har skapats. Du måste vara registrerad för händelsen "testskapad" med hjälp av registrerings-API:et innan du skickar en valideringshändelse.
Anmärkning
Det finns en begränsningsgräns på 2 begäranden per minut när du publicerar en valideringshändelse.
Resurs-URL
https://api.partnercenter.microsoft.com/webhooks/v1/registration/validationEvents
Exempel på begäran
POST /webhooks/v1/registration/validationEvents
MS-CorrelationId: dddd3333-ee44-5555-66ff-777777aaaaaa
Authorization: Bearer ...
Accept: */*
Host: api.partnercenter.microsoft.com
Accept-Encoding: gzip, deflate
Content-Length:
Svarsexempel
HTTP/1.1 200
Status: 200
Content-Length: 181
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
MS-CorrelationId: eeee4444-ff55-6666-77aa-888888bbbbbb
MS-RequestId: 2f498d5a-a6ab-468f-98d8-93c96da09051
X-Locale: en-US
{ "correlationId": "eeee4444-ff55-6666-77aa-888888bbbbbb" }
Kontrollera att händelsen levererades
Returnerar valideringshändelsens aktuella tillstånd. Den här verifieringen kan vara till hjälp vid felsökning av problem med händelseleverans. Svaret innehåller ett resultat för varje försök att leverera händelsen.
Resurs webbadress
https://api.partnercenter.microsoft.com/webhooks/v1/registration/validationEvents/{correlationId}
Exempel på begäran
GET /webhooks/v1/registration/validationEvents/eeee4444-ff55-6666-77aa-888888bbbbbb
MS-CorrelationId: dddd3333-ee44-5555-66ff-777777aaaaaa
Authorization: Bearer ...
Accept: */*
Host: api.partnercenter.microsoft.com
Accept-Encoding: gzip, deflate
Svarsexempel
HTTP/1.1 200
Status: 200
Content-Length: 469
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
MS-CorrelationId: ffff5555-aa66-7777-88bb-999999cccccc
MS-RequestId: 0843bdb2-113a-4926-a51c-284aa01d722e
X-Locale: en-US
{
"correlationId": "eeee4444-ff55-6666-77aa-888888bbbbbb",
"partnerId": "00234d9d-8c2d-4ff5-8c18-39f8afc6f7f3",
"status": "completed",
"callbackUrl": "{{YourCallbackUrl}}",
"results": [{
"responseCode": "OK",
"responseMessage": "",
"systemError": false,
"dateTimeUtc": "2017-12-08T21:39:48.2386997"
}]
}
Exempel på signaturverifiering
Exempel på återanropsstyrenhetssignatur (ASP.NET)
[AuthorizeSignature]
[Route("webhooks/callback")]
public IHttpActionResult Post(PartnerResourceChangeCallBack callback)
Signaturverifiering
I följande exempel visas hur du lägger till ett auktoriseringsattribut till den kontrollant som tar emot återanrop från Webhook-händelser.
namespace Webhooks.Security
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using Microsoft.Partner.Logging;
/// <summary>
/// Signature based Authorization
/// </summary>
public class AuthorizeSignatureAttribute : AuthorizeAttribute
{
private const string MsSignatureHeader = "x-ms-signature";
private const string CertificateUrlHeader = "x-ms-certificate-url";
private const string SignatureAlgorithmHeader = "x-ms-signature-algorithm";
private const string MicrosoftCorporationIssuer = "O=Microsoft Corporation";
private const string SignatureScheme = "Signature";
/// <inheritdoc/>
public override async Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
ValidateAuthorizationHeaders(actionContext.Request);
await VerifySignature(actionContext.Request);
}
private static async Task<string> GetContentAsync(HttpRequestMessage request)
{
// By default the stream can only be read once and we need to read it here so that we can hash the body to validate the signature from microsoft.
// Load into a buffer, so that the stream can be accessed here and in the api when it binds the content to the expected model type.
await request.Content.LoadIntoBufferAsync();
var s = await request.Content.ReadAsStreamAsync();
var reader = new StreamReaders;
var body = await reader.ReadToEndAsync();
// set the stream position back to the beginning
if (s.CanSeek)
{
s.Seek(0, SeekOrigin.Begin);
}
return body;
}
private static void ValidateAuthorizationHeaders(HttpRequestMessage request)
{
var authHeader = request.Headers.Authorization;
if (string.IsNullOrWhiteSpace(authHeader?.Parameter) && string.IsNullOrWhiteSpace(GetHeaderValue(request.Headers, MsSignatureHeader)))
{
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Authorization header missing."));
}
var signatureHeaderValue = GetHeaderValue(request.Headers, MsSignatureHeader);
if (authHeader != null
&& !string.Equals(authHeader.Scheme, SignatureScheme, StringComparison.OrdinalIgnoreCase)
&& !string.IsNullOrWhiteSpace(signatureHeaderValue)
&& !signatureHeaderValue.StartsWith(SignatureScheme, StringComparison.OrdinalIgnoreCase))
{
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.Unauthorized, $"Authorization scheme needs to be '{SignatureScheme}'."));
}
if (string.IsNullOrWhiteSpace(GetHeaderValue(request.Headers, CertificateUrlHeader)))
{
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.BadRequest, $"Request header {CertificateUrlHeader} missing."));
}
if (string.IsNullOrWhiteSpace(GetHeaderValue(request.Headers, SignatureAlgorithmHeader)))
{
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.BadRequest, $"Request header {SignatureAlgorithmHeader} missing."));
}
}
private static string GetHeaderValue(HttpHeaders headers, string key)
{
headers.TryGetValues(key, out var headerValues);
return headerValues?.FirstOrDefault();
}
private static async Task VerifySignature(HttpRequestMessage request)
{
// Get signature value from either authorization header or x-ms-signature header.
var base64Signature = request.Headers.Authorization?.Parameter ?? GetHeaderValue(request.Headers, MsSignatureHeader).Split(' ')[1];
var signatureAlgorithm = GetHeaderValue(request.Headers, SignatureAlgorithmHeader);
var certificateUrl = GetHeaderValue(request.Headers, CertificateUrlHeader);
var certificate = await GetCertificate(certificateUrl);
var content = await GetContentAsync(request);
var alg = signatureAlgorithm.Split('-'); // for example RSA-SHA1
var isValid = false;
var logger = GetLoggerIfAvailable(request);
// Validate the certificate
VerifyCertificate(certificate, request, logger);
if (alg.Length == 2 && alg[0].Equals("RSA", StringComparison.OrdinalIgnoreCase))
{
var signature = Convert.FromBase64String(base64Signature);
var csp = (RSACryptoServiceProvider)certificate.PublicKey.Key;
var encoding = new UTF8Encoding();
var data = encoding.GetBytes(content);
var hashAlgorithm = alg[1].ToUpper();
isValid = csp.VerifyData(data, CryptoConfig.MapNameToOID(hashAlgorithm), signature);
}
if (!isValid)
{
// log that we were not able to validate the signature
logger?.TrackTrace(
"Failed to validate signature for webhook callback",
new Dictionary<string, string> { { "base64Signature", base64Signature }, { "certificateUrl", certificateUrl }, { "signatureAlgorithm", signatureAlgorithm }, { "content", content } });
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Signature verification failed"));
}
}
private static ILogger GetLoggerIfAvailable(HttpRequestMessage request)
{
return request.GetDependencyScope().GetService(typeof(ILogger)) as ILogger;
}
private static async Task<X509Certificate2> GetCertificate(string certificateUrl)
{
byte[] certBytes;
using (var webClient = new WebClient())
{
certBytes = await webClient.DownloadDataTaskAsync(certificateUrl);
}
return new X509Certificate2(certBytes);
}
private static void VerifyCertificate(X509Certificate2 certificate, HttpRequestMessage request, ILogger logger)
{
if (!certificate.Verify())
{
logger?.TrackTrace("Failed to verify certificate for webhook callback.", new Dictionary<string, string> { { "Subject", certificate.Subject }, { "Issuer", certificate.Issuer } });
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Certificate verification failed."));
}
if (!certificate.Issuer.Contains(MicrosoftCorporationIssuer))
{
logger?.TrackTrace($"Certificate not issued by {MicrosoftCorporationIssuer}.", new Dictionary<string, string> { { "Issuer", certificate.Issuer } });
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.Unauthorized, $"Certificate not issued by {MicrosoftCorporationIssuer}."));
}
}
}
}