Replaced all EnvelopeGenerator.GeneratorAPI namespaces with EnvelopeGenerator.API across controllers, models, extensions, middleware, and annotation-related files. Updated using/import statements and namespace declarations accordingly. Added wwwroot folder to project file. Minor code adjustments made for consistency. This unifies API naming for improved clarity and maintainability.
252 lines
9.1 KiB
C#
252 lines
9.1 KiB
C#
using DigitalData.Core.API;
|
|
using DigitalData.Core.Application;
|
|
using EnvelopeGenerator.Infrastructure;
|
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
|
using Microsoft.AspNetCore.Localization;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using System.Globalization;
|
|
using Scalar.AspNetCore;
|
|
using Microsoft.OpenApi.Models;
|
|
using DigitalData.UserManager.DependencyInjection;
|
|
using EnvelopeGenerator.Application;
|
|
using DigitalData.Auth.Client;
|
|
using DigitalData.Core.Abstractions;
|
|
using EnvelopeGenerator.API.Models;
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using DigitalData.Core.Abstractions.Security.Extensions;
|
|
using EnvelopeGenerator.API.Middleware;
|
|
using NLog.Web;
|
|
using NLog;
|
|
|
|
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
|
logger.Info("Logging initialized!");
|
|
|
|
try
|
|
{
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
|
|
|
|
if (!builder.Environment.IsDevelopment())
|
|
{
|
|
builder.Logging.ClearProviders();
|
|
builder.Host.UseNLog();
|
|
}
|
|
|
|
var config = builder.Configuration;
|
|
|
|
var deferredProvider = new DeferredServiceProvider();
|
|
|
|
builder.Services.AddControllers();
|
|
|
|
// CORS Policy
|
|
var allowedOrigins = config.GetSection("AllowedOrigins").Get<string[]>() ??
|
|
throw new InvalidOperationException("AllowedOrigins section is missing in the configuration.");
|
|
builder.Services.AddCors(options =>
|
|
{
|
|
options.AddPolicy("AllowSpecificOriginsPolicy", builder =>
|
|
{
|
|
builder.WithOrigins(allowedOrigins)
|
|
.SetIsOriginAllowedToAllowWildcardSubdomains()
|
|
.AllowAnyMethod()
|
|
.AllowAnyHeader()
|
|
.AllowCredentials();
|
|
});
|
|
});
|
|
|
|
// Swagger
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
builder.Services.AddSwaggerGen(options =>
|
|
{
|
|
options.SwaggerDoc("v1", new OpenApiInfo
|
|
{
|
|
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.AddSecurityRequirement(new OpenApiSecurityRequirement
|
|
{
|
|
{
|
|
new OpenApiSecurityScheme
|
|
{
|
|
Reference = new OpenApiReference
|
|
{
|
|
Type = ReferenceType.SecurityScheme,
|
|
Id = "Bearer"
|
|
}
|
|
},
|
|
Array.Empty<string>()
|
|
}
|
|
});
|
|
|
|
var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
|
|
foreach (var xmlFile in xmlFiles)
|
|
{
|
|
options.IncludeXmlComments(xmlFile);
|
|
}
|
|
});
|
|
builder.Services.AddOpenApi();
|
|
|
|
//AddEF Core dbcontext
|
|
var useDbMigration = Environment.GetEnvironmentVariable("MIGRATION_TEST_MODE") == true.ToString() || config.GetValue<bool>("UseDbMigration");
|
|
var cnnStrName = useDbMigration ? "DbMigrationTest" : "Default";
|
|
var connStr = config.GetConnectionString(cnnStrName)
|
|
?? throw new InvalidOperationException($"Connection string '{cnnStrName}' is missing in the application configuration.");
|
|
|
|
builder.Services.Configure<ConnectionString>(cs => cs.Value = connStr);
|
|
|
|
builder.Services.AddDbContext<EGDbContext>(options => options.UseSqlServer(connStr));
|
|
|
|
builder.Services.AddAuthHubClient(config.GetSection("AuthClientParams"));
|
|
|
|
var authTokenKeys = config.GetOrDefault<AuthTokenKeys>();
|
|
|
|
builder.Services.AddAuthentication(options =>
|
|
{
|
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
})
|
|
.AddJwtBearer(opt =>
|
|
{
|
|
opt.TokenValidationParameters = new TokenValidationParameters
|
|
{
|
|
ValidateIssuerSigningKey = true,
|
|
IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) =>
|
|
{
|
|
var clientParams = deferredProvider.GetOptions<ClientParams>();
|
|
var publicKey = clientParams!.PublicKeys.Get(authTokenKeys.Issuer, authTokenKeys.Audience);
|
|
return [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;
|
|
}
|
|
};
|
|
});
|
|
|
|
// 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
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
builder.Services.AddUserManager<EGDbContext>();
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
// LDAP
|
|
builder.ConfigureBySection<DirectorySearchOptions>();
|
|
builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions"));
|
|
|
|
// Localizer
|
|
builder.Services.AddCookieBasedLocalizer();
|
|
|
|
// Envelope generator serives
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
builder.Services
|
|
.AddEnvelopeGeneratorInfrastructureServices(opt =>
|
|
{
|
|
opt.AddDbTriggerParams(config);
|
|
opt.AddDbContext((provider, options) =>
|
|
{
|
|
var logger = provider.GetRequiredService<ILogger<EGDbContext>>();
|
|
options.UseSqlServer(connStr)
|
|
.LogTo(log => logger.LogInformation("{log}", log), Microsoft.Extensions.Logging.LogLevel.Trace)
|
|
.EnableSensitiveDataLogging()
|
|
.EnableDetailedErrors();
|
|
});
|
|
opt.AddSQLExecutor(executor => executor.ConnectionString = connStr);
|
|
})
|
|
.AddEnvelopeGeneratorServices(config);
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
var app = builder.Build();
|
|
|
|
deferredProvider.Factory = () => app.Services;
|
|
|
|
app.UseMiddleware<ExceptionHandlingMiddleware>();
|
|
|
|
app.MapOpenApi();
|
|
|
|
// Configure the HTTP request pipeline.
|
|
if (app.Environment.IsDevelopment() || (app.IsDevOrDiP() && config.GetValue<bool>("UseSwagger")))
|
|
{
|
|
app.UseSwagger();
|
|
app.UseSwaggerUI();
|
|
app.MapScalarApiReference();
|
|
}
|
|
|
|
// Set CORS policy
|
|
app.UseCors("AllowSpecificOriginsPolicy");
|
|
|
|
// Localizer
|
|
string[] supportedCultureNames = ["de-DE", "en-US"];
|
|
IList<CultureInfo> list = [.. supportedCultureNames.Select(cn => new CultureInfo(cn))];
|
|
var cultureInfo = list.FirstOrDefault() ?? throw new InvalidOperationException("There is no supported culture.");
|
|
var 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();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error(ex, "Stopped program because of exception");
|
|
throw;
|
|
} |