diff options
Diffstat (limited to 'code/api/src')
| -rw-r--r-- | code/api/src/Endpoints/EndpointBase.cs | 25 | ||||
| -rw-r--r-- | code/api/src/Models/Static/JsonSettings.cs | 9 | ||||
| -rw-r--r-- | code/api/src/Program.cs | 113 | ||||
| -rw-r--r-- | code/api/src/Services/EmailValidationService.cs | 2 | ||||
| -rw-r--r-- | code/api/src/Services/PasswordResetService.cs | 45 | ||||
| -rw-r--r-- | code/api/src/Services/TenantService.cs | 2 | ||||
| -rw-r--r-- | code/api/src/Services/UserService.cs | 2 | ||||
| -rw-r--r-- | code/api/src/Utilities/BasicAuthenticationAttribute.cs | 30 | ||||
| -rw-r--r-- | code/api/src/Utilities/BasicAuthenticationHandler.cs | 27 |
9 files changed, 153 insertions, 102 deletions
diff --git a/code/api/src/Endpoints/EndpointBase.cs b/code/api/src/Endpoints/EndpointBase.cs index 105fbdf..e8e2494 100644 --- a/code/api/src/Endpoints/EndpointBase.cs +++ b/code/api/src/Endpoints/EndpointBase.cs @@ -8,15 +8,18 @@ public class EndpointBase : ControllerBase /// <summary> /// User data for the currently logged on user. /// </summary> - protected LoggedInUserModel LoggedInUser => new() { + protected LoggedInUserModel LoggedInUser => new() + { Username = User.FindFirstValue(AppClaims.NAME), Id = User.FindFirstValue(AppClaims.USER_ID).AsGuid(), }; [NonAction] - protected ActionResult KnownProblem(string title = default, string subtitle = default, Dictionary<string, string[]> errors = default) { - HttpContext.Response.Headers.Add(AppHeaders.IS_KNOWN_PROBLEM, "1"); - return BadRequest(new KnownProblemModel { + protected ActionResult KnownProblem(string title = default, string subtitle = default, Dictionary<string, string[]> errors = default) + { + HttpContext.Response.Headers.Append(AppHeaders.IS_KNOWN_PROBLEM, "1"); + return BadRequest(new KnownProblemModel + { Title = title, Subtitle = subtitle, Errors = errors, @@ -25,27 +28,31 @@ public class EndpointBase : ControllerBase } [NonAction] - protected ActionResult KnownProblem(KnownProblemModel problem) { - HttpContext.Response.Headers.Add(AppHeaders.IS_KNOWN_PROBLEM, "1"); + protected ActionResult KnownProblem(KnownProblemModel problem) + { + HttpContext.Response.Headers.Append(AppHeaders.IS_KNOWN_PROBLEM, "1"); problem.TraceId = HttpContext.TraceIdentifier; return BadRequest(problem); } [NonAction] - protected RequestTimeZoneInfo GetRequestTimeZone(ILogger logger = default) { + protected RequestTimeZoneInfo GetRequestTimeZone(ILogger logger = default) + { Request.Headers.TryGetValue(AppHeaders.BROWSER_TIME_ZONE, out var timeZoneHeader); var tz = TimeZoneInfo.FindSystemTimeZoneById(timeZoneHeader.ToString().HasValue() ? timeZoneHeader.ToString() : "UTC"); var offset = tz.BaseUtcOffset.Hours; // This is fine as long as the client is not connecting from Australia: Lord Howe Island, // according to https://en.wikipedia.org/wiki/Daylight_saving_time_by_country - if (tz.IsDaylightSavingTime(AppDateTime.UtcNow)) { + if (tz.IsDaylightSavingTime(AppDateTime.UtcNow)) + { offset++; } logger?.LogInformation("Request time zone (" + tz.Id + ") offset is: " + offset + " hours"); - return new RequestTimeZoneInfo() { + return new RequestTimeZoneInfo() + { TimeZoneInfo = tz, Offset = offset, LocalDateTime = TimeZoneInfo.ConvertTimeFromUtc(AppDateTime.UtcNow, tz) diff --git a/code/api/src/Models/Static/JsonSettings.cs b/code/api/src/Models/Static/JsonSettings.cs index a163c11..3405606 100644 --- a/code/api/src/Models/Static/JsonSettings.cs +++ b/code/api/src/Models/Static/JsonSettings.cs @@ -1,11 +1,16 @@ -namespace IOL.GreatOffice.Api.Data.Static; +namespace IOL.GreatOffice.Api.Models.Static; public static class JsonSettings { - public static Action<JsonOptions> Default { get; } = options => { + public static Action<JsonOptions> SetDefaultAction { get; } = options => + { options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString; options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; }; + public static readonly JsonSerializerOptions WriteIndented = new() + { + WriteIndented = true + }; } diff --git a/code/api/src/Program.cs b/code/api/src/Program.cs index fcb9465..7277fd3 100644 --- a/code/api/src/Program.cs +++ b/code/api/src/Program.cs @@ -8,11 +8,12 @@ global using System.ComponentModel.DataAnnotations.Schema; global using System.Security.Claims; global using System.Text.Json; global using System.Text.Json.Serialization; -global using IOL.GreatOffice.Api.Data.Database; -global using IOL.GreatOffice.Api.Data.Enums; -global using IOL.GreatOffice.Api.Data.Models; -global using IOL.GreatOffice.Api.Data.Static; +global using IOL.GreatOffice.Api.Models.Database; +global using IOL.GreatOffice.Api.Models.Enums; +global using IOL.GreatOffice.Api.Models.Models; +global using IOL.GreatOffice.Api.Models.Static; global using IOL.GreatOffice.Api.Services; +global using IOL.GreatOffice.Api.Resources; global using IOL.GreatOffice.Api.Utilities; global using IOL.Helpers; global using Microsoft.OpenApi.Models; @@ -31,10 +32,8 @@ global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Logging; global using Serilog; global using Quartz; -global using IOL.GreatOffice.Api.Resources; using IOL.GreatOffice.Api.Endpoints.V1; using IOL.GreatOffice.Api.Jobs; -using IOL.GreatOffice.Api.Models.Database; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc.Versioning; @@ -44,7 +43,9 @@ namespace IOL.GreatOffice.Api; public static class Program { - public static WebApplicationBuilder CreateAppBuilder(string[] args) { + private static readonly string[] supportedCultures = ["en", "nb"]; + public static WebApplicationBuilder CreateAppBuilder(string[] args) + { var builder = WebApplication.CreateBuilder(args); builder.Services.AddLogging(); builder.Services.AddHttpClient(); @@ -67,37 +68,37 @@ public static class Program .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) .WriteTo.Console(); - if (!builder.Environment.IsDevelopment() && configuration.SEQ_API_KEY.HasValue() && configuration.SEQ_API_URL.HasValue()) { + if (!builder.Environment.IsDevelopment() && configuration.SEQ_API_KEY.HasValue() && configuration.SEQ_API_URL.HasValue()) + { logger.WriteTo.Seq(configuration.SEQ_API_URL, apiKey: configuration.SEQ_API_KEY); } Log.Logger = logger.CreateLogger(); - Log.Information("Starting web host, " - + JsonSerializer.Serialize(configuration.GetPublicVersion(), - new JsonSerializerOptions() { - WriteIndented = true - })); + Log.Information("Starting web host, " + JsonSerializer.Serialize(configuration.GetPublicObject(), JsonSettings.WriteIndented)); builder.Host.UseSerilog(Log.Logger); - if (builder.Environment.IsDevelopment()) { + if (builder.Environment.IsDevelopment()) + { builder.Services.AddCors(); } - if (builder.Environment.IsProduction()) { + if (builder.Environment.IsProduction()) + { builder.Services.Configure<ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedProto; }); } builder.Services.AddLocalization(); - builder.Services.AddRequestLocalization(options => { - var supportedCultures = new[] {"en", "nb"}; + builder.Services.AddRequestLocalization(options => + { options.SetDefaultCulture(supportedCultures[0]) .AddSupportedCultures(supportedCultures) .AddSupportedUICultures(supportedCultures); options.ApplyCurrentCultureToResponseHeaders = true; }); - builder.Services.Configure<RequestLocalizationOptions>(options => { + builder.Services.Configure<RequestLocalizationOptions>(options => + { options.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context => // Get culture from specific cookie await Task.FromResult(new ProviderCultureResult(context.Request.Cookies[AppCookies.Locale] ?? "en"))) @@ -109,61 +110,72 @@ public static class Program .ProtectKeysWithCertificate(configuration.CERT1()) .PersistKeysToDbContext<MainAppDatabase>(); - builder.Services.Configure(JsonSettings.Default); - builder.Services.AddQuartz(options => { - options.UsePersistentStore(o => { + builder.Services.Configure(JsonSettings.SetDefaultAction); + + builder.Services.AddQuartz(options => + { + options.UsePersistentStore(o => + { o.UsePostgres(builder.Configuration.GetQuartzDatabaseConnectionString(vaultService.GetCurrentAppConfiguration)); o.UseSerializer<QuartzJsonSerializer>(); }); - options.UseMicrosoftDependencyInjectionJobFactory(); options.RegisterJobs(); }); builder.Services.AddQuartzHostedService(options => { options.WaitForJobsToComplete = true; }); - builder.Services.AddAuthentication(options => { - options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; - }) - .AddCookie(options => { + builder.Services.AddAuthentication(options => + { + options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; + }) + .AddCookie(options => + { options.Cookie.Name = AppCookies.Session; options.Cookie.Domain = builder.Environment.IsDevelopment() ? "localhost" : ".greatoffice.app"; options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; options.SlidingExpiration = true; options.Events.OnRedirectToAccessDenied = - options.Events.OnRedirectToLogin = c => { + options.Events.OnRedirectToLogin = c => + { c.Response.StatusCode = StatusCodes.Status401Unauthorized; return Task.FromResult<object>(null); }; }) .AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>(AppConstants.BASIC_AUTH_SCHEME, default); - builder.Services.AddDbContext<MainAppDatabase>(options => { + builder.Services.AddDbContext<MainAppDatabase>(options => + { options.UseNpgsql(builder.Configuration.GetAppDatabaseConnectionString(vaultService.GetCurrentAppConfiguration), - npgsqlDbContextOptionsBuilder => { + npgsqlDbContextOptionsBuilder => + { npgsqlDbContextOptionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); npgsqlDbContextOptionsBuilder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), default); }) .UseSnakeCaseNamingConvention(); - if (builder.Environment.IsDevelopment()) { + if (builder.Environment.IsDevelopment()) + { options.EnableSensitiveDataLogging(); } }); - builder.Services.AddApiVersioning(options => { + builder.Services.AddApiVersioning(options => + { options.ApiVersionReader = new UrlSegmentApiVersionReader(); options.ReportApiVersions = true; options.AssumeDefaultVersionWhenUnspecified = false; }); builder.Services.AddVersionedApiExplorer(options => { options.SubstituteApiVersionInUrl = true; }); - builder.Services.AddSwaggerGen(options => { + builder.Services.AddSwaggerGen(options => + { options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "IOL.GreatOffice.Api.xml")); options.UseApiEndpoints(); options.OperationFilter<SwaggerDefaultValues>(); options.OperationFilter<PaginationOperationFilter>(); options.SwaggerDoc(ApiSpecV1.Document.VersionName, ApiSpecV1.Document.OpenApiInfo); options.AddSecurityDefinition("Basic", - new OpenApiSecurityScheme { + new OpenApiSecurityScheme + { Name = "Authorization", Type = SecuritySchemeType.ApiKey, Scheme = "Basic", @@ -186,7 +198,8 @@ public static class Program }); }); - builder.Services.AddPagination(options => { + builder.Services.AddPagination(options => + { options.DefaultSize = 50; options.MaxSize = 100; options.CanChangeSizeFromQuery = true; @@ -195,16 +208,19 @@ public static class Program builder.Services .AddControllers() .AddDataAnnotationsLocalization() - .AddJsonOptions(JsonSettings.Default); + .AddJsonOptions(JsonSettings.SetDefaultAction); return builder; } - public static WebApplication CreateWebApplication(WebApplicationBuilder builder) { + public static WebApplication CreateWebApplication(WebApplicationBuilder builder) + { var app = builder.Build(); - if (app.Environment.IsDevelopment()) { + if (app.Environment.IsDevelopment()) + { app.UseDeveloperExceptionPage(); - app.UseCors(cors => { + app.UseCors(cors => + { cors.AllowAnyMethod(); cors.AllowAnyHeader(); cors.SetIsOriginAllowed(_ => true); @@ -213,7 +229,8 @@ public static class Program }); } - if (app.Environment.IsProduction()) { + if (app.Environment.IsProduction()) + { app.UseForwardedHeaders(); } @@ -226,7 +243,8 @@ public static class Program .UseAuthentication() .UseAuthorization() .UseSwagger() - .UseSwaggerUI(options => { + .UseSwaggerUI(options => + { options.SwaggerEndpoint(ApiSpecV1.Document.SwaggerPath, ApiSpecV1.Document.VersionName); options.DocumentTitle = AppConstants.API_NAME; }) @@ -234,15 +252,20 @@ public static class Program return app; } - public static int Main(string[] args) { - try { + public static int Main(string[] args) + { + try + { CreateWebApplication(CreateAppBuilder(args)).Run(); return 0; - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Fatal(ex, "Unhandled exception"); return 1; } - finally { + finally + { Log.Information("Shut down complete, flushing logs..."); Log.CloseAndFlush(); } diff --git a/code/api/src/Services/EmailValidationService.cs b/code/api/src/Services/EmailValidationService.cs index e88dfec..c7be20a 100644 --- a/code/api/src/Services/EmailValidationService.cs +++ b/code/api/src/Services/EmailValidationService.cs @@ -1,5 +1,3 @@ -using IOL.GreatOffice.Api.Models.Database; - namespace IOL.GreatOffice.Api.Services; public class EmailValidationService diff --git a/code/api/src/Services/PasswordResetService.cs b/code/api/src/Services/PasswordResetService.cs index a179e10..d4aeb0d 100644 --- a/code/api/src/Services/PasswordResetService.cs +++ b/code/api/src/Services/PasswordResetService.cs @@ -1,5 +1,3 @@ -using IOL.GreatOffice.Api.Models.Database; - namespace IOL.GreatOffice.Api.Services; public class PasswordResetService @@ -14,7 +12,8 @@ public class PasswordResetService MainAppDatabase database, VaultService vaultService, ILogger<PasswordResetService> logger, - MailService mailService, IStringLocalizer<SharedResources> localizer) { + MailService mailService, IStringLocalizer<SharedResources> localizer) + { _database = database; _configuration = vaultService.GetCurrentAppConfiguration(); _logger = logger; @@ -22,11 +21,13 @@ public class PasswordResetService _localizer = localizer; } - public async Task<PasswordResetRequest> GetRequestAsync(Guid id, CancellationToken cancellationToken = default) { + public async Task<PasswordResetRequest> GetRequestAsync(Guid id, CancellationToken cancellationToken = default) + { var request = await _database.PasswordResetRequests .Include(c => c.User) .SingleOrDefaultAsync(c => c.Id == id, cancellationToken); - if (request == default) { + if (request == default) + { return default; } @@ -34,7 +35,8 @@ public class PasswordResetService return request; } - public async Task<FulfillPasswordResetRequestResult> FulfillRequestAsync(Guid id, string newPassword, CancellationToken cancellationToken = default) { + public async Task<FulfillPasswordResetRequestResult> FulfillRequestAsync(Guid id, string newPassword, CancellationToken cancellationToken = default) + { var request = await GetRequestAsync(id, cancellationToken); if (request == default) return FulfillPasswordResetRequestResult.REQUEST_NOT_FOUND; var user = _database.Users.FirstOrDefault(c => c.Id == request.User.Id); @@ -47,13 +49,15 @@ public class PasswordResetService return FulfillPasswordResetRequestResult.FULFILLED; } - public async Task AddRequestAsync(User user, TimeZoneInfo requestTz, CancellationToken cancellationToken = default) { + public async Task AddRequestAsync(User user, TimeZoneInfo requestTz, CancellationToken cancellationToken = default) + { await DeleteRequestsForUserAsync(user.Id, cancellationToken); var request = new PasswordResetRequest(user); _database.PasswordResetRequests.Add(request); await _database.SaveChangesAsync(cancellationToken); var zonedExpirationDate = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(request.ExpirationDate, requestTz.Id); - var message = new MailService.PostmarkEmail() { + var message = new MailService.PostmarkEmail() + { To = request.User.Username, Subject = _localizer["Reset password - Greatoffice"], TextBody = _localizer[""" @@ -68,16 +72,16 @@ If you did not request a password reset, no action is required. """, user.DisplayName(true), _configuration.CANONICAL_FRONTEND_URL, request.Id, zonedExpirationDate.ToString("yyyy-MM-dd hh:mm")] }; -#pragma warning disable 4014 - Task.Run(() => { -#pragma warning restore 4014 - _mailService.SendMailAsync(message); - _logger.LogInformation($"Added password reset request for user: {request.User.Username}, expires in {request.ExpirationDate.Subtract(AppDateTime.UtcNow)}."); - }, - cancellationToken); + await Task.Run(() => + { + _mailService.SendMailAsync(message).ConfigureAwait(false); + _logger.LogInformation($"Added password reset request for user: {request.User.Username}, expires in {request.ExpirationDate.Subtract(AppDateTime.UtcNow)}."); + }, + cancellationToken).ConfigureAwait(false); } - public async Task DeleteRequestsForUserAsync(Guid userId, CancellationToken cancellationToken = default) { + public async Task DeleteRequestsForUserAsync(Guid userId, CancellationToken cancellationToken = default) + { var requestsToRemove = _database.PasswordResetRequests.Where(c => c.UserId == userId).ToList(); if (!requestsToRemove.Any()) return; _database.PasswordResetRequests.RemoveRange(requestsToRemove); @@ -85,10 +89,13 @@ If you did not request a password reset, no action is required. _logger.LogInformation($"Deleted {requestsToRemove.Count} password reset requests for user: {userId}."); } - public async Task DeleteStaleRequestsAsync(CancellationToken cancellationToken = default) { + public async Task DeleteStaleRequestsAsync(CancellationToken cancellationToken = default) + { var deleteCount = 0; - foreach (var request in _database.PasswordResetRequests.Where(c => c.IsExpired)) { - if (!request.IsExpired) { + foreach (var request in _database.PasswordResetRequests.Where(c => c.IsExpired)) + { + if (!request.IsExpired) + { continue; } diff --git a/code/api/src/Services/TenantService.cs b/code/api/src/Services/TenantService.cs index 477a865..0de6f53 100644 --- a/code/api/src/Services/TenantService.cs +++ b/code/api/src/Services/TenantService.cs @@ -1,5 +1,3 @@ -using IOL.GreatOffice.Api.Models.Database; - namespace IOL.GreatOffice.Api.Services; public class TenantService diff --git a/code/api/src/Services/UserService.cs b/code/api/src/Services/UserService.cs index 8e183fe..4df8ded 100644 --- a/code/api/src/Services/UserService.cs +++ b/code/api/src/Services/UserService.cs @@ -1,5 +1,3 @@ -using IOL.GreatOffice.Api.Models.Database; - namespace IOL.GreatOffice.Api.Services; public class UserService diff --git a/code/api/src/Utilities/BasicAuthenticationAttribute.cs b/code/api/src/Utilities/BasicAuthenticationAttribute.cs index 0bfd007..9e57595 100644 --- a/code/api/src/Utilities/BasicAuthenticationAttribute.cs +++ b/code/api/src/Utilities/BasicAuthenticationAttribute.cs @@ -5,10 +5,11 @@ namespace IOL.GreatOffice.Api.Utilities; public class BasicAuthenticationAttribute : TypeFilterAttribute { - public BasicAuthenticationAttribute(string claimPermission) : base(typeof(BasicAuthenticationFilter)) { - Arguments = new object[] { + public BasicAuthenticationAttribute(string claimPermission) : base(typeof(BasicAuthenticationFilter)) + { + Arguments = [ new Claim(claimPermission, "True") - }; + ]; } } @@ -16,23 +17,30 @@ public class BasicAuthenticationFilter : IAuthorizationFilter { private readonly Claim _claim; - public BasicAuthenticationFilter(Claim claim) { + public BasicAuthenticationFilter(Claim claim) + { _claim = claim; } - public void OnAuthorization(AuthorizationFilterContext context) { - if (!context.HttpContext.Request.Headers.ContainsKey("Authorization")) return; - try { - var authHeader = AuthenticationHeaderValue.Parse(context.HttpContext.Request.Headers["Authorization"]); - if (authHeader.Parameter is null) { + public void OnAuthorization(AuthorizationFilterContext context) + { + if (!context.HttpContext.Request.Headers.TryGetValue("Authorization", out Microsoft.Extensions.Primitives.StringValues authzHeaderValue)) return; + try + { + var authHeader = AuthenticationHeaderValue.Parse(authzHeaderValue); + if (authHeader.Parameter is null) + { context.Result = new ForbidResult(AppConstants.BASIC_AUTH_SCHEME); } var hasClaim = context.HttpContext.User.Claims.Any(c => c.Type == _claim.Type && c.Value == _claim.Value); - if (!hasClaim) { + if (!hasClaim) + { context.Result = new ForbidResult(AppConstants.BASIC_AUTH_SCHEME); } - } catch { + } + catch + { // ignore } } diff --git a/code/api/src/Utilities/BasicAuthenticationHandler.cs b/code/api/src/Utilities/BasicAuthenticationHandler.cs index 3b92293..41486ef 100644 --- a/code/api/src/Utilities/BasicAuthenticationHandler.cs +++ b/code/api/src/Utilities/BasicAuthenticationHandler.cs @@ -1,7 +1,6 @@ using System.Net.Http.Headers; using System.Text; using System.Text.Encodings.Web; -using IOL.GreatOffice.Api.Models.Database; using Microsoft.Extensions.Options; namespace IOL.GreatOffice.Api.Utilities; @@ -16,17 +15,18 @@ public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSc IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, - ISystemClock clock, MainAppDatabase context, VaultService vaultService ) : - base(options, logger, encoder, clock) { + base(options, logger, encoder) + { _context = context; _configuration = vaultService.GetCurrentAppConfiguration(); _logger = logger.CreateLogger<BasicAuthenticationHandler>(); } - protected override Task<AuthenticateResult> HandleAuthenticateAsync() { + protected override Task<AuthenticateResult> HandleAuthenticateAsync() + { var endpoint = Context.GetEndpoint(); if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null) return Task.FromResult(AuthenticateResult.NoResult()); @@ -34,9 +34,11 @@ public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSc if (!Request.Headers.ContainsKey("Authorization")) return Task.FromResult(AuthenticateResult.Fail("Missing Authorization Header")); - try { + try + { var tokenEntropy = _configuration.APP_AES_KEY; - if (tokenEntropy.IsNullOrWhiteSpace()) { + if (tokenEntropy.IsNullOrWhiteSpace()) + { _logger.LogWarning("No token entropy is available in env:TOKEN_ENTROPY, Basic auth is disabled"); return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header")); } @@ -47,16 +49,19 @@ public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSc var decryptedString = Encoding.UTF8.GetString(credentialBytes).DecryptWithAes(tokenEntropy); var tokenIsGuid = Guid.TryParse(decryptedString, out var tokenId); - if (!tokenIsGuid) { + if (!tokenIsGuid) + { return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header")); } var token = _context.AccessTokens.Include(c => c.User).SingleOrDefault(c => c.Id == tokenId); - if (token == default) { + if (token == default) + { return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header: Not Found")); } - if (token.HasExpired) { + if (token.HasExpired) + { return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header: Expired")); } @@ -72,7 +77,9 @@ public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSc var ticket = new AuthenticationTicket(principal, AppConstants.BASIC_AUTH_SCHEME); return Task.FromResult(AuthenticateResult.Success(ticket)); - } catch (Exception e) { + } + catch (Exception e) + { _logger.LogError(e, $"An exception occured when challenging {AppConstants.BASIC_AUTH_SCHEME}"); return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header")); } |
