Move preview authorization middleware to fix preview

This commit is contained in:
Kenn Jacobsen
2021-02-19 11:45:58 +01:00
parent bf41c2eeaa
commit 6c7316afcd
5 changed files with 36 additions and 22 deletions

View File

@@ -75,7 +75,6 @@ namespace Umbraco.Extensions
builder.Services.ConfigureOptions<ConfigureBackOfficeCookieOptions>();
builder.Services.AddUnique<PreviewAuthenticationMiddleware>();
builder.Services.AddUnique<BackOfficeExternalLoginProviderErrorMiddleware>();
builder.Services.AddUnique<IBackOfficeAntiforgery, BackOfficeAntiforgery>();

View File

@@ -44,9 +44,6 @@ namespace Umbraco.Extensions
public static IApplicationBuilder UseUmbracoPreview(this IApplicationBuilder app)
{
// TODO: I'm unsure this middleware will execute before the endpoint, we'll have to see
app.UseMiddleware<PreviewAuthenticationMiddleware>();
app.UseEndpoints(endpoints =>
{
PreviewRoutes previewRoutes = app.ApplicationServices.GetRequiredService<PreviewRoutes>();

View File

@@ -272,6 +272,7 @@ namespace Umbraco.Extensions
builder.Services.AddUnique<InstallAreaRoutes>();
builder.Services.AddUnique<UmbracoRequestLoggingMiddleware>();
builder.Services.AddUnique<PreviewAuthenticationMiddleware>();
builder.Services.AddUnique<UmbracoRequestMiddleware>();
builder.Services.AddUnique<BootFailedMiddleware>();

View File

@@ -125,6 +125,7 @@ namespace Umbraco.Extensions
}
else
{
app.UseMiddleware<PreviewAuthenticationMiddleware>();
app.UseMiddleware<UmbracoRequestMiddleware>();
app.UseMiddleware<MiniProfilerMiddleware>();
}

View File

@@ -3,35 +3,47 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Extensions;
using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Web.BackOffice.Middleware
namespace Umbraco.Cms.Web.Common.Middleware
{
/// <summary>
/// Ensures that preview pages (front-end routed) are authenticated with the back office identity appended to the principal alongside any default authentication that takes place
/// </summary>
public class PreviewAuthenticationMiddleware : IMiddleware
{
private readonly ILogger<PreviewAuthenticationMiddleware> _logger;
public PreviewAuthenticationMiddleware(ILogger<PreviewAuthenticationMiddleware> logger) => _logger = logger;
/// <inheritdoc/>
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var request = context.Request;
if (!request.IsClientSideRequest())
// do not process if client-side request
if (request.IsClientSideRequest())
{
await next(context);
return;
}
try
{
var isPreview = request.HasPreviewCookie()
&& context.User != null
&& !request.IsBackOfficeRequest();
&& context.User != null
&& !request.IsBackOfficeRequest();
if (isPreview)
{
var cookieOptions = context.RequestServices.GetRequiredService<IOptionsSnapshot<CookieAuthenticationOptions>>()
.Get(Constants.Security.BackOfficeAuthenticationType);
.Get(Core.Constants.Security.BackOfficeAuthenticationType);
if (cookieOptions == null)
{
throw new InvalidOperationException("No cookie options found with name " + Constants.Security.BackOfficeAuthenticationType);
throw new InvalidOperationException("No cookie options found with name " + Core.Constants.Security.BackOfficeAuthenticationType);
}
// If we've gotten this far it means a preview cookie has been set and a front-end umbraco document request is executing.
@@ -40,23 +52,27 @@ namespace Umbraco.Cms.Web.BackOffice.Middleware
if (request.Cookies.TryGetValue(cookieOptions.Cookie.Name, out var cookie))
{
var unprotected = cookieOptions.TicketDataFormat.Unprotect(cookie);
if (unprotected != null)
var backOfficeIdentity = unprotected?.Principal.GetUmbracoIdentity();
if (backOfficeIdentity != null)
{
var backOfficeIdentity = unprotected.Principal.GetUmbracoIdentity();
if (backOfficeIdentity != null)
{
// Ok, we've got a real ticket, now we can add this ticket's identity to the current
// Principal, this means we'll have 2 identities assigned to the principal which we can
// use to authorize the preview and allow for a back office User.
context.User.AddIdentity(backOfficeIdentity);
}
// Ok, we've got a real ticket, now we can add this ticket's identity to the current
// Principal, this means we'll have 2 identities assigned to the principal which we can
// use to authorize the preview and allow for a back office User.
context.User.AddIdentity(backOfficeIdentity);
}
}
}
}
await next(context);
catch (Exception ex)
{
// log any errors and continue the request without preview
_logger.LogError($"Unable to perform preview authentication: {ex.Message}");
}
finally
{
await next(context);
}
}
}
}