From f69f1f510d5e17efa97972f66cc135312f93dd71 Mon Sep 17 00:00:00 2001 From: andrealouisestanderen Date: Thu, 23 Nov 2023 15:14:21 +0100 Subject: [PATCH 1/6] Clean up --- .../Configuration/ServiceRepositorySettings.cs | 2 +- backend/src/Designer/Controllers/HomeController.cs | 12 ++++++------ .../src/Designer/Controllers/SessionController.cs | 8 ++++---- backend/src/Designer/Helpers/AuthenticationHelper.cs | 5 +++-- .../Infrastructure/AuthenticationConfiguration.cs | 5 ++--- backend/src/Designer/Program.cs | 12 ++++++------ backend/src/Designer/RepositoryClient/Model/User.cs | 1 - .../GiteaAPIWrapper/GiteaAPIWrapper.cs | 2 -- .../AzureDevOps/AzureDevOpsBuildClient.cs | 2 +- .../ApiTestsAuthAndCookieDelegatingHandler.cs | 4 ++-- .../Fixtures/GiteaAuthDelegatingHandler.cs | 4 ++-- .../UserControllerGiteaIntegrationTests.cs | 5 ++--- backend/tests/Designer.Tests/Utils/PrincipalUtil.cs | 5 ++--- 13 files changed, 31 insertions(+), 36 deletions(-) diff --git a/backend/src/Designer/Configuration/ServiceRepositorySettings.cs b/backend/src/Designer/Configuration/ServiceRepositorySettings.cs index 29b4d90492c..ab9bff10d3c 100644 --- a/backend/src/Designer/Configuration/ServiceRepositorySettings.cs +++ b/backend/src/Designer/Configuration/ServiceRepositorySettings.cs @@ -172,7 +172,7 @@ public class ServiceRepositorySettings : ISettingsMarker public string GiteaLoginUrl { get; set; } /// - /// Gets or sets the BaseResourceFolderContainer that identifes where in the docker container the runtime can find files needed + /// Gets or sets the BaseResourceFolderContainer that identifies where in the docker container the runtime can find files needed /// public string BaseResourceFolderContainer { get; set; } diff --git a/backend/src/Designer/Controllers/HomeController.cs b/backend/src/Designer/Controllers/HomeController.cs index 61734fc4fef..ca9b0171654 100644 --- a/backend/src/Designer/Controllers/HomeController.cs +++ b/backend/src/Designer/Controllers/HomeController.cs @@ -126,7 +126,7 @@ public IActionResult Error() /// The login page public async Task Login() { - string userName = string.Empty; + string userName; string goToUrl = "/"; // Verify that user is not logged in already. @@ -141,7 +141,7 @@ public async Task Login() userName = await _giteaApi.GetUserNameFromUI(); if (string.IsNullOrEmpty(userName)) { - return (Environment.GetEnvironmentVariable("ServiceRepositorySettings__GiteaLoginUrl") != null) + return Environment.GetEnvironmentVariable("ServiceRepositorySettings__GiteaLoginUrl") != null ? Redirect(Environment.GetEnvironmentVariable("ServiceRepositorySettings__GiteaLoginUrl")) : Redirect(_settings.GiteaLoginUrl); } @@ -153,7 +153,7 @@ public async Task Login() _logger.LogInformation("Updating app key for " + userName); KeyValuePair accessKeyValuePair = await _giteaApi.GetSessionAppKey() ?? default(KeyValuePair); - List claims = new List(); + List claims = new (); const string Issuer = "https://altinn.no"; if (!accessKeyValuePair.Equals(default(KeyValuePair))) { @@ -165,10 +165,10 @@ public async Task Login() } claims.Add(new Claim(AltinnCoreClaimTypes.Developer, userName, ClaimValueTypes.String, Issuer)); - ClaimsIdentity identity = new ClaimsIdentity("TestUserLogin"); + ClaimsIdentity identity = new ("TestUserLogin"); identity.AddClaims(claims); - ClaimsPrincipal principal = new ClaimsPrincipal(identity); + ClaimsPrincipal principal = new (identity); string timeoutString = DateTime.UtcNow.AddMinutes(_generalSettings.SessionDurationInMinutes - 5).ToString(); HttpContext.Response.Cookies.Append( @@ -227,7 +227,7 @@ public IActionResult AppToken(AppKey appKey) /// The debug info you want public async Task Debug() { - StringBuilder stringBuilder = new StringBuilder(); + StringBuilder stringBuilder = new (); stringBuilder.AppendLine("Debug info"); stringBuilder.AppendLine("App token is: " + _sourceControl.GetAppToken()); stringBuilder.AppendLine("App token id is " + _sourceControl.GetAppTokenId()); diff --git a/backend/src/Designer/Controllers/SessionController.cs b/backend/src/Designer/Controllers/SessionController.cs index 5defc8c156c..fd8a67502f5 100644 --- a/backend/src/Designer/Controllers/SessionController.cs +++ b/backend/src/Designer/Controllers/SessionController.cs @@ -22,7 +22,7 @@ namespace Altinn.Studio.Designer.Controllers public class SessionController : ControllerBase { private readonly GeneralSettings _settings; - private readonly int _sessingExtensionInMinutes = 30; + private readonly int _sessionExtensionInMinutes = 30; private readonly IHttpContextAccessor _httpContextAccessor; /// @@ -71,19 +71,19 @@ public async Task KeepAlive() return Unauthorized(); } - HttpContext.Response.Cookies.Append(_settings.SessionTimeoutCookieName, DateTime.UtcNow.AddMinutes(_sessingExtensionInMinutes - 5).ToString()); + HttpContext.Response.Cookies.Append(_settings.SessionTimeoutCookieName, DateTime.UtcNow.AddMinutes(_sessionExtensionInMinutes - 5).ToString()); await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, HttpContext.User, new AuthenticationProperties { - ExpiresUtc = DateTime.UtcNow.AddMinutes(_sessingExtensionInMinutes), + ExpiresUtc = DateTime.UtcNow.AddMinutes(_sessionExtensionInMinutes), IsPersistent = false, AllowRefresh = false, }); - return Ok(_sessingExtensionInMinutes); + return Ok(_sessionExtensionInMinutes); } /// diff --git a/backend/src/Designer/Helpers/AuthenticationHelper.cs b/backend/src/Designer/Helpers/AuthenticationHelper.cs index 5bd978d7d7f..e66e5e5b33c 100644 --- a/backend/src/Designer/Helpers/AuthenticationHelper.cs +++ b/backend/src/Designer/Helpers/AuthenticationHelper.cs @@ -23,6 +23,7 @@ public static string GetDeveloperUserName(HttpContext context) if (context.User != null) { + Console.WriteLine("user: " + context.User); foreach (Claim claim in context.User.Claims) { if (claim.Type.Equals(AltinnCoreClaimTypes.Developer)) @@ -106,7 +107,7 @@ public static string GetDeveloperAppTokenId(HttpContext context) } /// - /// Returns the designer cookie + /// Returns the designer cookie /// /// Httpcontext with request /// The cookie host @@ -124,7 +125,7 @@ public static Cookie GetDesignerCookie(HttpContext context, string cookieHost) /// A header value string public static string GetDeveloperTokenHeaderValue(HttpContext context) { - return "token " + AuthenticationHelper.GetDeveloperAppToken(context); + return "token " + GetDeveloperAppToken(context); } /// diff --git a/backend/src/Designer/Infrastructure/AuthenticationConfiguration.cs b/backend/src/Designer/Infrastructure/AuthenticationConfiguration.cs index c2ef260acc7..17db55ac9fc 100644 --- a/backend/src/Designer/Infrastructure/AuthenticationConfiguration.cs +++ b/backend/src/Designer/Infrastructure/AuthenticationConfiguration.cs @@ -1,4 +1,3 @@ -using System.Net; using System.Threading.Tasks; using Altinn.Studio.Designer.Authorization; @@ -37,12 +36,12 @@ public static IServiceCollection ConfigureAuthentication(this IServiceCollection { options.AccessDeniedPath = "/Home/NotAuthorized/"; options.LogoutPath = "/Home/Logout/"; - options.Cookie.Name = Altinn.Studio.Designer.Constants.General.DesignerCookieName; + options.Cookie.Name = Constants.General.DesignerCookieName; options.Events = new CookieAuthenticationEvents { // Add Custom Event handler to be able to redirect users for authentication upgrade OnRedirectToAccessDenied = NotAuthorizedHandler.RedirectToNotAuthorized, - OnRedirectToLogin = async (context) => + OnRedirectToLogin = async context => { if (context.Request.Path.Value.Contains("keepalive", System.StringComparison.OrdinalIgnoreCase)) { diff --git a/backend/src/Designer/Program.cs b/backend/src/Designer/Program.cs index 00eb3c4d778..3d3d4963086 100644 --- a/backend/src/Designer/Program.cs +++ b/backend/src/Designer/Program.cs @@ -72,7 +72,7 @@ void ConfigureSetupLogging() async Task SetConfigurationProviders(ConfigurationManager config, IWebHostEnvironment hostingEnvironment) { - logger.LogInformation($"// Program.cs // SetConfigurationProviders // Attempting to configure providers."); + logger.LogInformation("// Program.cs // SetConfigurationProviders // Attempting to configure providers"); string basePath = Directory.GetParent(Directory.GetCurrentDirectory()).FullName; config.SetBasePath(basePath); config.AddJsonFile(basePath + "app/altinn-appsettings/altinn-appsettings-secret.json", optional: true, reloadOnChange: true); @@ -98,7 +98,7 @@ async Task SetConfigurationProviders(ConfigurationManager config, IWebHostEnviro !string.IsNullOrEmpty(keyVaultSettings.ClientSecret) && !string.IsNullOrEmpty(keyVaultSettings.SecretUri)) { - logger.LogInformation("// Program.cs // SetConfigurationProviders // Attempting to configure KeyVault."); + logger.LogInformation("// Program.cs // SetConfigurationProviders // Attempting to configure KeyVault"); AzureServiceTokenProvider azureServiceTokenProvider = new($"RunAs=App;AppId={keyVaultSettings.ClientId};TenantId={keyVaultSettings.TenantId};AppKey={keyVaultSettings.ClientSecret}"); KeyVaultClient keyVaultClient = new( new KeyVaultClient.AuthenticationCallback( @@ -129,7 +129,7 @@ async Task SetConfigurationProviders(ConfigurationManager config, IWebHostEnviro } } - logger.LogInformation($"// Program.cs // SetConfigurationProviders // Configured providers."); + logger.LogInformation("// Program.cs // SetConfigurationProviders // Configured providers"); } void ConfigureLogging(ILoggingBuilder builder) @@ -171,7 +171,7 @@ void ConfigureLogging(ILoggingBuilder builder) void ConfigureServices(IServiceCollection services, IConfiguration configuration, IWebHostEnvironment env) { - logger.LogInformation($"// Program.cs // ConfigureServices // Attempting to configure services."); + logger.LogInformation("// Program.cs // ConfigureServices // Attempting to configure services"); services.Configure(options => { @@ -249,12 +249,12 @@ void ConfigureServices(IServiceCollection services, IConfiguration configuration // Auto register all settings classes services.RegisterSettingsByBaseType(configuration); - logger.LogInformation($"// Program.cs // ConfigureServices // Configuration complete"); + logger.LogInformation("// Program.cs // ConfigureServices // Configuration complete"); } void Configure(IConfiguration configuration) { - logger.LogInformation($"// Program.cs // Configure // Attempting to configure env."); + logger.LogInformation("// Program.cs // Configure // Attempting to configure env"); if (app.Environment.IsDevelopment() || app.Environment.IsStaging()) { app.UseExceptionHandler("/error-local-development"); diff --git a/backend/src/Designer/RepositoryClient/Model/User.cs b/backend/src/Designer/RepositoryClient/Model/User.cs index a59d19a50b4..e49d0175d7f 100644 --- a/backend/src/Designer/RepositoryClient/Model/User.cs +++ b/backend/src/Designer/RepositoryClient/Model/User.cs @@ -13,7 +13,6 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using System.Text; -using Newtonsoft.Json; namespace Altinn.Studio.Designer.RepositoryClient.Model { diff --git a/backend/src/Designer/Services/Implementation/GiteaAPIWrapper/GiteaAPIWrapper.cs b/backend/src/Designer/Services/Implementation/GiteaAPIWrapper/GiteaAPIWrapper.cs index a254afb003d..bb58177ea8e 100644 --- a/backend/src/Designer/Services/Implementation/GiteaAPIWrapper/GiteaAPIWrapper.cs +++ b/backend/src/Designer/Services/Implementation/GiteaAPIWrapper/GiteaAPIWrapper.cs @@ -7,7 +7,6 @@ using System.Text; using System.Text.Json; using System.Text.RegularExpressions; -using System.Threading; using System.Threading.Tasks; using System.Web; using Altinn.Studio.Designer.Configuration; @@ -15,7 +14,6 @@ using Altinn.Studio.Designer.Models; using Altinn.Studio.Designer.RepositoryClient.Model; using Altinn.Studio.Designer.Services.Interfaces; - using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; diff --git a/backend/src/Designer/TypedHttpClients/AzureDevOps/AzureDevOpsBuildClient.cs b/backend/src/Designer/TypedHttpClients/AzureDevOps/AzureDevOpsBuildClient.cs index a43854154bf..337cc717974 100644 --- a/backend/src/Designer/TypedHttpClients/AzureDevOps/AzureDevOpsBuildClient.cs +++ b/backend/src/Designer/TypedHttpClients/AzureDevOps/AzureDevOpsBuildClient.cs @@ -83,7 +83,7 @@ private static QueueBuildRequest CreateBuildRequest(QueueBuildParameters queueBu private async Task SendRequest(QueueBuildRequest queueBuildRequest) { string requestBody = JsonConvert.SerializeObject(queueBuildRequest); - using StringContent httpContent = new StringContent(requestBody, Encoding.UTF8, "application/json"); + using StringContent httpContent = new (requestBody, Encoding.UTF8, "application/json"); string requestUri = "?api-version=5.1"; _logger.LogInformation("Doing a request toward: {HttpClientBaseAddress}{RequestUri}", _httpClient.BaseAddress, requestUri); diff --git a/backend/tests/Designer.Tests/Controllers/ApiTests/ApiTestsAuthAndCookieDelegatingHandler.cs b/backend/tests/Designer.Tests/Controllers/ApiTests/ApiTestsAuthAndCookieDelegatingHandler.cs index 4ea1748a75a..b06e65fe6bf 100644 --- a/backend/tests/Designer.Tests/Controllers/ApiTests/ApiTestsAuthAndCookieDelegatingHandler.cs +++ b/backend/tests/Designer.Tests/Controllers/ApiTests/ApiTestsAuthAndCookieDelegatingHandler.cs @@ -40,14 +40,14 @@ protected override async Task SendAsync(HttpRequestMessage if (loginResponse.Headers.Contains("Set-Cookie")) { cookies = loginResponse.Headers.GetValues("Set-Cookie"); - SetAltinnStudiCookieFromResponseHeader(httpRequestMessageXsrf, cookies); + SetAltinnStudioCookieFromResponseHeader(httpRequestMessageXsrf, cookies); } var xsrfResponse = await base.SendAsync(httpRequestMessageXsrf, cancellationToken); var xsrfcookies = xsrfResponse.Headers.GetValues("Set-Cookie"); var xsrfToken = GetXsrfTokenFromCookie(xsrfcookies); - SetAltinnStudiCookieFromResponseHeader(request, cookies, xsrfToken); + SetAltinnStudioCookieFromResponseHeader(request, cookies, xsrfToken); return await base.SendAsync(request, cancellationToken); } diff --git a/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs b/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs index 17184c419f6..b7a0235ef3f 100644 --- a/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs +++ b/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs @@ -47,14 +47,14 @@ private async Task GetAuthorizedGiteaResponse(CancellationT using var giteaGetLoginResponse = await giteaClient.GetAsync(giteaLoginUrl, cancellationToken); string htmlContent = await giteaGetLoginResponse.Content.ReadAsStringAsync(cancellationToken); - List> formValues = new List> + List> formValues = new () { new KeyValuePair("user_name", GiteaConstants.TestUser), new KeyValuePair("password", GiteaConstants.TestUserPassword), new KeyValuePair("_csrf", GetStringFromHtmlContent(htmlContent, " factor public async Task GetCurrentUser_ShouldReturnOk(string expectedUserName, string expectedEmail) { string requestUrl = "designer/api/user/current"; - using HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl); + using HttpRequestMessage httpRequestMessage = new (HttpMethod.Get, requestUrl); using HttpResponseMessage response = await HttpClient.SendAsync(httpRequestMessage); @@ -51,7 +50,7 @@ public async Task UserRepos_ShouldReturnOk(string org) string targetRepo = TestDataHelper.GenerateTestRepoName(); await CreateAppUsingDesigner(org, targetRepo); - string requestUrl = $"designer/api/user/repos"; + string requestUrl = "designer/api/user/repos"; using var response = await HttpClient.GetAsync(requestUrl); response.StatusCode.Should().Be(HttpStatusCode.OK); var content = await response.Content.ReadAsAsync>(); diff --git a/backend/tests/Designer.Tests/Utils/PrincipalUtil.cs b/backend/tests/Designer.Tests/Utils/PrincipalUtil.cs index 55b68574da1..9ff6ffe8ad4 100644 --- a/backend/tests/Designer.Tests/Utils/PrincipalUtil.cs +++ b/backend/tests/Designer.Tests/Utils/PrincipalUtil.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Security.Claims; using AltinnCore.Authentication.Constants; @@ -15,11 +14,11 @@ public static class PrincipalUtil public static ClaimsPrincipal GetToken(string userName) { - List claims = new List(); + List claims = new (); const string Issuer = "https://altinn.no"; claims.Add(new Claim(AltinnCoreClaimTypes.Developer, userName, ClaimValueTypes.String, Issuer)); - ClaimsIdentity identity = new ClaimsIdentity("TestUserLogin"); + ClaimsIdentity identity = new ("TestUserLogin"); identity.AddClaims(claims); return new ClaimsPrincipal(identity); From 4d9b60f11c5af91fbf27c9b1ca854cad59944e4f Mon Sep 17 00:00:00 2001 From: andrealouisestanderen Date: Thu, 23 Nov 2023 15:15:17 +0100 Subject: [PATCH 2/6] Clean up --- backend/src/Designer/Controllers/HomeController.cs | 8 ++++---- .../AzureDevOps/AzureDevOpsBuildClient.cs | 2 +- .../Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs | 4 ++-- .../UserControllerGiteaIntegrationTests.cs | 2 +- backend/tests/Designer.Tests/Utils/PrincipalUtil.cs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/backend/src/Designer/Controllers/HomeController.cs b/backend/src/Designer/Controllers/HomeController.cs index ca9b0171654..b6b3ebae0ed 100644 --- a/backend/src/Designer/Controllers/HomeController.cs +++ b/backend/src/Designer/Controllers/HomeController.cs @@ -153,7 +153,7 @@ public async Task Login() _logger.LogInformation("Updating app key for " + userName); KeyValuePair accessKeyValuePair = await _giteaApi.GetSessionAppKey() ?? default(KeyValuePair); - List claims = new (); + List claims = new(); const string Issuer = "https://altinn.no"; if (!accessKeyValuePair.Equals(default(KeyValuePair))) { @@ -165,10 +165,10 @@ public async Task Login() } claims.Add(new Claim(AltinnCoreClaimTypes.Developer, userName, ClaimValueTypes.String, Issuer)); - ClaimsIdentity identity = new ("TestUserLogin"); + ClaimsIdentity identity = new("TestUserLogin"); identity.AddClaims(claims); - ClaimsPrincipal principal = new (identity); + ClaimsPrincipal principal = new(identity); string timeoutString = DateTime.UtcNow.AddMinutes(_generalSettings.SessionDurationInMinutes - 5).ToString(); HttpContext.Response.Cookies.Append( @@ -227,7 +227,7 @@ public IActionResult AppToken(AppKey appKey) /// The debug info you want public async Task Debug() { - StringBuilder stringBuilder = new (); + StringBuilder stringBuilder = new(); stringBuilder.AppendLine("Debug info"); stringBuilder.AppendLine("App token is: " + _sourceControl.GetAppToken()); stringBuilder.AppendLine("App token id is " + _sourceControl.GetAppTokenId()); diff --git a/backend/src/Designer/TypedHttpClients/AzureDevOps/AzureDevOpsBuildClient.cs b/backend/src/Designer/TypedHttpClients/AzureDevOps/AzureDevOpsBuildClient.cs index 337cc717974..33c1ce561bf 100644 --- a/backend/src/Designer/TypedHttpClients/AzureDevOps/AzureDevOpsBuildClient.cs +++ b/backend/src/Designer/TypedHttpClients/AzureDevOps/AzureDevOpsBuildClient.cs @@ -83,7 +83,7 @@ private static QueueBuildRequest CreateBuildRequest(QueueBuildParameters queueBu private async Task SendRequest(QueueBuildRequest queueBuildRequest) { string requestBody = JsonConvert.SerializeObject(queueBuildRequest); - using StringContent httpContent = new (requestBody, Encoding.UTF8, "application/json"); + using StringContent httpContent = new(requestBody, Encoding.UTF8, "application/json"); string requestUri = "?api-version=5.1"; _logger.LogInformation("Doing a request toward: {HttpClientBaseAddress}{RequestUri}", _httpClient.BaseAddress, requestUri); diff --git a/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs b/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs index b7a0235ef3f..261f902cf80 100644 --- a/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs +++ b/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs @@ -47,14 +47,14 @@ private async Task GetAuthorizedGiteaResponse(CancellationT using var giteaGetLoginResponse = await giteaClient.GetAsync(giteaLoginUrl, cancellationToken); string htmlContent = await giteaGetLoginResponse.Content.ReadAsStringAsync(cancellationToken); - List> formValues = new () + List> formValues = new() { new KeyValuePair("user_name", GiteaConstants.TestUser), new KeyValuePair("password", GiteaConstants.TestUserPassword), new KeyValuePair("_csrf", GetStringFromHtmlContent(htmlContent, " factor public async Task GetCurrentUser_ShouldReturnOk(string expectedUserName, string expectedEmail) { string requestUrl = "designer/api/user/current"; - using HttpRequestMessage httpRequestMessage = new (HttpMethod.Get, requestUrl); + using HttpRequestMessage httpRequestMessage = new(HttpMethod.Get, requestUrl); using HttpResponseMessage response = await HttpClient.SendAsync(httpRequestMessage); diff --git a/backend/tests/Designer.Tests/Utils/PrincipalUtil.cs b/backend/tests/Designer.Tests/Utils/PrincipalUtil.cs index 9ff6ffe8ad4..cba6572cd8b 100644 --- a/backend/tests/Designer.Tests/Utils/PrincipalUtil.cs +++ b/backend/tests/Designer.Tests/Utils/PrincipalUtil.cs @@ -14,11 +14,11 @@ public static class PrincipalUtil public static ClaimsPrincipal GetToken(string userName) { - List claims = new (); + List claims = new(); const string Issuer = "https://altinn.no"; claims.Add(new Claim(AltinnCoreClaimTypes.Developer, userName, ClaimValueTypes.String, Issuer)); - ClaimsIdentity identity = new ("TestUserLogin"); + ClaimsIdentity identity = new("TestUserLogin"); identity.AddClaims(claims); return new ClaimsPrincipal(identity); From 2033fcba9269c6886b1e884a2480b27323a900b5 Mon Sep 17 00:00:00 2001 From: andrealouisestanderen Date: Thu, 23 Nov 2023 15:15:53 +0100 Subject: [PATCH 3/6] Add custom 401 http delegation handler --- .../DelegatingHandlers/Custom401Handler.cs | 34 +++++++++++++++++++ .../TypedHttpClientRegistration.cs | 20 ++++++----- .../Fixtures/GiteaAuthDelegatingHandler.cs | 4 +-- .../Utils/AuthenticationUtil.cs | 6 ++-- 4 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 backend/src/Designer/TypedHttpClients/DelegatingHandlers/Custom401Handler.cs diff --git a/backend/src/Designer/TypedHttpClients/DelegatingHandlers/Custom401Handler.cs b/backend/src/Designer/TypedHttpClients/DelegatingHandlers/Custom401Handler.cs new file mode 100644 index 00000000000..00d127047b9 --- /dev/null +++ b/backend/src/Designer/TypedHttpClients/DelegatingHandlers/Custom401Handler.cs @@ -0,0 +1,34 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace Altinn.Studio.Designer.TypedHttpClients.DelegatingHandlers; + +public class Custom401Handler : DelegatingHandler +{ + private readonly IHttpContextAccessor _httpContextAccessor; + + public Custom401Handler(IHttpContextAccessor httpContextAccessor, HttpClientHandler innerHandler) : base(innerHandler) + { + _httpContextAccessor = httpContextAccessor; + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var response = await base.SendAsync(request, cancellationToken); + + if (response.StatusCode == HttpStatusCode.Unauthorized) + { + foreach (var cookie in _httpContextAccessor.HttpContext.Request.Cookies.Keys) + { + _httpContextAccessor.HttpContext.Response.Cookies.Delete(cookie); + _httpContextAccessor.HttpContext.Response.StatusCode = 401; + } + } + + return response; + } +} diff --git a/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs b/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs index b8c0228f18d..61213995eac 100644 --- a/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs +++ b/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs @@ -71,22 +71,26 @@ private static IHttpClientBuilder AddKubernetesWrapperTypedHttpClient(this IServ return services.AddHttpClient(); } - private static IHttpClientBuilder AddGiteaTypedHttpClient(this IServiceCollection services, IConfiguration config) + private static IHttpClientBuilder AddGiteaTypedHttpClient(this IServiceCollection services, + IConfiguration config) => services.AddHttpClient((sp, httpClient) => { IHttpContextAccessor httpContextAccessor = sp.GetRequiredService(); - ServiceRepositorySettings serviceRepSettings = config.GetSection("ServiceRepositorySettings").Get(); - Uri uri = new Uri(serviceRepSettings.ApiEndPoint); + ServiceRepositorySettings serviceRepoSettings = + config.GetSection("ServiceRepositorySettings").Get(); + Uri uri = new Uri(serviceRepoSettings.ApiEndPoint); httpClient.BaseAddress = uri; httpClient.DefaultRequestHeaders.Add( General.AuthorizationTokenHeaderName, AuthenticationHelper.GetDeveloperTokenHeaderValue(httpContextAccessor.HttpContext)); }) - .ConfigurePrimaryHttpMessageHandler(() => - new HttpClientHandler - { - AllowAutoRedirect = true - }); + .ConfigurePrimaryHttpMessageHandler((sp) => + { + var handler = new HttpClientHandler { AllowAutoRedirect = true }; + + return new Custom401Handler(sp.GetRequiredService(), handler); + }); + private static IHttpClientBuilder AddAltinnAuthenticationTypedHttpClient(this IServiceCollection services, IConfiguration config) => services.AddHttpClient((sp, httpClient) => diff --git a/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs b/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs index 261f902cf80..a3b41204c9a 100644 --- a/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs +++ b/backend/tests/Designer.Tests/Fixtures/GiteaAuthDelegatingHandler.cs @@ -82,14 +82,14 @@ private async Task LoginToDesignerAndProxyRequest(HttpRespo if (loginResponse.Headers.Contains("Set-Cookie")) { cookies = loginResponse.Headers.GetValues("Set-Cookie"); - AuthenticationUtil.SetAltinnStudiCookieFromResponseHeader(httpRequestMessageXsrf, cookies); + AuthenticationUtil.SetAltinnStudioCookieFromResponseHeader(httpRequestMessageXsrf, cookies); } var xsrfResponse = await base.SendAsync(httpRequestMessageXsrf, cancellationToken); var xsrfcookies = xsrfResponse.Headers.GetValues("Set-Cookie"); string xsrfToken = AuthenticationUtil.GetXsrfTokenFromCookie(xsrfcookies); - AuthenticationUtil.SetAltinnStudiCookieFromResponseHeader(request, cookies, xsrfToken); + AuthenticationUtil.SetAltinnStudioCookieFromResponseHeader(request, cookies, xsrfToken); SetCookies(request, GetGiteaAuthCookiesFromResponseMessage(xsrfResponse)); return await base.SendAsync(request, cancellationToken); diff --git a/backend/tests/Designer.Tests/Utils/AuthenticationUtil.cs b/backend/tests/Designer.Tests/Utils/AuthenticationUtil.cs index 276730fd011..d5b6512dddc 100644 --- a/backend/tests/Designer.Tests/Utils/AuthenticationUtil.cs +++ b/backend/tests/Designer.Tests/Utils/AuthenticationUtil.cs @@ -27,14 +27,14 @@ public static async Task AddAuthenticateAndAuthAndXsrFCookieToRequest(HttpClient if (loginResponse.Headers.Contains("Set-Cookie")) { cookies = loginResponse.Headers.GetValues("Set-Cookie"); - SetAltinnStudiCookieFromResponseHeader(httpRequestMessageXsrf, cookies); + SetAltinnStudioCookieFromResponseHeader(httpRequestMessageXsrf, cookies); } HttpResponseMessage xsrfResponse = await client.SendAsync(httpRequestMessageXsrf); IEnumerable xsrfcookies = xsrfResponse.Headers.GetValues("Set-Cookie"); string xsrfToken = GetXsrfTokenFromCookie(xsrfcookies); - SetAltinnStudiCookieFromResponseHeader(message, cookies, xsrfToken); + SetAltinnStudioCookieFromResponseHeader(message, cookies, xsrfToken); } internal static string GetXsrfTokenFromCookie(IEnumerable setCookieHeader) @@ -57,7 +57,7 @@ internal static string GetXsrfTokenFromCookie(IEnumerable setCookieHeade return null; } - internal static void SetAltinnStudiCookieFromResponseHeader(HttpRequestMessage requestMessage, IEnumerable setCookieHeader, string xsrfToken = null) + internal static void SetAltinnStudioCookieFromResponseHeader(HttpRequestMessage requestMessage, IEnumerable setCookieHeader, string xsrfToken = null) { if (setCookieHeader != null) { From 9168884bb16ad3c52ecfe2ca982985d99a2b5e91 Mon Sep 17 00:00:00 2001 From: andrealouisestanderen Date: Mon, 27 Nov 2023 13:58:42 +0100 Subject: [PATCH 4/6] Use custom exception in delegation handler and throw same exception from source control fetch remote changes method --- .../Controllers/RepositoryController.cs | 2 +- .../src/Designer/Filters/Git/GitErrorCodes.cs | 1 + .../Git/GitExceptionFilterAttribute.cs | 13 ++++++++----- .../Designer/Helpers/AuthenticationHelper.cs | 1 - .../SourceControlLoggingDecorator.cs | 5 +++++ .../DelegatingHandlers/Custom401Handler.cs | 15 ++++----------- .../Exceptions/GiteaUnathorizedException.cs | 19 +++++++++++++++++++ .../TypedHttpClientRegistration.cs | 2 +- 8 files changed, 39 insertions(+), 19 deletions(-) create mode 100644 backend/src/Designer/TypedHttpClients/Exceptions/GiteaUnathorizedException.cs diff --git a/backend/src/Designer/Controllers/RepositoryController.cs b/backend/src/Designer/Controllers/RepositoryController.cs index 4aeb0a8a742..b0ffb407d82 100644 --- a/backend/src/Designer/Controllers/RepositoryController.cs +++ b/backend/src/Designer/Controllers/RepositoryController.cs @@ -185,7 +185,7 @@ public async Task GetRepository(string org, string repository) /// The repository status [HttpGet] [Route("repo/{org}/{repository:regex(^(?!datamodels$)[[a-z]][[a-z0-9-]]{{1,28}}[[a-z0-9]]$)}/status")] - public RepoStatus RepoStatus(string org, string repository) + public async Task RepoStatus(string org, string repository) { string developer = AuthenticationHelper.GetDeveloperUserName(HttpContext); SemaphoreSlim semaphore = _userRequestsSynchronizationService.GetRequestsSemaphore(org, repository, developer); diff --git a/backend/src/Designer/Filters/Git/GitErrorCodes.cs b/backend/src/Designer/Filters/Git/GitErrorCodes.cs index d3c6393f3ea..3c5ed7e7acf 100644 --- a/backend/src/Designer/Filters/Git/GitErrorCodes.cs +++ b/backend/src/Designer/Filters/Git/GitErrorCodes.cs @@ -4,5 +4,6 @@ public class GitErrorCodes { public const string NonFastForwardError = "GT_01"; public const string RepositoryNotFound = "GT_02"; + public const string GiteaSessionExpired = "GT_03"; } } diff --git a/backend/src/Designer/Filters/Git/GitExceptionFilterAttribute.cs b/backend/src/Designer/Filters/Git/GitExceptionFilterAttribute.cs index 1489ee4cfbd..73b1cbeab07 100644 --- a/backend/src/Designer/Filters/Git/GitExceptionFilterAttribute.cs +++ b/backend/src/Designer/Filters/Git/GitExceptionFilterAttribute.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Net; -using Altinn.Studio.Designer.Models; +using System.Net; +using Altinn.Studio.Designer.TypedHttpClients.Exceptions; using LibGit2Sharp; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; @@ -25,10 +23,15 @@ public override void OnException(ExceptionContext context) context.Result = new ObjectResult(ProblemDetailsUtils.GenerateProblemDetails(context.Exception, GitErrorCodes.NonFastForwardError, HttpStatusCode.Conflict)) { StatusCode = (int)HttpStatusCode.Conflict }; } - if (context.Exception is LibGit2Sharp.RepositoryNotFoundException) + if (context.Exception is RepositoryNotFoundException) { context.Result = new ObjectResult(ProblemDetailsUtils.GenerateProblemDetails(context.Exception, GitErrorCodes.RepositoryNotFound, HttpStatusCode.NotFound)) { StatusCode = (int)HttpStatusCode.NotFound }; } + + if (context.Exception is GiteaUnathorizedException) + { + context.Result = new ObjectResult(ProblemDetailsUtils.GenerateProblemDetails(context.Exception, GitErrorCodes.GiteaSessionExpired, HttpStatusCode.Unauthorized)) { StatusCode = (int)HttpStatusCode.Unauthorized }; + } } } } diff --git a/backend/src/Designer/Helpers/AuthenticationHelper.cs b/backend/src/Designer/Helpers/AuthenticationHelper.cs index e66e5e5b33c..a65e5a850e1 100644 --- a/backend/src/Designer/Helpers/AuthenticationHelper.cs +++ b/backend/src/Designer/Helpers/AuthenticationHelper.cs @@ -23,7 +23,6 @@ public static string GetDeveloperUserName(HttpContext context) if (context.User != null) { - Console.WriteLine("user: " + context.User); foreach (Claim claim in context.User.Claims) { if (claim.Type.Equals(AltinnCoreClaimTypes.Developer)) diff --git a/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs b/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs index 7b6cb287e01..74f49979d84 100644 --- a/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs +++ b/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs @@ -6,6 +6,7 @@ using Altinn.Studio.Designer.Models; using Altinn.Studio.Designer.RepositoryClient.Model; using Altinn.Studio.Designer.Services.Interfaces; +using Altinn.Studio.Designer.TypedHttpClients.Exceptions; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -170,6 +171,10 @@ public void FetchRemoteChanges(string org, string repository) { _decoratedService.FetchRemoteChanges(org, repository); } + catch (LibGit2Sharp.LibGit2SharpException) + { + throw new GiteaUnathorizedException("Gitea session is invalid."); + } catch (Exception ex) { LogError(ex, "FetchRemoteChanges", org, repository); diff --git a/backend/src/Designer/TypedHttpClients/DelegatingHandlers/Custom401Handler.cs b/backend/src/Designer/TypedHttpClients/DelegatingHandlers/Custom401Handler.cs index 00d127047b9..a42047945ca 100644 --- a/backend/src/Designer/TypedHttpClients/DelegatingHandlers/Custom401Handler.cs +++ b/backend/src/Designer/TypedHttpClients/DelegatingHandlers/Custom401Handler.cs @@ -1,19 +1,15 @@ -using System; using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; +using Altinn.Studio.Designer.TypedHttpClients.Exceptions; namespace Altinn.Studio.Designer.TypedHttpClients.DelegatingHandlers; public class Custom401Handler : DelegatingHandler { - private readonly IHttpContextAccessor _httpContextAccessor; - - public Custom401Handler(IHttpContextAccessor httpContextAccessor, HttpClientHandler innerHandler) : base(innerHandler) + public Custom401Handler(HttpClientHandler innerHandler) : base(innerHandler) { - _httpContextAccessor = httpContextAccessor; } protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) @@ -22,11 +18,8 @@ protected override async Task SendAsync(HttpRequestMessage if (response.StatusCode == HttpStatusCode.Unauthorized) { - foreach (var cookie in _httpContextAccessor.HttpContext.Request.Cookies.Keys) - { - _httpContextAccessor.HttpContext.Response.Cookies.Delete(cookie); - _httpContextAccessor.HttpContext.Response.StatusCode = 401; - } + response.Dispose(); + throw new GiteaUnathorizedException("Gitea session is invalid"); } return response; diff --git a/backend/src/Designer/TypedHttpClients/Exceptions/GiteaUnathorizedException.cs b/backend/src/Designer/TypedHttpClients/Exceptions/GiteaUnathorizedException.cs new file mode 100644 index 00000000000..23960b20309 --- /dev/null +++ b/backend/src/Designer/TypedHttpClients/Exceptions/GiteaUnathorizedException.cs @@ -0,0 +1,19 @@ +using System; + +namespace Altinn.Studio.Designer.TypedHttpClients.Exceptions +{ + /// + /// Altinn specific exception which can be caught specifically when Gitea returns Unauthorized (401) + /// + public class GiteaUnathorizedException : Exception + { + /// + /// Constructor + /// + /// A custom message for this specific exception + public GiteaUnathorizedException(string message) + : base(message) + { + } + } +} diff --git a/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs b/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs index 61213995eac..f06c9dce517 100644 --- a/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs +++ b/backend/src/Designer/TypedHttpClients/TypedHttpClientRegistration.cs @@ -88,7 +88,7 @@ private static IHttpClientBuilder AddGiteaTypedHttpClient(this IServiceCollectio { var handler = new HttpClientHandler { AllowAutoRedirect = true }; - return new Custom401Handler(sp.GetRequiredService(), handler); + return new Custom401Handler(handler); }); From 1206f0f305753d1555fdb80dc6641b044b07fc20 Mon Sep 17 00:00:00 2001 From: andrealouisestanderen Date: Mon, 27 Nov 2023 14:21:19 +0100 Subject: [PATCH 5/6] Check for unauthorized exception before throwing custom excpetion --- backend/src/Designer/Controllers/RepositoryController.cs | 2 +- .../Implementation/SourceControlLoggingDecorator.cs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/src/Designer/Controllers/RepositoryController.cs b/backend/src/Designer/Controllers/RepositoryController.cs index b0ffb407d82..4aeb0a8a742 100644 --- a/backend/src/Designer/Controllers/RepositoryController.cs +++ b/backend/src/Designer/Controllers/RepositoryController.cs @@ -185,7 +185,7 @@ public async Task GetRepository(string org, string repository) /// The repository status [HttpGet] [Route("repo/{org}/{repository:regex(^(?!datamodels$)[[a-z]][[a-z0-9-]]{{1,28}}[[a-z0-9]]$)}/status")] - public async Task RepoStatus(string org, string repository) + public RepoStatus RepoStatus(string org, string repository) { string developer = AuthenticationHelper.GetDeveloperUserName(HttpContext); SemaphoreSlim semaphore = _userRequestsSynchronizationService.GetRequestsSemaphore(org, repository, developer); diff --git a/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs b/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs index 74f49979d84..7e4b1b41671 100644 --- a/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs +++ b/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs @@ -171,9 +171,14 @@ public void FetchRemoteChanges(string org, string repository) { _decoratedService.FetchRemoteChanges(org, repository); } - catch (LibGit2Sharp.LibGit2SharpException) + catch (LibGit2Sharp.LibGit2SharpException libGit2SharpException) { - throw new GiteaUnathorizedException("Gitea session is invalid."); + if (libGit2SharpException.Message.Contains("server requires authentication that we do not support")) + { + throw new GiteaUnathorizedException("Gitea session is invalid."); + } + + throw; } catch (Exception ex) { From b602ab5f998d70fa47d0ee03f3e5741b6575a464 Mon Sep 17 00:00:00 2001 From: andrealouisestanderen Date: Tue, 28 Nov 2023 13:29:05 +0100 Subject: [PATCH 6/6] Move exception handling to filter --- .../Designer/Filters/Git/GitExceptionFilterAttribute.cs | 2 +- .../Implementation/SourceControlLoggingDecorator.cs | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/backend/src/Designer/Filters/Git/GitExceptionFilterAttribute.cs b/backend/src/Designer/Filters/Git/GitExceptionFilterAttribute.cs index 73b1cbeab07..0df59603bf1 100644 --- a/backend/src/Designer/Filters/Git/GitExceptionFilterAttribute.cs +++ b/backend/src/Designer/Filters/Git/GitExceptionFilterAttribute.cs @@ -28,7 +28,7 @@ public override void OnException(ExceptionContext context) context.Result = new ObjectResult(ProblemDetailsUtils.GenerateProblemDetails(context.Exception, GitErrorCodes.RepositoryNotFound, HttpStatusCode.NotFound)) { StatusCode = (int)HttpStatusCode.NotFound }; } - if (context.Exception is GiteaUnathorizedException) + if (context.Exception is GiteaUnathorizedException || (context.Exception is LibGit2SharpException && context.Exception.Message.Contains("server requires authentication that we do not support"))) { context.Result = new ObjectResult(ProblemDetailsUtils.GenerateProblemDetails(context.Exception, GitErrorCodes.GiteaSessionExpired, HttpStatusCode.Unauthorized)) { StatusCode = (int)HttpStatusCode.Unauthorized }; } diff --git a/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs b/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs index 7e4b1b41671..9f119134147 100644 --- a/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs +++ b/backend/src/Designer/Services/Implementation/SourceControlLoggingDecorator.cs @@ -171,15 +171,6 @@ public void FetchRemoteChanges(string org, string repository) { _decoratedService.FetchRemoteChanges(org, repository); } - catch (LibGit2Sharp.LibGit2SharpException libGit2SharpException) - { - if (libGit2SharpException.Message.Contains("server requires authentication that we do not support")) - { - throw new GiteaUnathorizedException("Gitea session is invalid."); - } - - throw; - } catch (Exception ex) { LogError(ex, "FetchRemoteChanges", org, repository);