Example #1
0
        // 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>();
        }
Example #2
0
        // 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>();
        }
Example #3
0
        // 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);
        }