using System; using System.Threading.Tasks; using HealthChecks.UI.Client; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using IdentityModel; using Duende.IdentityServer; using Duende.IdentityServer.Configuration; using LiteCharmsSecurity.Admin.EntityFramework.Shared.DbContexts; using LiteCharmsSecurity.Admin.EntityFramework.Shared.Entities.Identity; using Skoruba.Duende.IdentityServer.Shared.Configuration.Helpers; using LiteCharmsSecurity.STS.Identity.Configuration; using LiteCharmsSecurity.STS.Identity.Configuration.Constants; using LiteCharmsSecurity.STS.Identity.Configuration.Interfaces; using LiteCharmsSecurity.STS.Identity.Helpers; using LiteCharmsSecurity.STS.Identity.Passkeys; using Microsoft.AspNetCore.Identity; namespace LiteCharmsSecurity.STS.Identity { public class Startup { public IConfiguration Configuration { get; } public IWebHostEnvironment Environment { get; } public Startup(IWebHostEnvironment environment, IConfiguration configuration) { Configuration = configuration; Environment = environment; } public void ConfigureServices(IServiceCollection services) { var rootConfiguration = CreateRootConfiguration(); services.AddSingleton(rootConfiguration); // Configure ServerSideSessions services.Configure(Configuration.GetSection(ServerSideSessionsConfiguration.SectionName)); // Register DbContexts for IdentityServer and Identity RegisterDbContexts(services); // Save data protection keys to db, using a common application name shared between Admin and STS services.AddDataProtection(Configuration); // Add email senders which is currently setup for SendGrid and SMTP services.AddEmailSenders(Configuration); // Add services for authentication, including Identity model and external providers RegisterAuthentication(services); // Add HSTS options RegisterHstsOptions(services); // Add all dependencies for Asp.Net Core Identity in MVC - these dependencies are injected into generic Controllers // Including settings for MVC and Localization // If you want to change primary keys or use another db model for Asp.Net Core Identity: services.AddMvcWithLocalization(Configuration); services.AddRazorPages(); // Add authorization policies for MVC RegisterAuthorization(services); // Add IHttpContextAccessor for Passkey TagHelper services.AddHttpContextAccessor(); // Configure IdentityPasskeyOptions for development if (Environment.IsDevelopment()) { services.Configure(options => { // Allow localhost origins for development options.ValidateOrigin = context => ValueTask.FromResult( context.Origin.StartsWith("https://localhost") || context.Origin.StartsWith("http://localhost")); }); } services.AddIdSHealthChecks(Configuration); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseCookiePolicy(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } app.UsePathBase(Configuration.GetValue("BasePath")); app.UseStaticFiles(); UseAuthentication(app); // Add custom security headers app.UseSecurityHeaders(Configuration); app.UseMvcLocalizationServices(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoint => { // Map passkey endpoints for passkey authentication endpoint.MapPasskeyEndpoints(); endpoint.MapDefaultControllerRoute(); endpoint.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); }); } public virtual void RegisterDbContexts(IServiceCollection services) { services.RegisterDbContexts(Configuration); } public virtual void RegisterAuthentication(IServiceCollection services) { services.AddAuthenticationServices(Configuration); services.AddIdentityServer(Configuration); } public virtual void RegisterAuthorization(IServiceCollection services) { var rootConfiguration = CreateRootConfiguration(); services.AddAuthorizationPolicies(rootConfiguration); } public virtual void UseAuthentication(IApplicationBuilder app) { app.UseIdentityServer(); } public virtual void RegisterHstsOptions(IServiceCollection services) { services.AddHsts(options => { options.Preload = true; options.IncludeSubDomains = true; options.MaxAge = TimeSpan.FromDays(365); }); } protected IRootConfiguration CreateRootConfiguration() { var rootConfiguration = new RootConfiguration(); Configuration.GetSection(ConfigurationConsts.AdminConfigurationKey).Bind(rootConfiguration.AdminConfiguration); Configuration.GetSection(ConfigurationConsts.RegisterConfigurationKey).Bind(rootConfiguration.RegisterConfiguration); return rootConfiguration; } } }