Add support for ГОСТ Р 34.10 digital signatures
- Implemented the GostKeyValue class for handling public key parameters in ГОСТ Р 34.10 digital signatures. - Created the GostSignedXml class to manage XML signatures using ГОСТ 34.10, including methods for computing and checking signatures. - Developed the GostSignedXmlImpl class to encapsulate the signature computation logic and public key retrieval. - Added specific key value classes for ГОСТ Р 34.10-2001, ГОСТ Р 34.10-2012/256, and ГОСТ Р 34.10-2012/512 to support different signature algorithms. - Ensured compatibility with existing XML signature standards while integrating ГОСТ cryptography.
This commit is contained in:
@@ -104,6 +104,16 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
string? backfillTicketClaim = null;
|
||||
string? backfillFailureReason = null;
|
||||
|
||||
var packApprovalRequired = combinedScopes.Contains(StellaOpsScopes.PacksApprove);
|
||||
var packApprovalMetadataSatisfied = true;
|
||||
var packFreshAuthSatisfied = true;
|
||||
string? packRunIdClaim = null;
|
||||
string? packGateIdClaim = null;
|
||||
string? packPlanHashClaim = null;
|
||||
DateTimeOffset? packAuthTime = null;
|
||||
string? packMetadataFailureReason = null;
|
||||
string? packFreshAuthFailureReason = null;
|
||||
|
||||
if (principalAuthenticated)
|
||||
{
|
||||
incidentReasonClaim = principal!.FindFirstValue(StellaOpsClaimTypes.IncidentReason);
|
||||
@@ -111,6 +121,12 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
backfillTicketClaim = principal!.FindFirstValue(StellaOpsClaimTypes.BackfillTicket);
|
||||
backfillReasonClaim = backfillReasonClaim?.Trim();
|
||||
backfillTicketClaim = backfillTicketClaim?.Trim();
|
||||
if (packApprovalRequired)
|
||||
{
|
||||
packRunIdClaim = NormalizePackClaim(principal!.FindFirstValue(StellaOpsClaimTypes.PackRunId));
|
||||
packGateIdClaim = NormalizePackClaim(principal!.FindFirstValue(StellaOpsClaimTypes.PackGateId));
|
||||
packPlanHashClaim = NormalizePackClaim(principal!.FindFirstValue(StellaOpsClaimTypes.PackPlanHash));
|
||||
}
|
||||
}
|
||||
|
||||
if (principalAuthenticated && allScopesSatisfied)
|
||||
@@ -137,6 +153,35 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
}
|
||||
}
|
||||
|
||||
if (principalAuthenticated && tenantAllowed && allScopesSatisfied && packApprovalRequired)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(packRunIdClaim))
|
||||
{
|
||||
packApprovalMetadataSatisfied = false;
|
||||
packMetadataFailureReason = "packs.approve tokens require pack_run_id claim.";
|
||||
LogPackApprovalValidationFailure(principal!, packMetadataFailureReason);
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(packGateIdClaim))
|
||||
{
|
||||
packApprovalMetadataSatisfied = false;
|
||||
packMetadataFailureReason = "packs.approve tokens require pack_gate_id claim.";
|
||||
LogPackApprovalValidationFailure(principal!, packMetadataFailureReason);
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(packPlanHashClaim))
|
||||
{
|
||||
packApprovalMetadataSatisfied = false;
|
||||
packMetadataFailureReason = "packs.approve tokens require pack_plan_hash claim.";
|
||||
LogPackApprovalValidationFailure(principal!, packMetadataFailureReason);
|
||||
}
|
||||
else
|
||||
{
|
||||
packFreshAuthSatisfied = ValidatePackApprovalFreshAuthentication(
|
||||
principal!,
|
||||
out packAuthTime,
|
||||
out packFreshAuthFailureReason);
|
||||
}
|
||||
}
|
||||
|
||||
var bypassed = false;
|
||||
|
||||
if ((!principalAuthenticated || !allScopesSatisfied || !tenantAllowed || !incidentFreshAuthSatisfied) &&
|
||||
@@ -153,10 +198,21 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
incidentAuthTime = null;
|
||||
backfillMetadataSatisfied = true;
|
||||
backfillFailureReason = null;
|
||||
packApprovalMetadataSatisfied = true;
|
||||
packMetadataFailureReason = null;
|
||||
packFreshAuthSatisfied = true;
|
||||
packFreshAuthFailureReason = null;
|
||||
packAuthTime = null;
|
||||
bypassed = true;
|
||||
}
|
||||
|
||||
if (tenantAllowed && allScopesSatisfied && incidentFreshAuthSatisfied && backfillMetadataSatisfied)
|
||||
var requirementsSatisfied = tenantAllowed &&
|
||||
allScopesSatisfied &&
|
||||
incidentFreshAuthSatisfied &&
|
||||
backfillMetadataSatisfied &&
|
||||
(!packApprovalRequired || (packApprovalMetadataSatisfied && packFreshAuthSatisfied));
|
||||
|
||||
if (requirementsSatisfied)
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
@@ -210,9 +266,30 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
!string.IsNullOrWhiteSpace(backfillTicketClaim),
|
||||
httpContext?.Connection.RemoteIpAddress);
|
||||
}
|
||||
|
||||
if (packApprovalRequired && !packApprovalMetadataSatisfied)
|
||||
{
|
||||
logger.LogDebug(
|
||||
"Pack approval metadata requirement not satisfied. RunPresent={RunPresent}; GatePresent={GatePresent}; PlanPresent={PlanPresent}; Remote={Remote}",
|
||||
!string.IsNullOrWhiteSpace(packRunIdClaim),
|
||||
!string.IsNullOrWhiteSpace(packGateIdClaim),
|
||||
!string.IsNullOrWhiteSpace(packPlanHashClaim),
|
||||
httpContext?.Connection.RemoteIpAddress);
|
||||
}
|
||||
|
||||
if (packApprovalRequired && packApprovalMetadataSatisfied && !packFreshAuthSatisfied)
|
||||
{
|
||||
var authTimeText = packAuthTime?.ToString("o", CultureInfo.InvariantCulture) ?? "(unknown)";
|
||||
logger.LogDebug(
|
||||
"Pack approval fresh-auth requirement not satisfied. AuthTime={AuthTime}; Window={Window}; Remote={Remote}",
|
||||
authTimeText,
|
||||
PackApprovalFreshAuthWindow,
|
||||
httpContext?.Connection.RemoteIpAddress);
|
||||
}
|
||||
}
|
||||
|
||||
var reason = backfillFailureReason ?? incidentFailureReason ?? DetermineFailureReason(
|
||||
var packFailureReason = packMetadataFailureReason ?? packFreshAuthFailureReason;
|
||||
var reason = packFailureReason ?? backfillFailureReason ?? incidentFailureReason ?? DetermineFailureReason(
|
||||
principalAuthenticated,
|
||||
allScopesSatisfied,
|
||||
anyScopeMatched,
|
||||
@@ -231,7 +308,7 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
resourceOptions,
|
||||
normalizedTenant,
|
||||
missingScopes,
|
||||
tenantAllowed && allScopesSatisfied && incidentFreshAuthSatisfied && backfillMetadataSatisfied,
|
||||
requirementsSatisfied,
|
||||
bypassed,
|
||||
reason,
|
||||
principalAuthenticated,
|
||||
@@ -245,7 +322,13 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
backfillMetadataRequired,
|
||||
backfillMetadataSatisfied,
|
||||
backfillReasonClaim,
|
||||
backfillTicketClaim).ConfigureAwait(false);
|
||||
backfillTicketClaim,
|
||||
packApprovalRequired,
|
||||
packApprovalMetadataSatisfied,
|
||||
packFreshAuthSatisfied,
|
||||
packRunIdClaim,
|
||||
packGateIdClaim,
|
||||
packPlanHashClaim).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static string? DetermineFailureReason(
|
||||
@@ -280,6 +363,9 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string? NormalizePackClaim(string? value)
|
||||
=> string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
||||
|
||||
private static bool TenantAllowed(ClaimsPrincipal principal, StellaOpsResourceServerOptions options, out string? normalizedTenant)
|
||||
{
|
||||
normalizedTenant = null;
|
||||
@@ -330,7 +416,13 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
bool backfillMetadataRequired,
|
||||
bool backfillMetadataSatisfied,
|
||||
string? backfillReason,
|
||||
string? backfillTicket)
|
||||
string? backfillTicket,
|
||||
bool packApprovalRequired,
|
||||
bool packApprovalMetadataSatisfied,
|
||||
bool packFreshAuthSatisfied,
|
||||
string? packRunId,
|
||||
string? packGateId,
|
||||
string? packPlanHash)
|
||||
{
|
||||
if (!auditSinks.Any())
|
||||
{
|
||||
@@ -361,7 +453,13 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
backfillMetadataRequired,
|
||||
backfillMetadataSatisfied,
|
||||
backfillReason,
|
||||
backfillTicket);
|
||||
backfillTicket,
|
||||
packApprovalRequired,
|
||||
packApprovalMetadataSatisfied,
|
||||
packFreshAuthSatisfied,
|
||||
packRunId,
|
||||
packGateId,
|
||||
packPlanHash);
|
||||
|
||||
var cancellationToken = httpContext?.RequestAborted ?? CancellationToken.None;
|
||||
|
||||
@@ -398,7 +496,13 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
bool backfillMetadataRequired,
|
||||
bool backfillMetadataSatisfied,
|
||||
string? backfillReason,
|
||||
string? backfillTicket)
|
||||
string? backfillTicket,
|
||||
bool packApprovalRequired,
|
||||
bool packApprovalMetadataSatisfied,
|
||||
bool packFreshAuthSatisfied,
|
||||
string? packRunId,
|
||||
string? packGateId,
|
||||
string? packPlanHash)
|
||||
{
|
||||
var correlationId = ResolveCorrelationId(httpContext);
|
||||
var subject = BuildSubject(principal);
|
||||
@@ -422,7 +526,13 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
backfillMetadataRequired,
|
||||
backfillMetadataSatisfied,
|
||||
backfillReason,
|
||||
backfillTicket);
|
||||
backfillTicket,
|
||||
packApprovalRequired,
|
||||
packApprovalMetadataSatisfied,
|
||||
packFreshAuthSatisfied,
|
||||
packRunId,
|
||||
packGateId,
|
||||
packPlanHash);
|
||||
|
||||
return new AuthEventRecord
|
||||
{
|
||||
@@ -456,7 +566,13 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
bool backfillMetadataRequired,
|
||||
bool backfillMetadataSatisfied,
|
||||
string? backfillReason,
|
||||
string? backfillTicket)
|
||||
string? backfillTicket,
|
||||
bool packApprovalRequired,
|
||||
bool packApprovalMetadataSatisfied,
|
||||
bool packFreshAuthSatisfied,
|
||||
string? packRunId,
|
||||
string? packGateId,
|
||||
string? packPlanHash)
|
||||
{
|
||||
var properties = new List<AuthEventProperty>();
|
||||
|
||||
@@ -587,6 +703,48 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
}
|
||||
}
|
||||
|
||||
if (packApprovalRequired)
|
||||
{
|
||||
properties.Add(new AuthEventProperty
|
||||
{
|
||||
Name = "pack.approval_metadata_satisfied",
|
||||
Value = ClassifiedString.Public(packApprovalMetadataSatisfied ? "true" : "false")
|
||||
});
|
||||
|
||||
properties.Add(new AuthEventProperty
|
||||
{
|
||||
Name = "pack.fresh_auth_satisfied",
|
||||
Value = ClassifiedString.Public(packFreshAuthSatisfied ? "true" : "false")
|
||||
});
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(packRunId))
|
||||
{
|
||||
properties.Add(new AuthEventProperty
|
||||
{
|
||||
Name = "pack.run_id",
|
||||
Value = ClassifiedString.Sensitive(packRunId!)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(packGateId))
|
||||
{
|
||||
properties.Add(new AuthEventProperty
|
||||
{
|
||||
Name = "pack.gate_id",
|
||||
Value = ClassifiedString.Sensitive(packGateId!)
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(packPlanHash))
|
||||
{
|
||||
properties.Add(new AuthEventProperty
|
||||
{
|
||||
Name = "pack.plan_hash",
|
||||
Value = ClassifiedString.Sensitive(packPlanHash!)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
@@ -638,6 +796,45 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ValidatePackApprovalFreshAuthentication(
|
||||
ClaimsPrincipal principal,
|
||||
out DateTimeOffset? authenticationTime,
|
||||
out string? failureReason)
|
||||
{
|
||||
authenticationTime = null;
|
||||
|
||||
var authTimeClaim = principal.FindFirstValue(OpenIddictConstants.Claims.AuthenticationTime);
|
||||
if (string.IsNullOrWhiteSpace(authTimeClaim) ||
|
||||
!long.TryParse(authTimeClaim, NumberStyles.Integer, CultureInfo.InvariantCulture, out var authTimeSeconds))
|
||||
{
|
||||
failureReason = "packs.approve tokens require authentication_time claim.";
|
||||
LogPackApprovalValidationFailure(principal, failureReason);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
authenticationTime = DateTimeOffset.FromUnixTimeSeconds(authTimeSeconds);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
failureReason = "packs.approve tokens contain an invalid authentication_time value.";
|
||||
LogPackApprovalValidationFailure(principal, failureReason);
|
||||
return false;
|
||||
}
|
||||
|
||||
var now = timeProvider.GetUtcNow();
|
||||
if (now - authenticationTime > PackApprovalFreshAuthWindow)
|
||||
{
|
||||
failureReason = "packs.approve tokens require fresh authentication.";
|
||||
LogPackApprovalValidationFailure(principal, failureReason, authenticationTime);
|
||||
return false;
|
||||
}
|
||||
|
||||
failureReason = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void LogIncidentValidationFailure(
|
||||
ClaimsPrincipal principal,
|
||||
string message,
|
||||
@@ -666,6 +863,43 @@ internal sealed class StellaOpsScopeAuthorizationHandler : AuthorizationHandler<
|
||||
}
|
||||
}
|
||||
|
||||
private void LogPackApprovalValidationFailure(
|
||||
ClaimsPrincipal principal,
|
||||
string message,
|
||||
DateTimeOffset? authenticationTime = null)
|
||||
{
|
||||
var clientId = principal.FindFirstValue(StellaOpsClaimTypes.ClientId) ?? "<unknown>";
|
||||
var subject = principal.FindFirstValue(StellaOpsClaimTypes.Subject) ?? "<unknown>";
|
||||
var runId = principal.FindFirstValue(StellaOpsClaimTypes.PackRunId) ?? "<none>";
|
||||
var gateId = principal.FindFirstValue(StellaOpsClaimTypes.PackGateId) ?? "<none>";
|
||||
var planHash = principal.FindFirstValue(StellaOpsClaimTypes.PackPlanHash) ?? "<none>";
|
||||
|
||||
if (authenticationTime.HasValue)
|
||||
{
|
||||
logger.LogWarning(
|
||||
"{Message} ClientId={ClientId}; Subject={Subject}; PackRunId={PackRunId}; PackGateId={PackGateId}; PackPlanHash={PackPlanHash}; AuthTime={AuthTime:o}; Window={Window}",
|
||||
message,
|
||||
clientId,
|
||||
subject,
|
||||
runId,
|
||||
gateId,
|
||||
planHash,
|
||||
authenticationTime.Value,
|
||||
PackApprovalFreshAuthWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning(
|
||||
"{Message} ClientId={ClientId}; Subject={Subject}; PackRunId={PackRunId}; PackGateId={PackGateId}; PackPlanHash={PackPlanHash}",
|
||||
message,
|
||||
clientId,
|
||||
subject,
|
||||
runId,
|
||||
gateId,
|
||||
planHash);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolveCorrelationId(HttpContext? httpContext)
|
||||
{
|
||||
if (Activity.Current is { TraceId: var traceId } && traceId != default)
|
||||
|
||||
Reference in New Issue
Block a user