Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

client url verification and unsubscribe #7

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions Controllers/FHIRcastClientController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,25 @@ public IActionResult Post([FromForm] ClientModel model)
/// <param name="verification">Hub's verification response to our subscription attempt</param>
/// <returns></returns>
[HttpGet("{subscriptionId}")]
public IActionResult Get(string subscriptionId, [FromQuery] SubscriptionVerification verification)
public IActionResult Get(string subscriptionId)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you see how validation is done when posting subscriptions? The validation is basically set on the model using attributes specifying what is required etc. The framework then generates error messages that can be used in the response (which should probably be Bad request and not Not found).

{
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(); }

Subscription sub = pendingSubs[subscriptionId];

//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
{
Expand Down Expand Up @@ -148,7 +152,7 @@ public async Task<IActionResult> 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
Expand Down Expand Up @@ -186,7 +190,7 @@ public async Task<IActionResult> 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,
Expand Down
4 changes: 2 additions & 2 deletions Model/Subscriptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ public class SubscriptionVerification : SubscriptionWithLease {
}

public enum SubscriptionMode {
Subscribe,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should change the Enum casing just to get an easy fix for ToString() being the correct case. Better to stick with the language convention here.

Unsubscribe,
subscribe,
unsubscribe,
}

public class SubscriptionComparer : IEqualityComparer<Subscription> {
Expand Down
39 changes: 24 additions & 15 deletions Rules/SubscriptionValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,49 @@ public async Task<ClientValidationOutcome> 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 + "?" +
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You moved the logic for constructing the URL from the SubscriptionCallback class and in here. Keep it in that class instead if you need to re-write it. A better commit message on why you're doing this re-write would be great.

$"&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}'.");
Expand Down
4 changes: 2 additions & 2 deletions Rules/ValidateSubscriptionJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
}
}
Expand Down