diff --git a/EnvelopeGenerator.GeneratorAPI/EnvelopeGenerator.GeneratorAPI.csproj b/EnvelopeGenerator.GeneratorAPI/EnvelopeGenerator.GeneratorAPI.csproj index 418df9b2..81eae018 100644 --- a/EnvelopeGenerator.GeneratorAPI/EnvelopeGenerator.GeneratorAPI.csproj +++ b/EnvelopeGenerator.GeneratorAPI/EnvelopeGenerator.GeneratorAPI.csproj @@ -23,6 +23,8 @@ + + diff --git a/EnvelopeGenerator.GeneratorAPI/Program.cs b/EnvelopeGenerator.GeneratorAPI/Program.cs index b41d4b62..00d5fb8a 100644 --- a/EnvelopeGenerator.GeneratorAPI/Program.cs +++ b/EnvelopeGenerator.GeneratorAPI/Program.cs @@ -16,19 +16,30 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using DigitalData.Core.Abstractions.Security.Extensions; using EnvelopeGenerator.GeneratorAPI.Middleware; +using NLog.Web; +using NLog; -var builder = WebApplication.CreateBuilder(args); +var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger(); +logger.Info("Logging initialized!"); -var config = builder.Configuration; +try +{ + var builder = WebApplication.CreateBuilder(args); -var deferredProvider = new DeferredServiceProvider(); + builder.Logging.ClearProviders(); + builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); + builder.Host.UseNLog(); -builder.Services.AddControllers(); + var config = builder.Configuration; -//CORS Policy -var allowedOrigins = config.GetSection("AllowedOrigins").Get() ?? - throw new InvalidOperationException("AllowedOrigins section is missing in the configuration."); -builder.Services.AddCors(options => + var deferredProvider = new DeferredServiceProvider(); + + builder.Services.AddControllers(); + + //CORS Policy + var allowedOrigins = config.GetSection("AllowedOrigins").Get() ?? + throw new InvalidOperationException("AllowedOrigins section is missing in the configuration."); + builder.Services.AddCors(options => { options.AddPolicy("AllowSpecificOriginsPolicy", builder => { @@ -40,34 +51,34 @@ builder.Services.AddCors(options => }); }); -// Swagger -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(options => -{ - options.SwaggerDoc("v1", new OpenApiInfo + // Swagger + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(options => { - Version = "v1", - Title = "signFLOW Absender-API", - Description = "Eine API zur Verwaltung der Erstellung, des Versands und der Nachverfolgung von Umschlägen in der signFLOW-Anwendung.", - Contact = new OpenApiContact + options.SwaggerDoc("v1", new OpenApiInfo { - Name = "Digital Data GmbH", - Url = new Uri("https://digitaldata.works/digitale-signatur#kontakt"), - Email = "info-flow@digitaldata.works" - }, - }); + Version = "v1", + Title = "signFLOW Absender-API", + Description = "Eine API zur Verwaltung der Erstellung, des Versands und der Nachverfolgung von Umschlägen in der signFLOW-Anwendung.", + Contact = new OpenApiContact + { + Name = "Digital Data GmbH", + Url = new Uri("https://digitaldata.works/digitale-signatur#kontakt"), + Email = "info-flow@digitaldata.works" + }, + }); - options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme - { - Name = "Authorization", - Type = SecuritySchemeType.Http, - Scheme = "bearer", - BearerFormat = "JWT", - In = ParameterLocation.Header, - Description = "JWT-Autorisierungs-Header unter Verwendung des Bearer-Schemas.", - }); + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Name = "Authorization", + Type = SecuritySchemeType.Http, + Scheme = "bearer", + BearerFormat = "JWT", + In = ParameterLocation.Header, + Description = "JWT-Autorisierungs-Header unter Verwendung des Bearer-Schemas.", + }); - options.AddSecurityRequirement(new OpenApiSecurityRequirement + options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme @@ -82,130 +93,136 @@ builder.Services.AddSwaggerGen(options => } }); - var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml"); - foreach (var xmlFile in xmlFiles) - { - options.IncludeXmlComments(xmlFile); - } -}); -builder.Services.AddOpenApi(); -// DbContext -var connStr = config.GetConnectionString("Default") ?? throw new InvalidOperationException("There is no default connection string in appsettings.json."); - -builder.Services.Configure(cs => cs.Value = connStr); - -builder.Services.AddDbContext(options => options.UseSqlServer(connStr)); - -builder.Services.AddAuthHubClient(config.GetSection("AuthClientParams")); - -var authTokenKeys = config.GetOrDefault(); - -builder.Services.AddAuthentication(options => -{ - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; -}) - .AddJwtBearer(opt => - { - opt.TokenValidationParameters = new TokenValidationParameters + var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml"); + foreach (var xmlFile in xmlFiles) { - ValidateIssuerSigningKey = true, - IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) => - { - var clientParams = deferredProvider.GetOptions(); - var publicKey = clientParams!.PublicKeys.Get(authTokenKeys.Issuer, authTokenKeys.Audience); - return new List() { publicKey.SecurityKey }; - }, - ValidateIssuer = true, - ValidIssuer = authTokenKeys.Issuer, - ValidateAudience = true, - ValidAudience = authTokenKeys.Audience, - }; + options.IncludeXmlComments(xmlFile); + } + }); + builder.Services.AddOpenApi(); + // DbContext + var connStr = config.GetConnectionString("Default") ?? throw new InvalidOperationException("There is no default connection string in appsettings.json."); - opt.Events = new JwtBearerEvents + builder.Services.Configure(cs => cs.Value = connStr); + + builder.Services.AddDbContext(options => options.UseSqlServer(connStr)); + + builder.Services.AddAuthHubClient(config.GetSection("AuthClientParams")); + + var authTokenKeys = config.GetOrDefault(); + + builder.Services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(opt => { - OnMessageReceived = context => + opt.TokenValidationParameters = new TokenValidationParameters { - // if there is no token read related cookie or query string - if (context.Token is null) // if there is no token + ValidateIssuerSigningKey = true, + IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) => { - if (context.Request.Cookies.TryGetValue(authTokenKeys.Cookie, out var cookieToken) && cookieToken is not null) - context.Token = cookieToken; - else if (context.Request.Query.TryGetValue(authTokenKeys.QueryString, out var queryStrToken)) - context.Token = queryStrToken; + var clientParams = deferredProvider.GetOptions(); + var publicKey = clientParams!.PublicKeys.Get(authTokenKeys.Issuer, authTokenKeys.Audience); + return new List() { publicKey.SecurityKey }; + }, + ValidateIssuer = true, + ValidIssuer = authTokenKeys.Issuer, + ValidateAudience = true, + ValidAudience = authTokenKeys.Audience, + }; + + opt.Events = new JwtBearerEvents + { + OnMessageReceived = context => + { + // if there is no token read related cookie or query string + if (context.Token is null) // if there is no token + { + if (context.Request.Cookies.TryGetValue(authTokenKeys.Cookie, out var cookieToken) && cookieToken is not null) + context.Token = cookieToken; + else if (context.Request.Query.TryGetValue(authTokenKeys.QueryString, out var queryStrToken)) + context.Token = queryStrToken; + } + return Task.CompletedTask; } - return Task.CompletedTask; - } - }; + }; + }); + + // Authentication + builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) + .AddCookie(options => + { + options.Cookie.HttpOnly = true; // Makes the cookie inaccessible to client-side scripts for security + options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; // Ensures cookies are sent over HTTPS only + options.Cookie.SameSite = SameSiteMode.Strict; // Protects against CSRF attacks by restricting how cookies are sent with requests from external sites + options.LoginPath = "/api/auth/login"; + options.LogoutPath = "/api/auth/logout"; + options.SlidingExpiration = true; }); -// Authentication -builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) -.AddCookie(options => -{ - options.Cookie.HttpOnly = true; // Makes the cookie inaccessible to client-side scripts for security - options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; // Ensures cookies are sent over HTTPS only - options.Cookie.SameSite = SameSiteMode.Strict; // Protects against CSRF attacks by restricting how cookies are sent with requests from external sites - options.LoginPath = "/api/auth/login"; - options.LogoutPath = "/api/auth/logout"; - options.SlidingExpiration = true; -}); + // User manager + builder.Services.AddUserManager(); -// User manager -builder.Services.AddUserManager(); + // LDAP + builder.ConfigureBySection(); + builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions")); -// LDAP -builder.ConfigureBySection(); -builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions")); + // Localizer + builder.Services.AddCookieBasedLocalizer(); -// Localizer -builder.Services.AddCookieBasedLocalizer() ; + // Envelope generator serives + builder.Services + .AddEnvelopeGeneratorInfrastructureServices(sqlExecutorConfigureOptions: executor => executor.ConnectionString = connStr) + .AddEnvelopeGeneratorServices(config); -// Envelope generator serives -builder.Services - .AddEnvelopeGeneratorInfrastructureServices(sqlExecutorConfigureOptions: executor => executor.ConnectionString = connStr) - .AddEnvelopeGeneratorServices(config); + var app = builder.Build(); -var app = builder.Build(); + deferredProvider.Factory = () => app.Services; -deferredProvider.Factory = () => app.Services; + app.UseMiddleware(); -app.UseMiddleware(); + app.MapOpenApi(); -app.MapOpenApi(); + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment() || (app.IsDevOrDiP() && config.GetValue("UseSwagger"))) + { + app.UseSwagger(); + app.UseSwaggerUI(); + app.MapScalarApiReference(); + } -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment() || (app.IsDevOrDiP() && config.GetValue("UseSwagger"))) -{ - app.UseSwagger(); - app.UseSwaggerUI(); - app.MapScalarApiReference(); + // Set CORS policy + app.UseCors("AllowSpecificOriginsPolicy"); + + // Localizer + string[] supportedCultureNames = { "de-DE", "en-US" }; + IList list = supportedCultureNames.Select((string cn) => new CultureInfo(cn)).ToList(); + CultureInfo cultureInfo = list.FirstOrDefault() ?? throw new ArgumentNullException("supportedCultureNames", "Supported cultures cannot be empty."); + RequestLocalizationOptions requestLocalizationOptions = new RequestLocalizationOptions + { + SupportedCultures = list, + SupportedUICultures = list + }; + requestLocalizationOptions.RequestCultureProviders.Add(new QueryStringRequestCultureProvider()); + app.UseRequestLocalization(requestLocalizationOptions); + + + app.UseHttpsRedirection(); + + app.UseDefaultFiles(); + app.UseStaticFiles(); + + app.UseAuthentication(); + app.UseAuthorization(); + + app.MapControllers(); + + app.Run(); } - -// Set CORS policy -app.UseCors("AllowSpecificOriginsPolicy"); - -// Localizer -string[] supportedCultureNames = { "de-DE", "en-US" }; -IList list = supportedCultureNames.Select((string cn) => new CultureInfo(cn)).ToList(); -CultureInfo cultureInfo = list.FirstOrDefault() ?? throw new ArgumentNullException("supportedCultureNames", "Supported cultures cannot be empty."); -RequestLocalizationOptions requestLocalizationOptions = new RequestLocalizationOptions +catch (Exception ex) { - SupportedCultures = list, - SupportedUICultures = list -}; -requestLocalizationOptions.RequestCultureProviders.Add(new QueryStringRequestCultureProvider()); -app.UseRequestLocalization(requestLocalizationOptions); - - -app.UseHttpsRedirection(); - -app.UseDefaultFiles(); -app.UseStaticFiles(); - -app.UseAuthentication(); -app.UseAuthorization(); - -app.MapControllers(); - -app.Run(); + logger.Error(ex, "Stopped program because of exception"); + throw; +} \ No newline at end of file