diff --git a/Controllers/FHIRcastClientController.cs b/Controllers/FHIRcastClientController.cs index a63aca5..86e9796 100644 --- a/Controllers/FHIRcastClientController.cs +++ b/Controllers/FHIRcastClientController.cs @@ -87,8 +87,23 @@ public IActionResult Post([FromForm] ClientModel model) /// Hub's verification response to our subscription attempt /// [HttpGet("{subscriptionId}")] - public IActionResult Get(string subscriptionId, [FromQuery] SubscriptionVerification verification) + public IActionResult Get(string subscriptionId) { + if (!Request.Query.ContainsKey("hub.challenge")) + { + this.logger.LogDebug($"Missing hub.challenge"); + return NotFound(); + } + + if (!Request.Query.ContainsKey("hub.topic")) + { + this.logger.LogDebug($"Missing hub.topic"); + return NotFound(); + } + + string challenge = Request.Query["hub.challenge"]; + string topic = Request.Query["hub.topic"]; + //Received a verification request for non-pending subscription, return a NotFound response if (!pendingSubs.ContainsKey(subscriptionId)) { return NotFound(); } @@ -96,12 +111,12 @@ public IActionResult Get(string subscriptionId, [FromQuery] SubscriptionVerifica //Validate verification subcription with our subscription. If a match return challenge //otherwise return NotFound response. - if (SubsEqual(sub, verification)) + if (topic == sub.Topic) { //Move subscription to active sub collection and remove from pending subs activeSubs.Add(subscriptionId, sub); pendingSubs.Remove(subscriptionId); - return this.Content(verification.Challenge); + return this.Content(challenge); } else { @@ -148,7 +163,7 @@ public async Task Subscribe(string subscriptionUrl, string topic, UID = subUID, Callback = new Uri(this.Request.Scheme + "://" + this.Request.Host + "/client/" + subUID), Events = events.Split(";", StringSplitOptions.RemoveEmptyEntries), - Mode = SubscriptionMode.Subscribe, + Mode = SubscriptionMode.subscribe, Secret = secret, LeaseSeconds = 3600, Topic = topic @@ -179,14 +194,14 @@ public async Task Subscribe(string subscriptionUrl, string topic, return View("FHIRcastClient", internalModel); } - [Route("unsubscribe/{subscriptionId}")] + [Route("Unsubscribe/{subscriptionId}")] [HttpPost] public async Task Unsubscribe(string subscriptionId) { this.logger.LogDebug($"Unsubscribing subscription {subscriptionId}"); if (!activeSubs.ContainsKey(subscriptionId)) { return View("FHIRcastClient", internalModel); } Subscription sub = activeSubs[subscriptionId]; - sub.Mode = SubscriptionMode.Unsubscribe; + sub.Mode = SubscriptionMode.unsubscribe; var httpClient = new HttpClient(); var result = await httpClient.PostAsync(sub.HubURL, diff --git a/Model/Subscriptions.cs b/Model/Subscriptions.cs index 9d9bb0d..40f284c 100644 --- a/Model/Subscriptions.cs +++ b/Model/Subscriptions.cs @@ -62,8 +62,8 @@ public class SubscriptionVerification : SubscriptionWithLease { } public enum SubscriptionMode { - Subscribe, - Unsubscribe, + subscribe, + unsubscribe, } public class SubscriptionComparer : IEqualityComparer { diff --git a/Rules/SubscriptionValidator.cs b/Rules/SubscriptionValidator.cs index b352215..e707889 100644 --- a/Rules/SubscriptionValidator.cs +++ b/Rules/SubscriptionValidator.cs @@ -18,40 +18,49 @@ public async Task ValidateSubscription(Subscription sub throw new ArgumentNullException(nameof(subscription)); } - SubscriptionBase callbackParameters = null; + + HttpResponseMessage response = null; + string challenge = Guid.NewGuid().ToString("n"); + if (outcome == HubValidationOutcome.Canceled) { logger.LogDebug("Simulating canceled subscription."); - callbackParameters = new SubscriptionCancelled + SubscriptionBase callbackParameters = new SubscriptionCancelled { Reason = $"The subscription {subscription} was canceled for testing purposes.", }; } else { logger.LogDebug("Verifying subscription."); - callbackParameters = new SubscriptionVerification + SubscriptionVerification callbackParameters = new SubscriptionVerification { // Note that this is not necessarily cryptographically random/secure. - Challenge = Guid.NewGuid().ToString("n"), - }; - } + Challenge = challenge, + LeaseSeconds = subscription.LeaseSeconds, + Callback = subscription.Callback, + Events = subscription.Events, + Mode = subscription.Mode, + Topic = subscription.Topic, + }; - // Default parametres for both cancel/verify. - callbackParameters.Callback = subscription.Callback; - callbackParameters.Events = subscription.Events; - callbackParameters.Mode = subscription.Mode; - callbackParameters.Topic = subscription.Topic; + logger.LogDebug($"Calling callback url: {subscription.Callback}"); + string verifyUrl = subscription.Callback + "?" + + $"&hub.mode={callbackParameters.Mode.ToString().ToLower()}" + + $"&hub.topic={callbackParameters.Topic}" + + $"&hub.challenge={callbackParameters.Challenge}" + + $"&hub.events={string.Join(",", callbackParameters.Events)}" + + $"&hub.lease_seconds={callbackParameters.LeaseSeconds}"; + response = await new HttpClient().GetAsync(verifyUrl); + } - logger.LogDebug($"Calling callback url: {subscription.Callback}"); - var callbackUri = new SubscriptionCallback().GetCallbackUri(subscription, callbackParameters); - var response = await new HttpClient().GetAsync(callbackUri); + if (!response.IsSuccessStatusCode) { logger.LogInformation($"Status code was not success but instead {response.StatusCode}"); return ClientValidationOutcome.NotVerified; } if (outcome == HubValidationOutcome.Valid) { - var challenge = ((SubscriptionVerification)callbackParameters).Challenge; + var responseBody = (await response.Content.ReadAsStringAsync()); if (responseBody != challenge) { logger.LogInformation($"Callback result for verification request was not equal to challenge. Response body: '{responseBody}', Challenge: '{challenge}'."); diff --git a/Rules/ValidateSubscriptionJob.cs b/Rules/ValidateSubscriptionJob.cs index 816461d..c21465b 100644 --- a/Rules/ValidateSubscriptionJob.cs +++ b/Rules/ValidateSubscriptionJob.cs @@ -16,7 +16,7 @@ public ValidateSubscriptionJob(ISubscriptionValidator validator, ISubscriptions } public async Task Run(Subscription subscription, bool simulateCancellation) { - if (subscription.Mode == SubscriptionMode.Subscribe) { + if (subscription.Mode == SubscriptionMode.subscribe) { HubValidationOutcome validationOutcome = simulateCancellation ? HubValidationOutcome.Canceled : HubValidationOutcome.Valid; var validationResult = await this.validator.ValidateSubscription(subscription, validationOutcome); if (validationResult == ClientValidationOutcome.Verified) { @@ -26,7 +26,7 @@ public async Task Run(Subscription subscription, bool simulateCancellation) { } else { this.logger.LogInformation($"Not adding unverified subscription: {subscription}."); } - } else if (subscription.Mode == SubscriptionMode.Unsubscribe) { + } else if (subscription.Mode == SubscriptionMode.unsubscribe) { this.subscriptions.RemoveSubscription(subscription); } }