using System.Linq; using System.Security.Claims; using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; namespace EnvelopeGenerator.API.Extensions; /// /// Provides helper methods for working with envelope-specific authentication claims. /// public static class ReceiverClaimExtensions { private static string GetRequiredClaimOfReceiver(this ClaimsPrincipal user, string claimType) { var value = user.FindFirstValue(claimType); if (value is not null) { return value; } var identity = user.Identity; var principalName = identity?.Name ?? "(anonymous)"; var authType = identity?.AuthenticationType ?? "(none)"; var availableClaims = string.Join(", ", user.Claims.Select(c => $"{c.Type}={c.Value}")); var message = $"Required claim '{claimType}' is missing for user '{principalName}' (auth: {authType}). Available claims: [{availableClaims}]."; throw new InvalidOperationException(message); } /// /// Gets the authenticated envelope UUID from the claims. /// public static string GetEnvelopeUuidOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.NameIdentifier); /// /// Gets the authenticated receiver signature from the claims. /// public static string GetReceiverSignatureOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.Hash); /// /// Gets the authenticated receiver display name from the claims. /// public static string GetReceiverNameOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.Name); /// /// Gets the authenticated receiver email address from the claims. /// public static string GetReceiverMailOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.Email); /// /// Gets the authenticated envelope title from the claims. /// public static string GetEnvelopeTitleOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(EnvelopeClaimTypes.Title); /// /// Gets the authenticated envelope identifier from the claims. /// public static int GetEnvelopeIdOfReceiver(this ClaimsPrincipal user) { var envIdStr = user.GetRequiredClaimOfReceiver(EnvelopeClaimTypes.Id); if (!int.TryParse(envIdStr, out var envId)) { throw new InvalidOperationException($"Claim '{EnvelopeClaimTypes.Id}' is not a valid integer."); } return envId; } /// /// Signs in an envelope receiver using cookie authentication and attaches envelope claims. /// /// The current HTTP context. /// Envelope receiver DTO to extract claims from. /// Role to attach to the authentication ticket. public static async Task SignInEnvelopeAsync(this HttpContext context, EnvelopeReceiverDto envelopeReceiver, string receiverRole) { var claims = new List { new(ClaimTypes.NameIdentifier, envelopeReceiver.Envelope!.Uuid), new(ClaimTypes.Hash, envelopeReceiver.Receiver!.Signature), new(ClaimTypes.Name, envelopeReceiver.Name ?? string.Empty), new(ClaimTypes.Email, envelopeReceiver.Receiver.EmailAddress), new(EnvelopeClaimTypes.Title, envelopeReceiver.Envelope.Title), new(EnvelopeClaimTypes.Id, envelopeReceiver.Envelope.Id.ToString()), new(ClaimTypes.Role, receiverRole) }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var authProperties = new AuthenticationProperties { AllowRefresh = false, IsPersistent = false }; await context.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties); } }