using DigitalData.Auth.API.Config; using DigitalData.Auth.API.Entities; using DigitalData.Auth.API.Services; using DigitalData.Core.Abstractions.Security; using DigitalData.Core.Application; using DigitalData.Core.Security; using DigitalData.UserManager.Application; using DigitalData.UserManager.Application.DTOs.User; using DigitalData.UserManager.Application.Services; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using System.Security.Claims; using static System.Net.Mime.MediaTypeNames; var builder = WebApplication.CreateBuilder(args); builder.Configuration.AddJsonFile("consumers-api.json", true, true); var config = builder.Configuration; var apiParams = config.Get() ?? throw new InvalidOperationException("AuthApiOptions is missing or invalid in appsettings."); // Add services to the container. builder.Services.Configure(config); builder.Services.AddConsumerApiServiceFromConfiguration(config); builder.Services.AddCryptoFactory(config.GetSection("CryptParams")); builder.Services.AddJwtSignatureHandler(api => new Dictionary { { JwtRegisteredClaimNames.Sub, api.Name }, { JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds() } }); builder.Services.AddJwtSignatureHandler(user => new Dictionary { { JwtRegisteredClaimNames.Sub, user.Id }, { JwtRegisteredClaimNames.UniqueName, user.Id }, { JwtRegisteredClaimNames.Email, user.Email ?? string.Empty }, { JwtRegisteredClaimNames.GivenName, user.Prename ?? string.Empty }, { JwtRegisteredClaimNames.FamilyName, user.Name ?? string.Empty }, { JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds() } }); builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions")); var cnn_str = builder.Configuration.GetConnectionString("Default") ?? throw new InvalidOperationException("Default connection string is not found."); builder.Services.AddUserManager(cnn_str); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Name = "Authorization", Type = SecuritySchemeType.Http, Scheme = "bearer", BearerFormat = "JWT", In = ParameterLocation.Header, Description = "Enter 'Bearer' [space] and then your valid token." }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, Scheme = "oauth2", Name = "Bearer", In = ParameterLocation.Header }, new List() } }); }); // Add authentication Lazy? issuerSigningKeyInitiator = null; builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.RequireHttpsMetadata = apiParams!.RequireHttpsMetadata; options.ClaimsIssuer = apiParams!.Issuer; options.Audience = apiParams!.DefaultConsumer.Audience; options.TokenValidationParameters = new() { ValidateIssuer = true, ValidIssuer = apiParams!.Issuer, ValidateAudience = true, ValidAudience = apiParams!.DefaultConsumer.Audience, ValidateLifetime = true, IssuerSigningKey = issuerSigningKeyInitiator?.Value, NameClaimType = JwtRegisteredClaimNames.Name, RoleClaimType = ClaimTypes.Role }; options.Events = new JwtBearerEvents { OnMessageReceived = context => { // if there is no token read related cookie if (context.Token is null // if there is no token && context.Request.Cookies.TryGetValue(apiParams!.CookieName, out var token) // get token from cookies && token is not null) context.Token = token; return Task.CompletedTask; } }; }); var app = builder.Build(); app.AddDependentExtensions(); issuerSigningKeyInitiator = new Lazy(() => { var factory = app.Services.GetRequiredService(); var desc = factory.TokenDescriptors.Get(apiParams.Issuer, apiParams.DefaultConsumer.Audience); return desc.Validator.SecurityKey; }); // Configure the HTTP request pipeline. var use_swagger = config.GetValue("UseSwagger"); if (app.Environment.IsDevelopment() || use_swagger) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();