using AspNetCore.Identity.MongoDbCore.Extensions; using AspNetCore.Identity.MongoDbCore.Infrastructure; using Insight.Infrastructure.Entities; using Insight.Infrastructure.Services; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; using Microsoft.Net.Http.Headers; using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.Core.Configuration; using System.Text; namespace Insight.Infrastructure { public static class ServiceExtensions { public static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration, ILoggerFactory? loggerFactory = null) { var connectionString = configuration.GetValue(Appsettings.Database) ?? throw new Exception($"{Appsettings.Database} value not set (appsettings)"); var settings = MongoClientSettings.FromUrl(new MongoUrl(connectionString)); settings.ConnectTimeout = TimeSpan.FromSeconds(3); settings.IPv6 = false; if (loggerFactory is not null) { settings.LoggingSettings = new LoggingSettings(loggerFactory); } services.AddSingleton(new MongoClient(settings)); services.AddSingleton(provider => provider.GetRequiredService()); return services.AddSingleton(provider => provider.GetRequiredService().GetDatabase(Settings.Database)); } public static IServiceCollection AddInfrastructureServices(this IServiceCollection services) { services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); return services; } public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration configuration) { var connectionString = configuration.GetValue(Appsettings.Database) ?? throw new Exception($"{Appsettings.Database} value not set (appsettings)"); services.AddIdentity(options => { }) .AddMongoDbStores(connectionString, Settings.Database) .AddDefaultTokenProviders() .AddSignInManager(); return services; } public static IServiceCollection AddTokenServices(this IServiceCollection services, IConfiguration configuration) { var options = new Models.TokenOptions( key: configuration.GetValue(Appsettings.JwtKey) ?? throw new Exception($"{Appsettings.JwtKey} value not set (appsettings)"), expires: configuration.GetValue(Appsettings.JwtExp) ?? throw new Exception($"{Appsettings.JwtExp} value not set (appsettings)"), audience: configuration.GetValue(Appsettings.JwtAudience) ?? throw new Exception($"{Appsettings.JwtAudience} value not set (appsettings)"), issuer: configuration.GetValue(Appsettings.JwtIssuer) ?? throw new Exception($"{Appsettings.JwtIssuer} value not set (appsettings)")); services.AddSingleton(options); services.AddTransient(); return services; } public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) { // REWRITE TO COOKIE ONLY FOR WEB services.AddAuthentication(options => { options.DefaultScheme = "Custom"; options.DefaultChallengeScheme = "Custom"; }) .AddCookie("Cookies", options => { //options.Cookie.Domain = "insight.webmatic.de"; options.Cookie.Name = "insight"; options.LoginPath = "/account/login"; options.LogoutPath = "/account/logout"; options.ExpireTimeSpan = TimeSpan.FromHours(1); options.SlidingExpiration = true; options.Events.OnRedirectToLogin = options => { if (options.Request.Path.StartsWithSegments("/api") && options.Response.StatusCode == 200) options.Response.StatusCode = 401; else options.Response.Redirect(options.RedirectUri); return Task.CompletedTask; }; }) .AddJwtBearer("Bearer", options => { options.RequireHttpsMetadata = false; options.SaveToken = true; options.TokenValidationParameters.ValidateActor = false; options.TokenValidationParameters.ValidAudience = configuration.GetSection("Jwt:Audience").Value; options.TokenValidationParameters.ValidateAudience = true; options.TokenValidationParameters.ValidIssuer = configuration.GetSection("Jwt:Issuer").Value; options.TokenValidationParameters.ValidateIssuer = true; options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(configuration.GetSection("Jwt:Key").Value ?? throw new ArgumentNullException(nameof(TokenValidationParameters), "Jwt:Key")) ); options.TokenValidationParameters.ValidateIssuerSigningKey = true; options.TokenValidationParameters.ValidateLifetime = true; }) .AddPolicyScheme("Custom", "Custom", options => { options.ForwardDefaultSelector = context => { string authorization = context.Request.Headers[HeaderNames.Authorization]; if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer ")) return "Bearer"; return "Cookies"; }; }); return services; } public static IServiceCollection AddBearerAuthentication(this IServiceCollection services, IConfiguration configuration) { services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.RequireHttpsMetadata = false; options.SaveToken = true; options.TokenValidationParameters.ValidateActor = false; options.TokenValidationParameters.ValidAudience = configuration.GetValue(Appsettings.JwtAudience) ?? throw new Exception($"{Appsettings.JwtAudience} value not set (appsettings)"); options.TokenValidationParameters.ValidateAudience = true; options.TokenValidationParameters.ValidIssuer = configuration.GetValue(Appsettings.JwtIssuer) ?? throw new Exception($"{Appsettings.JwtIssuer} value not set (appsettings)"); options.TokenValidationParameters.ValidateIssuer = true; options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(configuration.GetValue(Appsettings.JwtKey) ?? throw new Exception($"{Appsettings.JwtKey} value not set (appsettings)")) ); options.TokenValidationParameters.ValidateIssuerSigningKey = true; options.TokenValidationParameters.ValidateLifetime = true; }); return services; } public static IServiceCollection AddProxyServices(this IServiceCollection services, IConfiguration configuration) { // add before routing services.Configure(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; }); return services; } public static IServiceCollection AddRoutingServices(this IServiceCollection services, IConfiguration configuration) { // add after proxy services.AddRouting(options => { options.LowercaseUrls = true; }); return services; } private static IServiceCollection AddIdentityServices2(this IServiceCollection services, IConfiguration configuration) { var identityOptions = new MongoDbIdentityConfiguration { MongoDbSettings = new MongoDbSettings { ConnectionString = configuration.GetSection("ConnectionStrings:Mongo").Value, DatabaseName = "insight" }, IdentityOptionsAction = options => { options.User.RequireUniqueEmail = true; options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@.-_"; options.Password.RequireDigit = false; options.Password.RequiredLength = 8; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequireLowercase = false; options.SignIn.RequireConfirmedAccount = false; options.SignIn.RequireConfirmedEmail = false; options.SignIn.RequireConfirmedPhoneNumber = false; options.Lockout.MaxFailedAccessAttempts = 5; options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); } }; services.ConfigureMongoDbIdentity(identityOptions) .AddDefaultTokenProviders() .AddSignInManager(); return services; } private static IServiceCollection AddIdentityAuthentication(this IServiceCollection services, IConfiguration configuration) { services.AddAuthentication(options => { //options.DefaultAuthenticateScheme = }); //cookieBuilder.ApplicationCookie = builder.AddApplicationCookie(); //cookieBuilder.ExternalCookie = builder.AddExternalCookie(); //cookieBuilder.TwoFactorRememberMeCookie = builder.AddTwoFactorRememberMeCookie(); //cookieBuilder.TwoFactorUserIdCookie = builder.AddTwoFactorUserIdCookie(); //.AddCookie(options => //{ // options. //}; //.AddIdentityCookies(); //.AddCookie(options => //{ // // Specify where to redirect un-authenticated users // options.LoginPath = "/account/login"; // // Specify the name of the auth cookie. // // ASP.NET picks a dumb name by default. // options.Cookie.Name = "insight"; //}); return services; } } }