Files
Umbraco-CMS/src/Umbraco.Cms.Api.Management/Security/BackOfficeSecureDataFormat.cs

78 lines
2.8 KiB
C#

using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Management.Security;
/// <summary>
/// Custom secure format that ensures the Identity in the ticket is verified <see cref="ClaimsIdentity" />
/// </summary>
internal sealed class BackOfficeSecureDataFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly TimeSpan _loginTimeout;
private readonly ISecureDataFormat<AuthenticationTicket> _ticketDataFormat;
public BackOfficeSecureDataFormat(TimeSpan loginTimeout, ISecureDataFormat<AuthenticationTicket> ticketDataFormat)
{
_loginTimeout = loginTimeout;
_ticketDataFormat = ticketDataFormat ?? throw new ArgumentNullException(nameof(ticketDataFormat));
}
public string Protect(AuthenticationTicket data, string? purpose)
{
// create a new ticket based on the passed in tickets details, however, we'll adjust the expires utc based on the specified timeout mins
var ticket = new AuthenticationTicket(
data.Principal,
new AuthenticationProperties(data.Properties.Items)
{
IssuedUtc = data.Properties.IssuedUtc,
ExpiresUtc = data.Properties.ExpiresUtc ?? DateTimeOffset.UtcNow.Add(_loginTimeout),
AllowRefresh = data.Properties.AllowRefresh,
IsPersistent = data.Properties.IsPersistent,
RedirectUri = data.Properties.RedirectUri
},
data.AuthenticationScheme);
return _ticketDataFormat.Protect(ticket);
}
public string Protect(AuthenticationTicket data) => Protect(data, string.Empty);
public AuthenticationTicket? Unprotect(string? protectedText) => Unprotect(protectedText, string.Empty);
/// <summary>
/// Un-protects the cookie
/// </summary>
/// <param name="protectedText"></param>
/// <param name="purpose"></param>
/// <returns></returns>
public AuthenticationTicket? Unprotect(string? protectedText, string? purpose)
{
AuthenticationTicket? decrypt;
try
{
decrypt = _ticketDataFormat.Unprotect(protectedText);
if (decrypt == null)
{
return null;
}
}
catch (Exception)
{
return null;
}
var identity = (ClaimsIdentity?)decrypt.Principal.Identity;
if (identity is null || !identity.VerifyBackOfficeIdentity(out ClaimsIdentity? verifiedIdentity))
{
return null;
}
//return the ticket with a UmbracoBackOfficeIdentity
var ticket = new AuthenticationTicket(new ClaimsPrincipal(verifiedIdentity), decrypt.Properties, decrypt.AuthenticationScheme);
return ticket;
}
}