Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

11039 the api should return a 401 status code when a session is invalid #11658

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public class ServiceRepositorySettings : ISettingsMarker
public string GiteaLoginUrl { get; set; }

/// <summary>
/// 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
/// </summary>
public string BaseResourceFolderContainer { get; set; }

Expand Down
12 changes: 6 additions & 6 deletions backend/src/Designer/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public IActionResult Error()
/// <returns>The login page</returns>
public async Task<IActionResult> Login()
{
string userName = string.Empty;
string userName;
string goToUrl = "/";

// Verify that user is not logged in already.
Expand All @@ -141,7 +141,7 @@ public async Task<IActionResult> 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);
}
Expand All @@ -153,7 +153,7 @@ public async Task<IActionResult> Login()

_logger.LogInformation("Updating app key for " + userName);
KeyValuePair<string, string> accessKeyValuePair = await _giteaApi.GetSessionAppKey() ?? default(KeyValuePair<string, string>);
List<Claim> claims = new List<Claim>();
List<Claim> claims = new();
const string Issuer = "https://altinn.no";
if (!accessKeyValuePair.Equals(default(KeyValuePair<string, string>)))
{
Expand All @@ -165,10 +165,10 @@ public async Task<IActionResult> 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(
Expand Down Expand Up @@ -227,7 +227,7 @@ public IActionResult AppToken(AppKey appKey)
/// <returns>The debug info you want</returns>
public async Task<IActionResult> 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());
Expand Down
8 changes: 4 additions & 4 deletions backend/src/Designer/Controllers/SessionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
Expand Down Expand Up @@ -71,19 +71,19 @@ public async Task<ActionResult> 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);
}

/// <summary>
Expand Down
5 changes: 3 additions & 2 deletions backend/src/Designer/Helpers/AuthenticationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

if (context.User != null)
{
Console.WriteLine("user: " + context.User);
Fixed Show fixed Hide fixed
foreach (Claim claim in context.User.Claims)
{
if (claim.Type.Equals(AltinnCoreClaimTypes.Developer))
Expand Down Expand Up @@ -106,7 +107,7 @@
}

/// <summary>
/// Returns the designer cookie
/// Returns the designer cookie
/// </summary>
/// <param name="context">Httpcontext with request</param>
/// <param name="cookieHost">The cookie host</param>
Expand All @@ -124,7 +125,7 @@
/// <returns>A header value string</returns>
public static string GetDeveloperTokenHeaderValue(HttpContext context)
{
return "token " + AuthenticationHelper.GetDeveloperAppToken(context);
return "token " + GetDeveloperAppToken(context);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Net;
using System.Threading.Tasks;

using Altinn.Studio.Designer.Authorization;
Expand Down Expand Up @@ -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))
{
Expand Down
12 changes: 6 additions & 6 deletions backend/src/Designer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@

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);
Expand All @@ -98,7 +98,7 @@
!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(
Expand Down Expand Up @@ -129,7 +129,7 @@
}
}

logger.LogInformation($"// Program.cs // SetConfigurationProviders // Configured providers.");
logger.LogInformation("// Program.cs // SetConfigurationProviders // Configured providers");
}

void ConfigureLogging(ILoggingBuilder builder)
Expand All @@ -149,7 +149,7 @@
// standalone package Microsoft.Extensions.Logging.ApplicationInsights
// or if you want to capture logs from early in the application startup
// pipeline from Startup.cs or Program.cs itself.
builder.AddApplicationInsights(applicationInsightsKey);

Check warning on line 152 in backend/src/Designer/Program.cs

View workflow job for this annotation

GitHub Actions / Run integration tests against actual gitea

'ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights(ILoggingBuilder, string)' is obsolete: 'InstrumentationKey based global ingestion is being deprecated. Use the AddApplicationInsights() overload which accepts Action<TelemetryConfiguration> and set TelemetryConfiguration.ConnectionString. See https://github.com/microsoft/ApplicationInsights-dotnet/issues/2560 for more details.'

Check warning on line 152 in backend/src/Designer/Program.cs

View workflow job for this annotation

GitHub Actions / Run dotnet build and test (windows-latest)

'ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights(ILoggingBuilder, string)' is obsolete: 'InstrumentationKey based global ingestion is being deprecated. Use the AddApplicationInsights() overload which accepts Action<TelemetryConfiguration> and set TelemetryConfiguration.ConnectionString. See https://github.com/microsoft/ApplicationInsights-dotnet/issues/2560 for more details.'

Check warning on line 152 in backend/src/Designer/Program.cs

View workflow job for this annotation

GitHub Actions / Run dotnet build and test (macos-latest)

'ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights(ILoggingBuilder, string)' is obsolete: 'InstrumentationKey based global ingestion is being deprecated. Use the AddApplicationInsights() overload which accepts Action<TelemetryConfiguration> and set TelemetryConfiguration.ConnectionString. See https://github.com/microsoft/ApplicationInsights-dotnet/issues/2560 for more details.'

// Optional: Apply filters to control what logs are sent to Application Insights.
// The following configures LogLevel Information or above to be sent to
Expand All @@ -171,7 +171,7 @@

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<KestrelServerOptions>(options =>
{
Expand Down Expand Up @@ -213,7 +213,7 @@
// Add application insight telemetry
if (!string.IsNullOrEmpty(applicationInsightsKey))
{
services.AddApplicationInsightsTelemetry(applicationInsightsKey);

Check warning on line 216 in backend/src/Designer/Program.cs

View workflow job for this annotation

GitHub Actions / Run integration tests against actual gitea

'ApplicationInsightsExtensions.AddApplicationInsightsTelemetry(IServiceCollection, string)' is obsolete: 'InstrumentationKey based global ingestion is being deprecated. Use the AddApplicationInsightsTelemetry() overload which accepts Action<ApplicationInsightsServiceOptions> and set ApplicationInsightsServiceOptions.ConnectionString. See https://github.com/microsoft/ApplicationInsights-dotnet/issues/2560 for more details.'

Check warning on line 216 in backend/src/Designer/Program.cs

View workflow job for this annotation

GitHub Actions / Run dotnet build and test (windows-latest)

'ApplicationInsightsExtensions.AddApplicationInsightsTelemetry(IServiceCollection, string)' is obsolete: 'InstrumentationKey based global ingestion is being deprecated. Use the AddApplicationInsightsTelemetry() overload which accepts Action<ApplicationInsightsServiceOptions> and set ApplicationInsightsServiceOptions.ConnectionString. See https://github.com/microsoft/ApplicationInsights-dotnet/issues/2560 for more details.'

Check warning on line 216 in backend/src/Designer/Program.cs

View workflow job for this annotation

GitHub Actions / Run dotnet build and test (macos-latest)

'ApplicationInsightsExtensions.AddApplicationInsightsTelemetry(IServiceCollection, string)' is obsolete: 'InstrumentationKey based global ingestion is being deprecated. Use the AddApplicationInsightsTelemetry() overload which accepts Action<ApplicationInsightsServiceOptions> and set ApplicationInsightsServiceOptions.ConnectionString. See https://github.com/microsoft/ApplicationInsights-dotnet/issues/2560 for more details.'
services.ConfigureTelemetryModule<EventCounterCollectionModule>(
(module, o) =>
{
Expand Down Expand Up @@ -249,12 +249,12 @@

// Auto register all settings classes
services.RegisterSettingsByBaseType<ISettingsMarker>(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");
Expand Down
1 change: 0 additions & 1 deletion backend/src/Designer/RepositoryClient/Model/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using System.Text;
using Newtonsoft.Json;

namespace Altinn.Studio.Designer.RepositoryClient.Model
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@
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;
using Altinn.Studio.Designer.Helpers;
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private static QueueBuildRequest CreateBuildRequest(QueueBuildParameters queueBu
private async Task<Build> 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);

Expand Down
Original file line number Diff line number Diff line change
@@ -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<HttpResponseMessage> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,26 @@ private static IHttpClientBuilder AddKubernetesWrapperTypedHttpClient(this IServ
return services.AddHttpClient<IKubernetesWrapperClient, KubernetesWrapperClient>();
}

private static IHttpClientBuilder AddGiteaTypedHttpClient(this IServiceCollection services, IConfiguration config)
private static IHttpClientBuilder AddGiteaTypedHttpClient(this IServiceCollection services,
IConfiguration config)
=> services.AddHttpClient<IGitea, GiteaAPIWrapper>((sp, httpClient) =>
{
IHttpContextAccessor httpContextAccessor = sp.GetRequiredService<IHttpContextAccessor>();
ServiceRepositorySettings serviceRepSettings = config.GetSection("ServiceRepositorySettings").Get<ServiceRepositorySettings>();
Uri uri = new Uri(serviceRepSettings.ApiEndPoint);
ServiceRepositorySettings serviceRepoSettings =
config.GetSection("ServiceRepositorySettings").Get<ServiceRepositorySettings>();
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<IHttpContextAccessor>(), handler);
});


private static IHttpClientBuilder AddAltinnAuthenticationTypedHttpClient(this IServiceCollection services, IConfiguration config)
=> services.AddHttpClient<IAltinnAuthenticationClient, AltinnAuthenticationClient>((sp, httpClient) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ protected override async Task<HttpResponseMessage> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ private async Task<HttpResponseMessage> GetAuthorizedGiteaResponse(CancellationT

using var giteaGetLoginResponse = await giteaClient.GetAsync(giteaLoginUrl, cancellationToken);
string htmlContent = await giteaGetLoginResponse.Content.ReadAsStringAsync(cancellationToken);
List<KeyValuePair<string, string>> formValues = new List<KeyValuePair<string, string>>
List<KeyValuePair<string, string>> formValues = new()
{
new KeyValuePair<string, string>("user_name", GiteaConstants.TestUser),
new KeyValuePair<string, string>("password", GiteaConstants.TestUserPassword),
new KeyValuePair<string, string>("_csrf", GetStringFromHtmlContent(htmlContent, "<input type=\"hidden\" name=\"_csrf\" value=\"", "\"")),
};

using FormUrlEncodedContent content = new FormUrlEncodedContent(formValues);
using FormUrlEncodedContent content = new(formValues);

using var giteaPostLoginMessage = new HttpRequestMessage(HttpMethod.Post, giteaLoginUrl)
{
Expand Down Expand Up @@ -82,14 +82,14 @@ private async Task<HttpResponseMessage> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using Altinn.Studio.Designer.Controllers;
using Altinn.Studio.Designer.RepositoryClient.Model;
using Designer.Tests.Fixtures;
using Designer.Tests.Utils;
Expand All @@ -27,7 +26,7 @@ public UserControllerGiteaIntegrationTests(WebApplicationFactory<Program> 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);

Expand All @@ -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<List<Repository>>();
Expand Down
Loading
Loading