using System; using System.Security.Claims; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Bit.Api.Utilities; using Bit.Core; using Bit.Core.Domains; using Bit.Core.Identity; using Bit.Core.Repositories; using Bit.Core.Services; using Repos = Bit.Core.Repositories.SqlServer; using System.Text; using Loggr.Extensions.Logging; using System.Linq; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Net.Http.Headers; using Newtonsoft.Json.Serialization; namespace Bit.Api { public class Startup { public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("settings.json") .AddJsonFile($"settings.{env.EnvironmentName}.json", optional: true); if(env.IsDevelopment()) { builder.AddUserSecrets(); } builder.AddEnvironmentVariables(); Configuration = builder.Build(); } public IConfigurationRoot Configuration { get; private set; } public void ConfigureServices(IServiceCollection services) { var provider = services.BuildServiceProvider(); // Options services.AddOptions(); // Settings var globalSettings = new GlobalSettings(); ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), globalSettings); services.AddSingleton(s => globalSettings); // Repositories services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); // Context services.AddScoped(); // Identity services.AddTransient(); services.AddJwtBearerIdentity(options => { options.User = new UserOptions { RequireUniqueEmail = true, AllowedUserNameCharacters = null // all }; options.Password = new PasswordOptions { RequireDigit = false, RequireLowercase = false, RequiredLength = 8, RequireNonAlphanumeric = false, RequireUppercase = false }; options.ClaimsIdentity = new ClaimsIdentityOptions { SecurityStampClaimType = "securitystamp", UserNameClaimType = ClaimTypes.Email }; options.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider; }, jwtBearerOptions => { jwtBearerOptions.Audience = "bitwarden"; jwtBearerOptions.Issuer = "bitwarden"; jwtBearerOptions.TokenLifetime = TimeSpan.FromDays(10 * 365); jwtBearerOptions.TwoFactorTokenLifetime = TimeSpan.FromMinutes(10); var keyBytes = Encoding.ASCII.GetBytes(globalSettings.JwtSigningKey); jwtBearerOptions.SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(keyBytes), SecurityAlgorithms.HmacSha256); }) .AddUserStore() .AddRoleStore() .AddTokenProvider("Authenticator") .AddTokenProvider>(TokenOptions.DefaultEmailProvider); var jwtIdentityOptions = provider.GetRequiredService>().Value; services.AddAuthorization(config => { config.AddPolicy("Application", new AuthorizationPolicyBuilder() .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​) .RequireAuthenticatedUser().RequireClaim(ClaimTypes.AuthenticationMethod, jwtIdentityOptions.AuthenticationMethod).Build()); config.AddPolicy("TwoFactor", new AuthorizationPolicyBuilder() .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser().RequireClaim(ClaimTypes.AuthenticationMethod, jwtIdentityOptions.TwoFactorAuthenticationMethod).Build()); }); services.AddScoped(); // Services services.AddSingleton(); services.AddSingleton(); services.AddScoped(); services.AddScoped(); services.AddScoped(); // Cors services.AddCors(config => { config.AddPolicy("All", policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().SetPreflightMaxAge(TimeSpan.FromDays(1))); }); // MVC services.AddMvc(config => { config.Filters.Add(new ExceptionHandlerFilterAttribute()); config.Filters.Add(new ModelStateValidationFilterAttribute()); // Allow JSON of content type "text/plain" to avoid cors preflight var textPlainMediaType = MediaTypeHeaderValue.Parse("text/plain"); foreach(var jsonFormatter in config.InputFormatters.OfType()) { jsonFormatter.SupportedMediaTypes.Add(textPlainMediaType); } }).AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver()); ; } public void Configure( IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, GlobalSettings globalSettings) { loggerFactory.AddConsole(); loggerFactory.AddDebug(); if(!env.IsDevelopment()) { loggerFactory.AddLoggr( LogLevel.Error, globalSettings.Loggr.LogKey, globalSettings.Loggr.ApiKey); } // Add static files to the request pipeline. app.UseStaticFiles(); // Add Cors app.UseCors("All"); // Add Jwt authentication to the request pipeline. app.UseJwtBearerIdentity(); // Add MVC to the request pipeline. app.UseMvc(); } } }