Files
Umbraco-CMS/src/Umbraco.Web.Common/Middleware/PreviewAuthenticationMiddleware.cs
Bjarke Berg 11e5257b56 V14: Untangle the preview functionality from the auth cookie (#16308)
* AB40660 - untangle the preview cookie from the auth cookie

* Clean up

* Allow anonymous to end preview sessions

* Some refinements

* update OpenApi.json

* Fix enter preview test

* correct tests to match new expectations of the preview cookie

* sync preview tests with correct expectations of access level

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2024-05-17 16:06:26 +02:00

84 lines
2.9 KiB
C#

using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Preview;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.Common.AspNetCore;
using Umbraco.Cms.Web.Common.Security;
using Umbraco.Extensions;
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;
private readonly IPreviewTokenGenerator _previewTokenGenerator;
private readonly IPreviewService _previewService;
public PreviewAuthenticationMiddleware(
ILogger<PreviewAuthenticationMiddleware> logger,
IPreviewTokenGenerator previewTokenGenerator,
IPreviewService previewService)
{
_logger = logger;
_previewTokenGenerator = previewTokenGenerator;
_previewService = previewService;
}
/// <inheritdoc />
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
HttpRequest request = context.Request;
// do not process if client-side request
if (request.IsClientSideRequest())
{
await next(context);
return;
}
try
{
var isPreview = request.HasPreviewCookie()
&& !request.IsBackOfficeRequest();
if (isPreview)
{
Attempt<ClaimsIdentity> backOfficeIdentityAttempt = await _previewService.TryGetPreviewClaimsIdentityAsync();
if (backOfficeIdentityAttempt.Success)
{
// 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(backOfficeIdentityAttempt.Result!);
}
else
{
_logger.LogDebug("Could not transform previewCookie value into a claimsIdentity");
}
}
}
catch (Exception ex)
{
// log any errors and continue the request without preview
_logger.LogError("Unable to perform preview authentication: {message}", ex.Message);
}
finally
{
await next(context);
}
}
}