Ejemplo n.º 1
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // retrieve smtp config from environment variable (needed for configuring both identity email confirm and email service)
            string smtpConfig = Configuration.GetValue <string>("BOOKING_SMTP");
            // determine whether email confirmation should be configured (enable for testing)
            bool emailConfirmation = string.IsNullOrEmpty(smtpConfig) ? HostingEnvironment.IsEnvironment("Development_WebAPI_Test") ? true : false : true;

            // configure data protection rules explicitly (linux hosts require this for the persistence of keys)
            // note: for production environments, set up a protector to interface with an external HSM/Key management system
            services.AddDataProtection()
            .SetApplicationName("angularbooking")
            .PersistKeysToFileSystem(new DirectoryInfo("/keys"));

            // configure CORS
            services.AddCors(options =>
            {
                options.AddPolicy("Default", builder =>
                                  builder.
                                  AllowAnyHeader().
                                  AllowAnyOrigin().
                                  AllowAnyMethod().
                                  AllowCredentials()
                                  );
            });

            // configure CSRF
            services.AddAntiforgery(options =>
            {
                options.HeaderName = "X-XSRF-TOKEN";
                options.SuppressXFrameOptionsHeader = false;
            });

            // configure MVC
            services.AddMvc(options =>
            {
                options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
            .AddJsonOptions(options =>
            {
                options.SerializerSettings.ContractResolver     = new CamelCasePropertyNamesContractResolver();
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
            });

            services.AddSpaStaticFiles(conf =>
            {
                conf.RootPath = "ClientApp/dist";
            });

            // configure global CORS policy
            services.Configure <MvcOptions>(options =>
            {
                options.Filters.Add(new CorsAuthorizationFilterFactory("Default"));
            });

            // add EF
            services.AddEntityFrameworkSqlite()
            .AddDbContext <ApplicationDbContext>(options =>
            {
                if (HostingEnvironment.IsEnvironment("Development_WebAPI_Test"))
                {
                    // configure in-memory WebAPI test environment
                    options.UseSqlite(_connection);
                }
                else
                {
                    options.UseSqlite("DataSource=local.db");
                }
            });

            // add Identity
            services.AddIdentity <User, IdentityRole>(config =>
            {
                config.SignIn.RequireConfirmedEmail = emailConfirmation;
            })
            .AddEntityFrameworkStores <ApplicationDbContext>()
            .AddDefaultTokenProviders();

            // add JWT auth
            // clear default claims
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            // specify jwt key
            string jwtKey = Configuration["JWT_KEY"];

            // configure default authentication scheme
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultScheme             = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.SaveToken = true;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer   = Configuration["JWT_ISSUER"],
                    ValidAudience = Configuration["JWT_AUDIENCE"],
                    // todo - use injected key from docker/kubernetes secret manager
                    IssuerSigningKey = new SymmetricSecurityKey(
                        Encoding.UTF8.GetBytes(jwtKey)),
                    ClockSkew = TimeSpan.Zero,
                };
                options.Events = new JwtBearerEvents
                {
                    OnTokenValidated = (content) =>
                    {
                        // get service for jwt manager
                        IJwtManager jwtManager = content.HttpContext.RequestServices.GetService <IJwtManager>();
                        JwtSecurityToken token = (JwtSecurityToken)content.SecurityToken;

                        // check against revocation list, and fail auth if on list
                        if (jwtManager.IsRevoked(token))
                        {
                            content.Fail("Refused: token has been revoked");
                            return(Task.CompletedTask);
                        }

                        return(Task.CompletedTask);
                    }
                };
            });

            services.AddOData();

            // add service for sending basic emails (BasicEmailService for local testing only, NOT for production use)
            string emailPickupDirectory = HostingEnvironment.IsEnvironment("Development_WebAPI_Test") ?
                                          Path.Combine(Environment.CurrentDirectory, "test_email") : null;

            services.AddTransient <IEmailService, BasicEmailService>(f => new BasicEmailService(emailPickupDirectory, smtpConfig));

            // add service for accessing application data layer
            services.AddScoped <IUnitOfWork, DbUnitOfWork>();

            // service for managing JWT creation and revocation
            services.AddSingleton <IJwtManager, InMemoryJwtManager>(f => new InMemoryJwtManager(Configuration, jwtKey));
        }