aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/Utilities
diff options
context:
space:
mode:
authorivarlovlie <git@ivarlovlie.no>2022-10-05 14:45:21 +0200
committerivarlovlie <git@ivarlovlie.no>2022-10-05 14:45:21 +0200
commitb7e39b59fd0fc7b5610ebff29035bf622079e0d8 (patch)
tree64be84ebbdac9f7ceced983390c53b10d575af5c /server/src/Utilities
parent2001c035fbb417ab0a3d42cfb04d17420bde4086 (diff)
downloadgreatoffice-b7e39b59fd0fc7b5610ebff29035bf622079e0d8.tar.xz
greatoffice-b7e39b59fd0fc7b5610ebff29035bf622079e0d8.zip
refactor: Change file structure
Diffstat (limited to 'server/src/Utilities')
-rw-r--r--server/src/Utilities/BasicAuthenticationAttribute.cs39
-rw-r--r--server/src/Utilities/BasicAuthenticationHandler.cs79
-rw-r--r--server/src/Utilities/ConfigurationExtensions.cs88
-rw-r--r--server/src/Utilities/GithubAuthenticationHelpers.cs84
-rw-r--r--server/src/Utilities/QuartzJsonSerializer.cs16
-rw-r--r--server/src/Utilities/SwaggerDefaultValues.cs58
-rw-r--r--server/src/Utilities/SwaggerGenOptionsExtensions.cs43
7 files changed, 0 insertions, 407 deletions
diff --git a/server/src/Utilities/BasicAuthenticationAttribute.cs b/server/src/Utilities/BasicAuthenticationAttribute.cs
deleted file mode 100644
index 0bfd007..0000000
--- a/server/src/Utilities/BasicAuthenticationAttribute.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System.Net.Http.Headers;
-using Microsoft.AspNetCore.Mvc.Filters;
-
-namespace IOL.GreatOffice.Api.Utilities;
-
-public class BasicAuthenticationAttribute : TypeFilterAttribute
-{
- public BasicAuthenticationAttribute(string claimPermission) : base(typeof(BasicAuthenticationFilter)) {
- Arguments = new object[] {
- new Claim(claimPermission, "True")
- };
- }
-}
-
-public class BasicAuthenticationFilter : IAuthorizationFilter
-{
- private readonly 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) {
- 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) {
- context.Result = new ForbidResult(AppConstants.BASIC_AUTH_SCHEME);
- }
- } catch {
- // ignore
- }
- }
-}
diff --git a/server/src/Utilities/BasicAuthenticationHandler.cs b/server/src/Utilities/BasicAuthenticationHandler.cs
deleted file mode 100644
index 6138193..0000000
--- a/server/src/Utilities/BasicAuthenticationHandler.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-using System.Net.Http.Headers;
-using System.Text;
-using System.Text.Encodings.Web;
-using Microsoft.Extensions.Options;
-
-namespace IOL.GreatOffice.Api.Utilities;
-
-public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
-{
- private readonly AppDbContext _context;
- private readonly AppConfiguration _configuration;
- private readonly ILogger<BasicAuthenticationHandler> _logger;
-
- public BasicAuthenticationHandler(
- IOptionsMonitor<AuthenticationSchemeOptions> options,
- ILoggerFactory logger,
- UrlEncoder encoder,
- ISystemClock clock,
- AppDbContext context,
- VaultService vaultService
- ) :
- base(options, logger, encoder, clock) {
- _context = context;
- _configuration = vaultService.GetCurrentAppConfiguration();
- _logger = logger.CreateLogger<BasicAuthenticationHandler>();
- }
-
- protected override Task<AuthenticateResult> HandleAuthenticateAsync() {
- var endpoint = Context.GetEndpoint();
- if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null)
- return Task.FromResult(AuthenticateResult.NoResult());
-
- if (!Request.Headers.ContainsKey("Authorization"))
- return Task.FromResult(AuthenticateResult.Fail("Missing Authorization Header"));
-
- try {
- var tokenEntropy = _configuration.APP_AES_KEY;
- 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"));
- }
-
- var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
- if (authHeader.Parameter == null) return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header"));
- var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
- var decryptedString = Encoding.UTF8.GetString(credentialBytes).DecryptWithAes(tokenEntropy);
- var tokenIsGuid = Guid.TryParse(decryptedString, out var tokenId);
-
- 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) {
- return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header: Not Found"));
- }
-
- if (token.HasExpired) {
- return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header: Expired"));
- }
-
- var permissions = new List<Claim>() {
- new(AppConstants.TOKEN_ALLOW_READ, token.AllowRead.ToString()),
- new(AppConstants.TOKEN_ALLOW_UPDATE, token.AllowUpdate.ToString()),
- new(AppConstants.TOKEN_ALLOW_CREATE, token.AllowCreate.ToString()),
- new(AppConstants.TOKEN_ALLOW_DELETE, token.AllowDelete.ToString()),
- };
- var claims = token.User.DefaultClaims().Concat(permissions);
- var identity = new ClaimsIdentity(claims, AppConstants.BASIC_AUTH_SCHEME);
- var principal = new ClaimsPrincipal(identity);
- var ticket = new AuthenticationTicket(principal, AppConstants.BASIC_AUTH_SCHEME);
-
- return Task.FromResult(AuthenticateResult.Success(ticket));
- } catch (Exception e) {
- _logger.LogError(e, $"An exception occured when challenging {AppConstants.BASIC_AUTH_SCHEME}");
- return Task.FromResult(AuthenticateResult.Fail("Invalid Authorization Header"));
- }
- }
-}
diff --git a/server/src/Utilities/ConfigurationExtensions.cs b/server/src/Utilities/ConfigurationExtensions.cs
deleted file mode 100644
index 405c702..0000000
--- a/server/src/Utilities/ConfigurationExtensions.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-namespace IOL.GreatOffice.Api.Utilities;
-
-public static class ConfigurationExtensions
-{
- public static string GetAppDatabaseConnectionString(this IConfiguration config, AppConfiguration configuration) {
- var host = configuration.DB_HOST;
- var port = configuration.DB_PORT;
- var database = configuration.DB_NAME;
- var user = configuration.DB_USER;
- var password = configuration.DB_PASSWORD;
-
- var res = "";
- if (config.GetValue<string>("ASPNETCORE_ENVIRONMENT") == "Development") {
- res = $"Server={host};Port={port};Database={database};User Id={user};Password={password};Include Error Detail=true";
- } else {
- res = $"Server={host};Port={port};Database={database};User Id={user};Password={password}";
- }
-
- Log.Debug("Using app database connection string: " + res);
- return res;
- }
-
- public static string GetAppDatabaseConnectionString(this IConfiguration config, Func<AppConfiguration> configuration) {
- var _configuration = configuration();
- var host = _configuration.DB_HOST;
- var port = _configuration.DB_PORT;
- var database = _configuration.DB_NAME;
- var user = _configuration.DB_USER;
- var password = _configuration.DB_PASSWORD;
-
- var res = "";
- if (config.GetValue<string>("ASPNETCORE_ENVIRONMENT") == "Development") {
- res = $"Server={host};Port={port};Database={database};User Id={user};Password={password};Include Error Detail=true";
- } else {
- res = $"Server={host};Port={port};Database={database};User Id={user};Password={password}";
- }
-
- Log.Debug("Using app database connection string: " + res);
- return res;
- }
-
- public static string GetQuartzDatabaseConnectionString(this IConfiguration config, AppConfiguration configuration) {
- var host = configuration.QUARTZ_DB_HOST;
- var port = configuration.QUARTZ_DB_PORT;
- var database = configuration.QUARTZ_DB_NAME;
- var user = configuration.QUARTZ_DB_USER;
- var password = configuration.QUARTZ_DB_PASSWORD;
-
- var res = "";
- if (config.GetValue<string>("ASPNETCORE_ENVIRONMENT") == "Development") {
- res = $"Server={host};Port={port};Database={database};User Id={user};Password={password};Include Error Detail=true";
- } else {
- res = $"Server={host};Port={port};Database={database};User Id={user};Password={password}";
- }
-
- Log.Debug("Using quartz database connection string: " + res);
- return res;
- }
-
- public static string GetQuartzDatabaseConnectionString(this IConfiguration config, Func<AppConfiguration> configuration) {
- var _configuration = configuration();
- var host = _configuration.QUARTZ_DB_HOST;
- var port = _configuration.QUARTZ_DB_PORT;
- var database = _configuration.QUARTZ_DB_NAME;
- var user = _configuration.QUARTZ_DB_USER;
- var password = _configuration.QUARTZ_DB_PASSWORD;
-
- var res = "";
- if (config.GetValue<string>("ASPNETCORE_ENVIRONMENT") == "Development") {
- res = $"Server={host};Port={port};Database={database};User Id={user};Password={password};Include Error Detail=true";
- } else {
- res = $"Server={host};Port={port};Database={database};User Id={user};Password={password}";
- }
-
- Log.Debug("Using quartz database connection string: " + res);
- return res;
- }
-
- public static string GetVersion(this IConfiguration configuration) {
- var versionFilePath = Path.Combine(AppPaths.AppData.HostPath, "version.txt");
- if (File.Exists(versionFilePath)) {
- var versionText = File.ReadAllText(versionFilePath);
- return versionText + "-" + configuration.GetValue<string>("ASPNETCORE_ENVIRONMENT");
- }
-
- return "unknown-" + configuration.GetValue<string>("ASPNETCORE_ENVIRONMENT");
- }
-}
diff --git a/server/src/Utilities/GithubAuthenticationHelpers.cs b/server/src/Utilities/GithubAuthenticationHelpers.cs
deleted file mode 100644
index a4461d2..0000000
--- a/server/src/Utilities/GithubAuthenticationHelpers.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using Microsoft.AspNetCore.Authentication.OAuth;
-using Npgsql;
-
-namespace IOL.GreatOffice.Api.Utilities;
-
-public static class GithubAuthenticationHelpers
-{
- public static async Task HandleGithubTicketCreation(OAuthCreatingTicketContext context, IConfiguration configuration, AppConfiguration options) {
- var githubId = context.Identity?.FindFirst(p => p.Type == ClaimTypes.NameIdentifier)?.Value;
- var githubUsername = context.Identity?.FindFirst(p => p.Type == ClaimTypes.Name)?.Value;
- var githubEmail = context.Identity?.FindFirst(p => p.Type == ClaimTypes.Email)?.Value;
-
- if (githubId.IsNullOrWhiteSpace() || githubUsername.IsNullOrWhiteSpace() || context.Identity == default) {
- return;
- }
-
- var claims = context.Identity.Claims.ToList();
- foreach (var claim in claims) {
- context.Identity.RemoveClaim(claim);
- }
-
- var connstring = configuration.GetAppDatabaseConnectionString(options);
- var connection = new NpgsqlConnection(connstring);
-
- Log.Information($"Getting user mappings for github user: {githubId}");
- var getMappedUserQuery = @$"SELECT u.id,u.username FROM github_user_mappings INNER JOIN users u on u.id = github_user_mappings.user_id WHERE github_id='{githubId}'";
- await connection.OpenAsync();
- await using var getMappedUserCommand = new NpgsqlCommand(getMappedUserQuery, connection);
- await using var reader = await getMappedUserCommand.ExecuteReaderAsync();
- var handled = false;
- while (await reader.ReadAsync()) {
- try {
- var userId = reader.GetGuid(0);
- var username = reader.GetString(1);
- context.Identity.AddClaim(new Claim(AppClaims.USER_ID, userId.ToString()));
- context.Identity.AddClaim(new Claim(AppClaims.NAME, username));
- if (context.AccessToken != default) {
- context.Identity.AddClaim(new Claim(AppClaims.GITHUB_ACCESS_TOKEN, context.AccessToken ?? ""));
- }
-
- Log.Information($"Found mapping for github id {githubId} mapped to user id {userId}");
- handled = true;
- } catch (Exception e) {
- Log.Error(e, "An exception occured when handling github user mappings");
- handled = false;
- }
- }
-
- await connection.CloseAsync();
-
- if (!handled) {
- var userId = Guid.NewGuid();
-
- var insertUserQuery = $@"INSERT INTO users VALUES ('{userId}', '{githubUsername}', '', '{AppDateTime.UtcNow}')";
- await connection.OpenAsync();
- await using var insertUserCommand = new NpgsqlCommand(insertUserQuery, connection);
- await insertUserCommand.ExecuteNonQueryAsync();
- await connection.CloseAsync();
-
- var refreshTokenEncryptionKey = options.APP_AES_KEY;
- string insertMappingQuery;
-
- if (context.RefreshToken.HasValue() && refreshTokenEncryptionKey.HasValue()) {
- var encryptedRefreshToken = context.RefreshToken.EncryptWithAes(refreshTokenEncryptionKey);
- insertMappingQuery = $@"INSERT INTO github_user_mappings VALUES ('{githubId}', '{userId}', '{githubEmail}', '{encryptedRefreshToken}')";
- } else {
- insertMappingQuery = $@"INSERT INTO github_user_mappings VALUES ('{githubId}', '{userId}', '{githubEmail}', '')";
- }
-
- await connection.OpenAsync();
- await using var insertMappingCommand = new NpgsqlCommand(insertMappingQuery, connection);
- await insertMappingCommand.ExecuteNonQueryAsync();
- await connection.CloseAsync();
-
- context.Identity.AddClaim(new Claim(AppClaims.USER_ID, userId.ToString()));
- context.Identity.AddClaim(new Claim(AppClaims.NAME, githubUsername));
- if (context.AccessToken != default) {
- context.Identity.AddClaim(new Claim(AppClaims.GITHUB_ACCESS_TOKEN, context.AccessToken ?? ""));
- }
-
- Log.Information($"Created mapping for github id {githubId} mapped to user id {userId}");
- }
- }
-}
diff --git a/server/src/Utilities/QuartzJsonSerializer.cs b/server/src/Utilities/QuartzJsonSerializer.cs
deleted file mode 100644
index 164a189..0000000
--- a/server/src/Utilities/QuartzJsonSerializer.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Quartz.Spi;
-
-namespace IOL.GreatOffice.Api.Utilities;
-
-public class QuartzJsonSerializer : IObjectSerializer
-{
- public void Initialize() { }
-
- public byte[] Serialize<T>(T obj) where T : class {
- return JsonSerializer.SerializeToUtf8Bytes(obj);
- }
-
- public T DeSerialize<T>(byte[] data) where T : class {
- return JsonSerializer.Deserialize<T>(data);
- }
-}
diff --git a/server/src/Utilities/SwaggerDefaultValues.cs b/server/src/Utilities/SwaggerDefaultValues.cs
deleted file mode 100644
index 4b5c764..0000000
--- a/server/src/Utilities/SwaggerDefaultValues.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using Microsoft.AspNetCore.Mvc.ApiExplorer;
-using Swashbuckle.AspNetCore.SwaggerGen;
-
-namespace IOL.GreatOffice.Api.Utilities;
-
-/// <summary>
-/// Represents the Swagger/Swashbuckle operation filter used to document the implicit API version parameter.
-/// </summary>
-/// <remarks>This <see cref="IOperationFilter"/> is only required due to bugs in the <see cref="SwaggerGenerator"/>.
-/// Once they are fixed and published, this class can be removed.</remarks>
-public class SwaggerDefaultValues : IOperationFilter
-{
- /// <summary>
- /// Applies the filter to the specified operation using the given context.
- /// </summary>
- /// <param name="operation">The operation to apply the filter to.</param>
- /// <param name="context">The current operation filter context.</param>
- public void Apply(OpenApiOperation operation, OperationFilterContext context) {
- var apiDescription = context.ApiDescription;
-
- operation.Deprecated |= apiDescription.IsDeprecated();
-
- // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1752#issue-663991077
- foreach (var responseType in context.ApiDescription.SupportedResponseTypes) {
- // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/b7cf75e7905050305b115dd96640ddd6e74c7ac9/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs#L383-L387
- var responseKey = responseType.IsDefaultResponse ? "default" : responseType.StatusCode.ToString();
- var response = operation.Responses[responseKey];
-
- foreach (var contentType in response.Content.Keys) {
- if (!responseType.ApiResponseFormats.Any(x => x.MediaType == contentType)) {
- response.Content.Remove(contentType);
- }
- }
- }
-
- if (operation.Parameters == null) {
- return;
- }
-
- // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/412
- // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/413
- foreach (var parameter in operation.Parameters) {
- var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
-
- if (parameter.Description == null) {
- parameter.Description = description.ModelMetadata.Description;
- }
-
- if (parameter.Schema.Default == null && description.DefaultValue != null) {
- // REF: https://github.com/Microsoft/aspnet-api-versioning/issues/429#issuecomment-605402330
- var json = JsonSerializer.Serialize(description.DefaultValue, description.ModelMetadata.ModelType);
- parameter.Schema.Default = OpenApiAnyFactory.CreateFromJson(json);
- }
-
- parameter.Required |= description.IsRequired;
- }
- }
-}
diff --git a/server/src/Utilities/SwaggerGenOptionsExtensions.cs b/server/src/Utilities/SwaggerGenOptionsExtensions.cs
deleted file mode 100644
index a2dcf7a..0000000
--- a/server/src/Utilities/SwaggerGenOptionsExtensions.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-#nullable enable
-using Microsoft.AspNetCore.Mvc.ApiExplorer;
-using Microsoft.AspNetCore.Mvc.Controllers;
-using Swashbuckle.AspNetCore.SwaggerGen;
-using BaseRoute = IOL.GreatOffice.Api.Endpoints.V1.BaseRoute;
-
-namespace IOL.GreatOffice.Api.Utilities;
-
-public static class SwaggerGenOptionsExtensions
-{
- /// <summary>
- /// Updates Swagger document to support ApiEndpoints.<br/><br/>
- /// For controllers inherited from <see cref="BaseRoute"/>:<br/>
- /// - Replaces action Tag with <c>[namespace]</c><br/>
- /// </summary>
- public static void UseApiEndpoints(this SwaggerGenOptions options) {
- options.TagActionsBy(EndpointNamespaceOrDefault);
- }
-
- private static IList<string?> EndpointNamespaceOrDefault(ApiDescription api) {
- if (api.ActionDescriptor is not ControllerActionDescriptor actionDescriptor) {
- throw new InvalidOperationException($"Unable to determine tag for endpoint: {api.ActionDescriptor.DisplayName}");
- }
-
- if (actionDescriptor.ControllerTypeInfo.GetBaseTypesAndThis().Any(t => t == typeof(BaseRoute))) {
- return new[] {
- actionDescriptor.ControllerTypeInfo.Namespace?.Split('.').Last()
- };
- }
-
- return new[] {
- actionDescriptor.ControllerName
- };
- }
-
- public static IEnumerable<Type> GetBaseTypesAndThis(this Type type) {
- Type? current = type;
- while (current != null) {
- yield return current;
- current = current.BaseType;
- }
- }
-}