using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Management.Security;
///
/// Custom secure format that ensures the Identity in the ticket is verified
///
internal sealed class BackOfficeSecureDataFormat : ISecureDataFormat
{
private readonly TimeSpan _loginTimeout;
private readonly ISecureDataFormat _ticketDataFormat;
public BackOfficeSecureDataFormat(TimeSpan loginTimeout, ISecureDataFormat 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);
///
/// Un-protects the cookie
///
///
///
///
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;
}
}