Skip to content

Commit e6ce78b

Browse files
authored
Merge pull request #49 from rubberduck-vba/webhook
fix authentication
2 parents fd6189c + 1933268 commit e6ce78b

7 files changed

+68
-39
lines changed

rubberduckvba.Server/Api/Admin/AdminController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class AdminController(ConfigurationOptions options, HangfireLauncherServi
1212
/// Enqueues a job that updates xmldoc content from the latest release/pre-release tags.
1313
/// </summary>
1414
/// <returns>The unique identifier of the enqueued job.</returns>
15-
[Authorize("github", AuthenticationSchemes = "github")]
15+
[Authorize("github")]
1616
[HttpPost("admin/update/xmldoc")]
1717
public IActionResult UpdateXmldocContent()
1818
{
@@ -24,7 +24,7 @@ public IActionResult UpdateXmldocContent()
2424
/// Enqueues a job that gets the latest release/pre-release tags and their respective assets, and updates the installer download stats.
2525
/// </summary>
2626
/// <returns>The unique identifier of the enqueued job.</returns>
27-
[Authorize("github", AuthenticationSchemes = "github")]
27+
[Authorize("github")]
2828
[HttpPost("admin/update/tags")]
2929
public IActionResult UpdateTagMetadata()
3030
{
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
namespace rubberduckvba.Server.Api.Admin;
2+
3+
public record class PushWebhookPayload
4+
{
5+
public string Ref { get; set; }
6+
7+
public bool Created { get; set; }
8+
public bool Deleted { get; set; }
9+
public bool Forced { get; set; }
10+
11+
public WebhookPayloadSender Sender { get; set; }
12+
public WebhookPayloadRepository Repository { get; set; }
13+
14+
public record class WebhookPayloadSender
15+
{
16+
public string Login { get; set; }
17+
}
18+
19+
public record class WebhookPayloadRepository
20+
{
21+
public int Id { get; set; }
22+
public string Name { get; set; }
23+
public WebhookPayloadRepositoryOwner Owner { get; set; }
24+
25+
public record class WebhookPayloadRepositoryOwner
26+
{
27+
public int Id { get; set; }
28+
public string Login { get; set; }
29+
public string Type { get; set; }
30+
}
31+
}
32+
}

rubberduckvba.Server/Api/Admin/WebhookController.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using Microsoft.AspNetCore.Authorization;
22
using Microsoft.AspNetCore.Mvc;
3-
using Newtonsoft.Json.Linq;
43

54
namespace rubberduckvba.Server.Api.Admin;
65

@@ -20,9 +19,9 @@ public WebhookController(
2019
_hangfire = hangfire;
2120
}
2221

23-
[Authorize("webhook", AuthenticationSchemes = "webhook-signature")]
22+
[Authorize("webhook")]
2423
[HttpPost("webhook/github")]
25-
public IActionResult GitHub([FromBody] JToken payload)
24+
public IActionResult GitHub([FromBody] PushWebhookPayload payload)
2625
{
2726
var eventType = _validator.Validate(payload, Request.Headers, out var content, out var gitref);
2827

@@ -34,6 +33,11 @@ public IActionResult GitHub([FromBody] JToken payload)
3433
Logger.LogInformation(message);
3534
return Ok(message);
3635
}
36+
else if (eventType == WebhookPayloadType.Ping)
37+
{
38+
Logger.LogInformation("Webhook ping event was accepted; nothing to process.");
39+
return Ok();
40+
}
3741
else if (eventType == WebhookPayloadType.Greeting)
3842
{
3943
Logger.LogInformation("Webhook push event was accepted; nothing to process. {content}", content);

rubberduckvba.Server/Api/Admin/WebhookPayloadType.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ public enum WebhookPayloadType
44
{
55
Unsupported,
66
Greeting,
7+
Ping,
78
Push
89
}
Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,26 @@
1-
using Newtonsoft.Json.Linq;
2-
3-
namespace rubberduckvba.Server.Api.Admin;
1+
namespace rubberduckvba.Server.Api.Admin;
42

53
public class WebhookPayloadValidationService(ConfigurationOptions options)
64
{
7-
public WebhookPayloadType Validate(JToken payload, IHeaderDictionary headers, out string? content, out GitRef? gitref)
5+
public WebhookPayloadType Validate(PushWebhookPayload payload, IHeaderDictionary headers, out string? content, out GitRef? gitref)
86
{
97
content = default;
10-
gitref = default;
118

12-
if (!IsValidHeaders(headers) || !IsValidSource(payload) || !IsValidEvent(payload))
9+
gitref = new GitRef(payload.Ref);
10+
if (headers["X-GitHub-Event"].FirstOrDefault() == "ping")
1311
{
14-
return WebhookPayloadType.Unsupported;
12+
if (!(payload.Created && gitref.Value.IsTag))
13+
{
14+
return WebhookPayloadType.Greeting;
15+
}
16+
return WebhookPayloadType.Ping;
1517
}
1618

17-
gitref = new GitRef(payload.Value<string>("ref"));
18-
if (!(payload.Value<bool>("created") && gitref.HasValue && gitref.Value.IsTag))
19+
if (headers["X-GitHub-Event"].FirstOrDefault() == "push")
1920
{
20-
content = payload.Value<string>("zen");
21-
return WebhookPayloadType.Greeting;
21+
return WebhookPayloadType.Push;
2222
}
2323

24-
return WebhookPayloadType.Push;
25-
}
26-
27-
private bool IsValidHeaders(IHeaderDictionary headers) =>
28-
headers.TryGetValue("X-GitHub-Event", out Microsoft.Extensions.Primitives.StringValues values) && values.Contains("push");
29-
30-
private bool IsValidSource(JToken payload) =>
31-
payload["repository"].Value<string>("name") == options.GitHubOptions.Value.Rubberduck &&
32-
payload["owner"].Value<int>("id") == options.GitHubOptions.Value.RubberduckOrgId;
33-
34-
private bool IsValidEvent(JToken payload)
35-
{
36-
var ev = payload["hook"]?["events"]?.Values<string>() ?? [];
37-
return ev.Contains("push");
24+
return WebhookPayloadType.Unsupported;
3825
}
3926
}

rubberduckvba.Server/Program.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
using rubberduckvba.Server.Services.rubberduckdb;
2222
using System.Diagnostics;
2323
using System.Reflection;
24-
using System.Security.Claims;
2524

2625
namespace rubberduckvba.Server;
2726

@@ -43,12 +42,12 @@ public static void Main(string[] args)
4342
builder.Services.Configure<ApiSettings>(options => builder.Configuration.GetSection("Api").Bind(options));
4443
builder.Services.Configure<HangfireSettings>(options => builder.Configuration.GetSection("Hangfire").Bind(options));
4544

46-
4745
builder.Services.AddAuthentication(options =>
4846
{
4947
options.RequireAuthenticatedSignIn = false;
48+
5049
options.DefaultAuthenticateScheme = "github";
51-
options.DefaultChallengeScheme = "github";
50+
options.DefaultScheme = "anonymous";
5251

5352
options.AddScheme("github", builder =>
5453
{
@@ -59,18 +58,16 @@ public static void Main(string[] args)
5958
builder.HandlerType = typeof(WebhookAuthenticationHandler);
6059
});
6160
});
61+
6262
builder.Services.AddAuthorization(options =>
6363
{
6464
options.AddPolicy("github", builder =>
6565
{
66-
builder.RequireAuthenticatedUser();
66+
builder.RequireAuthenticatedUser().AddAuthenticationSchemes("github");
6767
});
6868
options.AddPolicy("webhook", builder =>
6969
{
70-
builder.RequireAuthenticatedUser()
71-
.RequireClaim(ClaimTypes.Authentication, "webhook-signature")
72-
.RequireClaim(ClaimTypes.Role, "rubberduck-webhook")
73-
.RequireClaim(ClaimTypes.Name, "rubberduck-vba-releasebot");
70+
builder.RequireAuthenticatedUser().AddAuthenticationSchemes("webhook-signature");
7471
});
7572
});
7673

@@ -164,6 +161,8 @@ private static void ConfigureServices(IServiceCollection services)
164161
services.AddSingleton<IMarkdownFormattingService, MarkdownFormattingService>();
165162
services.AddSingleton<ISyntaxHighlighterService, SyntaxHighlighterService>();
166163
services.AddSingleton<WebhookSignatureValidationService>();
164+
services.AddSingleton<WebhookPayloadValidationService>();
165+
services.AddSingleton<HangfireLauncherService>();
167166

168167
services.AddSingleton<IRubberduckDbService, RubberduckDbService>();
169168
services.AddSingleton<TagServices>();

rubberduckvba.Server/WebhookSignatureValidationService.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ string[] xHubSignature256
2424

2525
if (!xGitHubEvent.Contains("push"))
2626
{
27-
// only authenticate push events
27+
if (xGitHubEvent.Contains("ping"))
28+
{
29+
// no harm just returning 200-OK on ping
30+
return true;
31+
}
32+
33+
// only authenticate ping and push events
2834
return false;
2935
}
3036

0 commit comments

Comments
 (0)