Refactor `ReceiverClaimExtensions` to support multiple claim type variations by introducing arrays for envelope ID, UUID, and receiver signature claim types. Updated the `GetRequiredClaimOfReceiver` method to handle multiple claim types and provide detailed error messages when claims are missing. Refactored methods to use the new claim type arrays for improved flexibility and robustness.
122 lines
5.4 KiB
C#
122 lines
5.4 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// Provides helper methods for working with envelope-specific authentication claims.
|
|
/// </summary>
|
|
public static class ReceiverClaimExtensions
|
|
{
|
|
private static readonly string[] EnvelopeIdClaimTypes = [EnvelopeClaimTypes.Id, "envelope_id", "EnvelopeId"];
|
|
private static readonly string[] EnvelopeUuidClaimTypes = [ClaimTypes.NameIdentifier, "envelope_uuid", "EnvelopeUuid"];
|
|
private static readonly string[] ReceiverSignatureClaimTypes = [ClaimTypes.Hash, "receiver_sig", "ReceiverSignature"];
|
|
|
|
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);
|
|
}
|
|
|
|
private static string GetRequiredClaimOfReceiver(this ClaimsPrincipal user, params string[] claimTypes)
|
|
{
|
|
foreach (var claimType in claimTypes.Where(t => !string.IsNullOrWhiteSpace(t)).Distinct())
|
|
{
|
|
var value = user.FindFirstValue(claimType);
|
|
if (!string.IsNullOrWhiteSpace(value))
|
|
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(s) '{string.Join("', '", claimTypes)}' are missing for user '{principalName}' (auth: {authType}). Available claims: [{availableClaims}].";
|
|
throw new InvalidOperationException(message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the authenticated envelope UUID from the claims.
|
|
/// </summary>
|
|
public static string GetEnvelopeUuidOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(EnvelopeUuidClaimTypes);
|
|
|
|
/// <summary>
|
|
/// Gets the authenticated receiver signature from the claims.
|
|
/// </summary>
|
|
public static string GetReceiverSignatureOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ReceiverSignatureClaimTypes);
|
|
|
|
/// <summary>
|
|
/// Gets the authenticated receiver display name from the claims.
|
|
/// </summary>
|
|
public static string GetReceiverNameOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.Name);
|
|
|
|
/// <summary>
|
|
/// Gets the authenticated receiver email address from the claims.
|
|
/// </summary>
|
|
public static string GetReceiverMailOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(ClaimTypes.Email);
|
|
|
|
/// <summary>
|
|
/// Gets the authenticated envelope title from the claims.
|
|
/// </summary>
|
|
public static string GetEnvelopeTitleOfReceiver(this ClaimsPrincipal user) => user.GetRequiredClaimOfReceiver(EnvelopeClaimTypes.Title);
|
|
|
|
/// <summary>
|
|
/// Gets the authenticated envelope identifier from the claims.
|
|
/// </summary>
|
|
public static int GetEnvelopeIdOfReceiver(this ClaimsPrincipal user)
|
|
{
|
|
var envIdStr = user.GetRequiredClaimOfReceiver(EnvelopeIdClaimTypes);
|
|
if (!int.TryParse(envIdStr, out var envId))
|
|
{
|
|
throw new InvalidOperationException($"Claim '{EnvelopeClaimTypes.Id}' is not a valid integer.");
|
|
}
|
|
|
|
return envId;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Signs in an envelope receiver using cookie authentication and attaches envelope claims.
|
|
/// </summary>
|
|
/// <param name="context">The current HTTP context.</param>
|
|
/// <param name="envelopeReceiver">Envelope receiver DTO to extract claims from.</param>
|
|
/// <param name="receiverRole">Role to attach to the authentication ticket.</param>
|
|
public static async Task SignInEnvelopeAsync(this HttpContext context, EnvelopeReceiverDto envelopeReceiver, string receiverRole)
|
|
{
|
|
var claims = new List<Claim>
|
|
{
|
|
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);
|
|
}
|
|
} |