// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // add singleton to allow Controllers to query the Request object services .AddSingleton <IHttpContextAccessor, HttpContextAccessor>() .AddSingleton(configuration) .AddDbContext <EmbcDbContext>( options => options .UseLoggerFactory(loggerFactory) .UseSqlServer(DatabaseTools.GetConnectionString(configuration)) ) // CORS policy .AddCors(opts => { opts.AddDefaultPolicy(builder => { builder.WithOrigins( "http://pathfinder.bcgov", "https://*.pathfinder.gov.bc.ca", "https://dev.justice.gov.bc.ca", "https://test.justice.gov.bc.ca", "https://justice.gov.bc.ca") .SetIsOriginAllowedToAllowWildcardSubdomains(); }); }) //XSRF token for Angular - not working yet //.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN") .AddSession() .AddMvc(opts => { // authorize on all controllers by default opts.Filters.Add(new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build())); // anti forgery validation by default - not working yet //opts.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()); }) .AddJsonOptions( opts => { opts.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; opts.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat; opts.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc; opts.SerializerSettings.DateParseHandling = Newtonsoft.Json.DateParseHandling.DateTimeOffset; opts.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; }); // Register the Swagger services services.AddSwaggerDocument(config => { config.PostProcess = document => { document.Info.Version = "v1"; document.Info.Title = "ESS API"; document.Info.Description = "Emergency Management BC Evacuee Support System API"; }; } ); // setup siteminder authentication services.AddAuthentication(options => { options.DefaultAuthenticateScheme = SiteMinderAuthOptions.AuthenticationSchemeName; options.DefaultChallengeScheme = SiteMinderAuthOptions.AuthenticationSchemeName; }).AddSiteminderAuth(); // In production, the Angular files will be served from this directory services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; }); // health checks services.AddHealthChecks(checks => { checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask <IHealthCheckResult>(HealthCheckResult.Healthy("Ok"))); checks.AddSqlCheck(configuration.GetDbName(), DatabaseTools.GetConnectionString(configuration)); }); services.AddAutoMapper(typeof(Startup)); services.AddMediatR(typeof(Startup)); services.AddTransient <IEmailSender, EmailSender>(); services.AddTransient <IPdfConverter, PdfConverter>(); services.AddTransient <IReferralsService, ReferralsService>(); services.AddTransient <IDataInterface, DataInterface>(); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // add singleton to allow Controllers to query the Request object services .AddSingleton <IHttpContextAccessor, HttpContextAccessor>() .AddSingleton(configuration) .AddDbContext <EmbcDbContext>( options => options .UseLoggerFactory(loggerFactory) .UseSqlServer(DatabaseTools.GetConnectionString(configuration)) ) // CORS policy .AddCors(opts => { opts.AddDefaultPolicy(builder => { builder.WithOrigins( "http://pathfinder.bcgov", "https://*.pathfinder.gov.bc.ca", "https://dev.justice.gov.bc.ca", "https://test.justice.gov.bc.ca", "https://justice.gov.bc.ca") .SetIsOriginAllowedToAllowWildcardSubdomains(); }); }) //XSRF token for Angular - not working yet //.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN") .AddMvc(opts => { // anti forgery validation by default - not working yet //opts.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()); }) .AddJsonOptions( opts => { opts.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; opts.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat; opts.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc; opts.SerializerSettings.DateParseHandling = Newtonsoft.Json.DateParseHandling.DateTimeOffset; opts.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; }); // Register the Swagger services services.AddSwaggerDocument(config => { config.PostProcess = document => { document.Info.Version = "v1"; document.Info.Title = "ESS API"; document.Info.Description = "Emergency Management BC Evacuee Support System API"; }; } ); services.AddScoped <KeyCloakClaimTransformer, KeyCloakClaimTransformer>(); services.AddAuthentication(options => { //Default to cookie auth, challenge with OIDC options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) //JWT bearer to support direct API authentication .AddJwtBearer(options => { configuration.GetSection("auth:jwt").Bind(options); options.Events = new JwtBearerEvents { OnAuthenticationFailed = async c => { var logger = c.HttpContext.RequestServices.GetRequiredService <ILogger <JwtBearerHandler> >(); logger.LogError(c.Exception, $"Error authenticating JWTBearer token"); c.Response.StatusCode = StatusCodes.Status401Unauthorized; c.Response.ContentType = "text/plain"; if (environment.IsDevelopment()) { // Debug only, in production do not share exceptions with the remote host. await c.Response.WriteAsync(c.Exception.ToString()); } await c.Response.WriteAsync("An error occurred processing yourauthentication."); }, OnTokenValidated = async c => { var claimTransformer = c.HttpContext.RequestServices.GetRequiredService <KeyCloakClaimTransformer>(); c.Principal = await claimTransformer.TransformAsync(c.Principal); c.Success(); } }; }) //cookies as default and sign in, principal will be saved as a cookie (no need to session state) .AddCookie(options => { configuration.GetSection("auth:cookie").Bind(options); options.Cookie.SameSite = SameSiteMode.Strict; options.LoginPath = "/login"; }) .AddOpenIdConnect(options => //oidc authentication for challenge authentication request { configuration.GetSection("auth:oidc").Bind(options); options.Events = new OpenIdConnectEvents() { OnAuthenticationFailed = async c => { var logger = c.HttpContext.RequestServices.GetRequiredService <ILogger <JwtBearerHandler> >(); logger.LogError(c.Exception, $"Error authenticating OIDC token"); c.HandleResponse(); c.Response.StatusCode = StatusCodes.Status401Unauthorized; c.Response.ContentType = "text/plain"; if (environment.IsDevelopment()) { // Debug only, in production do not share exceptions with the remote host. await c.Response.WriteAsync(c.Exception.ToString()); } await c.Response.WriteAsync("An error occurred processing your authentication."); }, OnTicketReceived = async c => { var claimTransformer = c.HttpContext.RequestServices.GetRequiredService <KeyCloakClaimTransformer>(); c.Principal = await claimTransformer.TransformAsync(c.Principal); c.Success(); } }; }); services.AddAuthorization(options => { //API authorization policy supports cookie or jwt authentication schemes options.AddPolicy("API", policy => { policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme, CookieAuthenticationDefaults.AuthenticationScheme); policy.RequireAuthenticatedUser(); }); //Set API policy as default for [authorize] controllers options.DefaultPolicy = options.GetPolicy("API"); }); services.Configure <CookiePolicyOptions>(options => { options.Secure = environment.IsDevelopment() ? CookieSecurePolicy.SameAsRequest : CookieSecurePolicy.Always; options.MinimumSameSitePolicy = SameSiteMode.None; }); // In production, the Angular files will be served from this directory services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; }); // health checks services.AddHealthChecks(checks => { checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask <IHealthCheckResult>(HealthCheckResult.Healthy("Ok"))); }); var keyRingPath = configuration.GetKeyRingPath(); var dpBuilder = services.AddDataProtection(); if (!string.IsNullOrEmpty(keyRingPath)) { log.LogInformation($"Setting data protection keys to persist in {keyRingPath}"); dpBuilder.PersistKeysToFileSystem(new DirectoryInfo(keyRingPath)); } else { log.LogWarning("data protection key folder is not set, check if KEY_RING_DIRECTORY env var is missing"); } services.AddAutoMapper(typeof(Startup)); services.AddMediatR(typeof(Startup)); services.AddTransient <IEmailSender, EmailSender>(); services.AddTransient <IPdfConverter, PdfConverter>(); services.AddTransient <IReferralsService, ReferralsService>(); services.AddTransient <IDataInterface, DataInterface>(); // Using AddScoped rather than transient because of state. Might be incorrect. services.AddScoped <ICurrentUser, CurrentUserService>(); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddSingleton <IConfiguration>(Configuration); // add singleton to allow Controllers to query the Request object services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddDbContext <EmbcDbContext>( options => options .UseSqlServer(DatabaseTools.GetConnectionString(Configuration))); // Add a memory cache services.AddMemoryCache(); // Add CORS policy services.AddCors(options => { options.AddPolicy("AllowAnyOrigin", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader()); }); // for security reasons, the following headers are set. services.AddMvc(opts => { // default deny var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); opts.Filters.Add(new AuthorizeFilter(policy)); opts.Filters.Add(typeof(NoCacheHttpHeadersAttribute)); opts.Filters.Add(new XRobotsTagAttribute() { NoIndex = true, NoFollow = true }); opts.Filters.Add(typeof(XContentTypeOptionsAttribute)); opts.Filters.Add(typeof(XDownloadOptionsAttribute)); opts.Filters.Add(typeof(XFrameOptionsAttribute)); opts.Filters.Add(typeof(XXssProtectionAttribute)); //CSPReportOnly opts.Filters.Add(typeof(CspReportOnlyAttribute)); opts.Filters.Add(new CspScriptSrcReportOnlyAttribute { None = true }); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) .AddJsonOptions( opts => { opts.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; opts.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat; opts.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc; opts.SerializerSettings.DateParseHandling = Newtonsoft.Json.DateParseHandling.DateTimeOffset; // ReferenceLoopHandling is set to Ignore to prevent JSON parser issues with the // user / roles model. opts.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; }); // setup siteminder authentication (core 2.0) services.AddAuthentication(options => { options.DefaultAuthenticateScheme = SiteMinderAuthOptions.AuthenticationSchemeName; options.DefaultChallengeScheme = SiteMinderAuthOptions.AuthenticationSchemeName; }).AddSiteminderAuth(options => { }); // setup key ring to persist in storage. if (!string.IsNullOrEmpty(Configuration["KEY_RING_DIRECTORY"])) { services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(Configuration["KEY_RING_DIRECTORY"])); } // In production, the Angular files will be served from this directory services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; }); // health checks services.AddHealthChecks(checks => { checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask <IHealthCheckResult>(HealthCheckResult.Healthy("Ok"))); //checks.AddSqlCheck(DatabaseTools.GetDatabaseName(Configuration), DatabaseTools.GetConnectionString(Configuration)); }); services.AddSession(); // add a data interface services.AddTransient <IDataInterface, DataInterface>(); //AutoMapper services.AddAutoMapper(typeof(Startup)); // Enable the IURLHelper to be able to build links within Controllers services.AddSingleton <IActionContextAccessor, ActionContextAccessor>(); services.AddScoped <IUrlHelper>(x => { var actionContext = x.GetRequiredService <IActionContextAccessor>().ActionContext; var factory = x.GetRequiredService <IUrlHelperFactory>(); return(factory.GetUrlHelper(actionContext)); }); services.AddTransient <IEmailSender, EmailSender>(); services.AddTransient <IPdfConverter, PdfConverter>(); services.AddTransient <IReferralsService, ReferralsService>(); services.AddMediatR(typeof(Startup).GetTypeInfo().Assembly); }