From e7f7492ce99aad967f0cfcac07e86ffd8403fe40 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 15 Nov 2023 16:08:57 +0100 Subject: [PATCH] Configure Angular cookie using defaults from antiforgery options and fix logging --- .../Security/BackOfficeAntiforgery.cs | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.BackOffice/Security/BackOfficeAntiforgery.cs b/src/Umbraco.Web.BackOffice/Security/BackOfficeAntiforgery.cs index a6e4e96d8b..cc1fc0c4bc 100644 --- a/src/Umbraco.Web.BackOffice/Security/BackOfficeAntiforgery.cs +++ b/src/Umbraco.Web.BackOffice/Security/BackOfficeAntiforgery.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; @@ -20,25 +22,35 @@ namespace Umbraco.Cms.Web.BackOffice.Security; public class BackOfficeAntiforgery : IBackOfficeAntiforgery { private readonly IAntiforgery _internalAntiForgery; - private GlobalSettings _globalSettings; + private readonly CookieBuilder _angularCookieBuilder; + [Obsolete($"Please use the constructor that accepts {nameof(ILoggerFactory)}. Will be removed in V14.")] public BackOfficeAntiforgery(IOptionsMonitor globalSettings) + : this(globalSettings, NullLoggerFactory.Instance) + { } + + public BackOfficeAntiforgery(IOptionsMonitor globalSettings, ILoggerFactory loggerFactory) { + CookieSecurePolicy cookieSecurePolicy = globalSettings.CurrentValue.UseHttps ? CookieSecurePolicy.Always : CookieSecurePolicy.SameAsRequest; + // NOTE: This is the only way to create a separate IAntiForgery service :( // Everything in netcore is internal. I have logged an issue here https://github.com/dotnet/aspnetcore/issues/22217 // but it will not be handled so we have to revert to this. - var services = new ServiceCollection(); - services.AddLogging(); - services.AddAntiforgery(x => - { - x.HeaderName = Constants.Web.AngularHeadername; - x.Cookie.Name = Constants.Web.CsrfValidationCookieName; - x.Cookie.SecurePolicy = globalSettings.CurrentValue.UseHttps ? CookieSecurePolicy.Always : CookieSecurePolicy.SameAsRequest; - }); - ServiceProvider container = services.BuildServiceProvider(); - _internalAntiForgery = container.GetRequiredService(); - _globalSettings = globalSettings.CurrentValue; - globalSettings.OnChange(x => _globalSettings = x); + _internalAntiForgery = new ServiceCollection() + .AddSingleton(loggerFactory) + .AddAntiforgery(x => + { + x.HeaderName = Constants.Web.AngularHeadername; + x.Cookie.Name = Constants.Web.CsrfValidationCookieName; + x.Cookie.SecurePolicy = cookieSecurePolicy; + }) + .BuildServiceProvider() + .GetRequiredService(); + + // Configure cookie builder using defaults from antiforgery options + _angularCookieBuilder = new AntiforgeryOptions().Cookie; + _angularCookieBuilder.HttpOnly = false; // Needs to be accessed from JavaScript + _angularCookieBuilder.SecurePolicy = cookieSecurePolicy; } /// @@ -68,15 +80,6 @@ public class BackOfficeAntiforgery : IBackOfficeAntiforgery // We need to set 2 cookies: // The cookie value that angular will use to set a header value on each request - we need to manually set this here // The validation cookie value generated by the anti-forgery helper that we validate the header token against - set above in GetAndStoreTokens - httpContext.Response.Cookies.Append( - Constants.Web.AngularCookieName, - set.RequestToken, - new CookieOptions - { - Path = "/", - //must be js readable - HttpOnly = false, - Secure = _globalSettings.UseHttps - }); + httpContext.Response.Cookies.Append(Constants.Web.AngularCookieName, set.RequestToken, _angularCookieBuilder.Build(httpContext)); } }