using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using OAuthServer; using OAuthServer.Services; var builder = WebApplication.CreateBuilder(args); // Add logging to console builder.Logging.AddConsole(); // Add services to the container. builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { // Create a authentication schema for JWT tokens options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, Scheme = "bearer", Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); }); builder.Services.AddDbContext(options => { options.UseSqlite("DataSource=db.sqlite3"); }); builder.Services.AddIdentity(options => { options.Stores.MaxLengthForKeys = 128; }) .AddEntityFrameworkStores() .AddDefaultTokenProviders(); // Load the signing key from a file if it exists or create a new one var rsaKey = JwtService.GetSigningKey(); // Add the JWT authentication method builder.Services.AddAuthentication().AddJwtBearer("OAuthToken", options => { options.SaveToken = false; options.TokenValidationParameters = new TokenValidationParameters() { ValidateIssuer = false, ValidateAudience = false, RequireSignedTokens = true, IssuerSigningKey = new RsaSecurityKey(rsaKey) }; }); builder.Services.Configure(options => { // SignIn settings. options.SignIn.RequireConfirmedAccount = false; options.SignIn.RequireConfirmedEmail = false; options.SignIn.RequireConfirmedPhoneNumber = false; // Lockout settings. options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); options.Lockout.MaxFailedAccessAttempts = 5; options.Lockout.AllowedForNewUsers = true; // Password settings. options.Password.RequireDigit = false; options.Password.RequireLowercase = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequiredLength = 1; options.Password.RequiredUniqueChars = 1; }); builder.Services.ConfigureApplicationCookie(options => { // Cookie options options.Cookie.Name = "AuthCookie"; options.Cookie.HttpOnly = true; options.ExpireTimeSpan = TimeSpan.FromHours(24); options.SlidingExpiration = true; options.LoginPath = "/login"; options.LogoutPath = "/logout"; }); // Force Identity's security stamp to be validated every minute. builder.Services.Configure(options => { options.ValidationInterval = TimeSpan.FromMinutes(10); }); // Set a more secure password hashing iteration count builder.Services.Configure(option => { option.IterationCount = 100_000; }); builder.Services.AddDataProtection().UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration() { EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC, ValidationAlgorithm = ValidationAlgorithm.HMACSHA256 }); // Add policy-based authorization builder.Services.AddAuthorization(options => { // Require either role to authenticate as Contestant options.AddPolicy("User", policy => policy .RequireRole("User") .AddAuthenticationSchemes(IdentityConstants.ApplicationScheme) ); // Require the External role to authenticate with a different authentication method options.AddPolicy("External", policy => policy .RequireRole("External") .AddAuthenticationSchemes("OAuthToken") ); }); builder.Services.AddSingleton(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.MapControllers(); // Automatically apply migrations to database on startup var scopeFactory = app.Services.GetRequiredService(); using (var scope = scopeFactory.CreateScope()) { using (var databaseContext = scope.ServiceProvider.GetRequiredService()) { // Migrate the database databaseContext.Database.Migrate(); } } app.Run();