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; } }