Skip to content
This repository was archived by the owner on Nov 17, 2023. It is now read-only.

Commit 6f4ae50

Browse files
committed
Port WebhookClient to WebApplicationBuilder
1 parent dbef61f commit 6f4ae50

File tree

13 files changed

+143
-196
lines changed

13 files changed

+143
-196
lines changed

src/Services/Identity/Identity.API/AppSettings.cs

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/Web/WebMVC/Extensions/Extensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public static void AddHealthChecks(this IServiceCollection services, IConfigurat
1010
.AddUrlGroup(_ => new Uri(configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" });
1111
}
1212

13-
public static void AddApplicationSevices(this IServiceCollection services, IConfiguration configuration)
13+
public static void AddApplicationServices(this IServiceCollection services, IConfiguration configuration)
1414
{
1515
services.Configure<AppSettings>(configuration);
1616

@@ -86,13 +86,13 @@ public static IEndpointConventionBuilder MapForwardSignalR(this WebApplication a
8686
{
8787
// Forward the SignalR traffic to the bff
8888
var destination = app.Configuration.GetRequiredValue("PurchaseUrl");
89-
var authTransformer = new BffAuthTransfomer();
89+
var authTransformer = new BffAuthTransformer();
9090
var requestConfig = new ForwarderRequestConfig();
9191

9292
return app.MapForwarder("/hub/notificationhub/{**any}", destination, requestConfig, authTransformer);
9393
}
9494

95-
private sealed class BffAuthTransfomer : HttpTransformer
95+
private sealed class BffAuthTransformer : HttpTransformer
9696
{
9797
public override async ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest, string destinationPrefix, CancellationToken cancellationToken)
9898
{

src/Web/WebMVC/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
builder.Services.AddControllersWithViews();
77

88
builder.Services.AddHealthChecks(builder.Configuration);
9-
builder.Services.AddApplicationSevices(builder.Configuration);
9+
builder.Services.AddApplicationServices(builder.Configuration);
1010
builder.Services.AddAuthenticationServices(builder.Configuration);
1111
builder.Services.AddHttpClientServices();
1212

src/Web/WebhookClient/Controllers/AccountController.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ public class AccountController : Controller
55
{
66
public async Task<IActionResult> SignIn(string returnUrl)
77
{
8-
var user = User as ClaimsPrincipal;
9-
108
var token = await HttpContext.GetTokenAsync("access_token");
119

1210
if (token != null)

src/Web/WebhookClient/Controllers/WebhooksReceivedController.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44
[Route("webhook-received")]
55
public class WebhooksReceivedController : Controller
66
{
7-
8-
private readonly Settings _settings;
7+
private readonly WebhookClientOptions _options;
98
private readonly ILogger _logger;
109
private readonly IHooksRepository _hooksRepository;
1110

12-
public WebhooksReceivedController(IOptions<Settings> settings, ILogger<WebhooksReceivedController> logger, IHooksRepository hooksRepository)
11+
public WebhooksReceivedController(IOptions<WebhookClientOptions> options, ILogger<WebhooksReceivedController> logger, IHooksRepository hooksRepository)
1312
{
14-
_settings = settings.Value;
13+
_options = options.Value;
1514
_logger = logger;
1615
_hooksRepository = hooksRepository;
1716
}
@@ -22,9 +21,9 @@ public async Task<IActionResult> NewWebhook(WebhookData hook)
2221
var header = Request.Headers[HeaderNames.WebHookCheckHeader];
2322
var token = header.FirstOrDefault();
2423

25-
_logger.LogInformation("Received hook with token {Token}. My token is {MyToken}. Token validation is set to {ValidateToken}", token, _settings.Token, _settings.ValidateToken);
24+
_logger.LogInformation("Received hook with token {Token}. My token is {MyToken}. Token validation is set to {ValidateToken}", token, _options.Token, _options.ValidateToken);
2625

27-
if (!_settings.ValidateToken || _settings.Token == token)
26+
if (!_options.ValidateToken || _options.Token == token)
2827
{
2928
_logger.LogInformation("Received hook is going to be processed");
3029
var newHook = new WebHookReceived()
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
namespace WebhookClient;
2+
3+
internal static class Extensions
4+
{
5+
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
6+
{
7+
var identityUrl = configuration.GetValue<string>("IdentityUrl");
8+
var callBackUrl = configuration.GetValue<string>("CallBackUrl");
9+
10+
// Add Authentication services
11+
12+
services.AddAuthentication(options =>
13+
{
14+
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
15+
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
16+
})
17+
.AddCookie(setup => setup.ExpireTimeSpan = TimeSpan.FromHours(2))
18+
.AddOpenIdConnect(options =>
19+
{
20+
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
21+
options.Authority = identityUrl.ToString();
22+
options.SignedOutRedirectUri = callBackUrl.ToString();
23+
options.ClientId = "webhooksclient";
24+
options.ClientSecret = "secret";
25+
options.ResponseType = "code";
26+
options.SaveTokens = true;
27+
options.GetClaimsFromUserInfoEndpoint = true;
28+
options.RequireHttpsMetadata = false;
29+
options.Scope.Add("openid");
30+
options.Scope.Add("webhooks");
31+
});
32+
33+
return services;
34+
}
35+
36+
public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration)
37+
{
38+
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
39+
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
40+
services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(Timeout.InfiniteTimeSpan);
41+
42+
//add http client services
43+
services.AddHttpClient("GrantClient")
44+
.SetHandlerLifetime(TimeSpan.FromMinutes(5))
45+
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>();
46+
47+
return services;
48+
}
49+
}
Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
namespace WebhookClient;
22

3-
public class HttpClientAuthorizationDelegatingHandler
4-
: DelegatingHandler
3+
public class HttpClientAuthorizationDelegatingHandler : DelegatingHandler
54
{
65
private readonly IHttpContextAccessor _httpContextAccessor;
76

@@ -12,15 +11,14 @@ public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContext
1211

1312
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
1413
{
15-
var authorizationHeader = _httpContextAccessor.HttpContext
16-
.Request.Headers["Authorization"];
14+
var authorizationHeader = _httpContextAccessor.HttpContext.Request.Headers["Authorization"];
1715

1816
if (!string.IsNullOrEmpty(authorizationHeader))
1917
{
2018
request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
2119
}
2220

23-
var token = await GetToken();
21+
var token = await _httpContextAccessor.HttpContext.GetTokenAsync("access_token");
2422

2523
if (token != null)
2624
{
@@ -29,12 +27,4 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
2927

3028
return await base.SendAsync(request, cancellationToken);
3129
}
32-
33-
async Task<string> GetToken()
34-
{
35-
const string ACCESS_TOKEN = "access_token";
36-
37-
return await _httpContextAccessor.HttpContext
38-
.GetTokenAsync(ACCESS_TOKEN);
39-
}
4030
}

src/Web/WebhookClient/Pages/RegisterWebhook.cshtml.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace WebhookClient.Pages
77

88
public class RegisterWebhookModel : PageModel
99
{
10-
private readonly Settings _settings;
10+
private readonly WebhookClientOptions _options;
1111
private readonly IHttpClientFactory _httpClientFactory;
1212

1313
[BindProperty] public string Token { get; set; }
@@ -18,23 +18,23 @@ public class RegisterWebhookModel : PageModel
1818
public string ResponseMessage { get; set; }
1919
public string RequestBodyJson { get; set; }
2020

21-
public RegisterWebhookModel(IOptions<Settings> settings, IHttpClientFactory httpClientFactory)
21+
public RegisterWebhookModel(IOptions<WebhookClientOptions> options, IHttpClientFactory httpClientFactory)
2222
{
23-
_settings = settings.Value;
23+
_options = options.Value;
2424
_httpClientFactory = httpClientFactory;
2525
}
2626

2727
public void OnGet()
2828
{
2929
ResponseCode = (int)HttpStatusCode.OK;
30-
Token = _settings.Token;
30+
Token = _options.Token;
3131
}
3232

3333
public async Task<IActionResult> OnPost()
3434
{
3535
ResponseCode = (int)HttpStatusCode.OK;
3636
var protocol = Request.IsHttps ? "https" : "http";
37-
var selfurl = !string.IsNullOrEmpty(_settings.SelfUrl) ? _settings.SelfUrl : $"{protocol}://{Request.Host}/{Request.PathBase}";
37+
var selfurl = !string.IsNullOrEmpty(_options.SelfUrl) ? _options.SelfUrl : $"{protocol}://{Request.Host}/{Request.PathBase}";
3838
if (!selfurl.EndsWith("/"))
3939
{
4040
selfurl = selfurl + "/";
@@ -50,7 +50,7 @@ public async Task<IActionResult> OnPost()
5050
Url = url,
5151
Token = Token
5252
};
53-
var response = await client.PostAsync<WebhookSubscriptionRequest>(_settings.WebhooksUrl + "/api/v1/webhooks", payload, new JsonMediaTypeFormatter());
53+
var response = await client.PostAsync<WebhookSubscriptionRequest>(_options.WebhooksUrl + "/api/v1/webhooks", payload, new JsonMediaTypeFormatter());
5454

5555
if (response.IsSuccessStatusCode)
5656
{
@@ -68,4 +68,4 @@ public async Task<IActionResult> OnPost()
6868
return Page();
6969
}
7070
}
71-
}
71+
}

src/Web/WebhookClient/Program.cs

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,71 @@
1-
CreateWebHostBuilder(args).Build().Run();
1+
var builder = WebApplication.CreateBuilder(args);
22

3+
builder.Services.AddSession(opt =>
4+
{
5+
opt.Cookie.Name = ".eShopWebhooks.Session";
6+
})
7+
.Configure<WebhookClientOptions>(builder.Configuration)
8+
.AddHttpClientServices(builder.Configuration)
9+
.AddCustomAuthentication(builder.Configuration)
10+
.AddTransient<IWebhooksClient, WebhooksClient>()
11+
.AddSingleton<IHooksRepository, InMemoryHooksRepository>()
12+
.AddMvc();
13+
builder.Services.AddControllers();
14+
var app = builder.Build();
315

4-
IWebHostBuilder CreateWebHostBuilder(string[] args) =>
5-
WebHost.CreateDefaultBuilder(args)
6-
.UseStartup<Startup>();
16+
var pathBase = app.Configuration["PATH_BASE"];
17+
if (!string.IsNullOrEmpty(pathBase))
18+
{
19+
app.UsePathBase(pathBase);
20+
}
21+
22+
if (!app.Environment.IsDevelopment())
23+
{
24+
app.UseExceptionHandler("/Error");
25+
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
26+
}
27+
28+
app.Map("/check", capp =>
29+
{
30+
capp.Run(async (context) =>
31+
{
32+
if ("OPTIONS".Equals(context.Request.Method, StringComparison.InvariantCultureIgnoreCase))
33+
{
34+
var validateToken = bool.TrueString.Equals(builder.Configuration["ValidateToken"], StringComparison.InvariantCultureIgnoreCase);
35+
var header = context.Request.Headers[HeaderNames.WebHookCheckHeader];
36+
var value = header.FirstOrDefault();
37+
var tokenToValidate = builder.Configuration["Token"];
38+
if (!validateToken || value == tokenToValidate)
39+
{
40+
if (!string.IsNullOrWhiteSpace(tokenToValidate))
41+
{
42+
context.Response.Headers.Add(HeaderNames.WebHookCheckHeader, tokenToValidate);
43+
}
44+
context.Response.StatusCode = (int)HttpStatusCode.OK;
45+
}
46+
else
47+
{
48+
await context.Response.WriteAsync("Invalid token");
49+
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
50+
}
51+
}
52+
else
53+
{
54+
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
55+
}
56+
});
57+
});
58+
59+
// Fix samesite issue when running eShop from docker-compose locally as by default http protocol is being used
60+
// Refer to https://github.com/dotnet-architecture/eShopOnContainers/issues/1391
61+
app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax });
62+
63+
app.UseStaticFiles();
64+
app.UseSession();
65+
app.UseRouting();
66+
app.UseAuthentication();
67+
app.UseAuthorization();
68+
app.MapDefaultControllerRoute();
69+
app.MapRazorPages();
70+
71+
await app.RunAsync();

src/Web/WebhookClient/Services/WebhooksClient.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@
22

33
public class WebhooksClient : IWebhooksClient
44
{
5-
65
private readonly IHttpClientFactory _httpClientFactory;
7-
private readonly Settings _settings;
8-
public WebhooksClient(IHttpClientFactory httpClientFactory, IOptions<Settings> settings)
6+
private readonly WebhookClientOptions _options;
7+
public WebhooksClient(IHttpClientFactory httpClientFactory, IOptions<WebhookClientOptions> options)
98
{
109
_httpClientFactory = httpClientFactory;
11-
_settings = settings.Value;
10+
_options = options.Value;
1211
}
1312
public async Task<IEnumerable<WebhookResponse>> LoadWebhooks()
1413
{
1514
var client = _httpClientFactory.CreateClient("GrantClient");
16-
var response = await client.GetAsync(_settings.WebhooksUrl + "/api/v1/webhooks");
15+
var response = await client.GetAsync(_options.WebhooksUrl + "/api/v1/webhooks");
1716
var json = await response.Content.ReadAsStringAsync();
1817
var subscriptions = JsonSerializer.Deserialize<IEnumerable<WebhookResponse>>(json, new JsonSerializerOptions
1918
{

0 commit comments

Comments
 (0)