namespace WebhookClient; public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddSession(opt => { opt.Cookie.Name = ".eShopWebhooks.Session"; }) .AddConfiguration(Configuration) .AddHttpClientServices(Configuration) .AddCustomAuthentication(Configuration) .AddTransient() .AddSingleton() .AddMvc(); services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { var pathBase = Configuration["PATH_BASE"]; if (!string.IsNullOrEmpty(pathBase)) { app.UsePathBase(pathBase); } if (!env.IsDevelopment()) { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. } app.Map("/check", capp => { capp.Run(async (context) => { if ("OPTIONS".Equals(context.Request.Method, StringComparison.InvariantCultureIgnoreCase)) { var validateToken = bool.TrueString.Equals(Configuration["ValidateToken"], StringComparison.InvariantCultureIgnoreCase); var header = context.Request.Headers[HeaderNames.WebHookCheckHeader]; var value = header.FirstOrDefault(); var tokenToValidate = Configuration["Token"]; if (!validateToken || value == tokenToValidate) { if (!string.IsNullOrWhiteSpace(tokenToValidate)) { context.Response.Headers.Add(HeaderNames.WebHookCheckHeader, tokenToValidate); } context.Response.StatusCode = (int)HttpStatusCode.OK; } else { await context.Response.WriteAsync("Invalid token"); context.Response.StatusCode = (int)HttpStatusCode.BadRequest; } } else { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; } }); }); // Fix samesite issue when running eShop from docker-compose locally as by default http protocol is being used // Refer to https://github.com/dotnet-architecture/eShopOnContainers/issues/1391 app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax }); app.UseStaticFiles(); app.UseSession(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); endpoints.MapRazorPages(); }); } } static class ServiceExtensions { public static IServiceCollection AddConfiguration(this IServiceCollection services, IConfiguration configuration) { services.Configure(configuration); return services; } public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) { var identityUrl = configuration.GetValue("IdentityUrl"); var callBackUrl = configuration.GetValue("CallBackUrl"); // Add Authentication services services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie(setup => setup.ExpireTimeSpan = TimeSpan.FromHours(2)) .AddOpenIdConnect(options => { options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.Authority = identityUrl.ToString(); options.SignedOutRedirectUri = callBackUrl.ToString(); options.ClientId = "webhooksclient"; options.ClientSecret = "secret"; options.ResponseType = "code"; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.RequireHttpsMetadata = false; options.Scope.Add("openid"); options.Scope.Add("webhooks"); }); return services; } public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration) { services.AddSingleton(); services.AddTransient(); services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(Timeout.InfiniteTimeSpan); //add http client services services.AddHttpClient("GrantClient") .SetHandlerLifetime(TimeSpan.FromMinutes(5)) .AddHttpMessageHandler(); return services; } }