feat: Initialize Zastava Webhook service with TLS and Authority authentication
- Added Program.cs to set up the web application with Serilog for logging, health check endpoints, and a placeholder admission endpoint. - Configured Kestrel server to use TLS 1.3 and handle client certificates appropriately. - Created StellaOps.Zastava.Webhook.csproj with necessary dependencies including Serilog and Polly. - Documented tasks in TASKS.md for the Zastava Webhook project, outlining current work and exit criteria for each task.
This commit is contained in:
		
							
								
								
									
										77
									
								
								src/StellaOps.Auth.Security/Dpop/DpopValidationOptions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/StellaOps.Auth.Security/Dpop/DpopValidationOptions.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| using System.Collections.Immutable; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace StellaOps.Auth.Security.Dpop; | ||||
|  | ||||
| /// <summary> | ||||
| /// Configures acceptable algorithms and replay windows for DPoP proof validation. | ||||
| /// </summary> | ||||
| public sealed class DpopValidationOptions | ||||
| { | ||||
|     private readonly HashSet<string> allowedAlgorithms = new(StringComparer.Ordinal); | ||||
|  | ||||
|     public DpopValidationOptions() | ||||
|     { | ||||
|         allowedAlgorithms.Add("ES256"); | ||||
|         allowedAlgorithms.Add("ES384"); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Maximum age a proof is considered valid relative to <see cref="IssuedAt"/>. | ||||
|     /// </summary> | ||||
|     public TimeSpan ProofLifetime { get; set; } = TimeSpan.FromMinutes(2); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Allowed clock skew when evaluating <c>iat</c>. | ||||
|     /// </summary> | ||||
|     public TimeSpan AllowedClockSkew { get; set; } = TimeSpan.FromSeconds(30); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Duration a successfully validated proof is tracked to prevent replay. | ||||
|     /// </summary> | ||||
|     public TimeSpan ReplayWindow { get; set; } = TimeSpan.FromMinutes(5); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Algorithms (JWA) permitted for DPoP proofs. | ||||
|     /// </summary> | ||||
|     public ISet<string> AllowedAlgorithms => allowedAlgorithms; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Normalised, upper-case representation of allowed algorithms. | ||||
|     /// </summary> | ||||
|     public IReadOnlySet<string> NormalizedAlgorithms { get; private set; } = ImmutableHashSet<string>.Empty; | ||||
|  | ||||
|     public void Validate() | ||||
|     { | ||||
|         if (ProofLifetime <= TimeSpan.Zero) | ||||
|         { | ||||
|             throw new InvalidOperationException("DPoP proof lifetime must be greater than zero."); | ||||
|         } | ||||
|  | ||||
|         if (AllowedClockSkew < TimeSpan.Zero || AllowedClockSkew > TimeSpan.FromMinutes(5)) | ||||
|         { | ||||
|             throw new InvalidOperationException("DPoP allowed clock skew must be between 0 seconds and 5 minutes."); | ||||
|         } | ||||
|  | ||||
|         if (ReplayWindow < TimeSpan.Zero) | ||||
|         { | ||||
|             throw new InvalidOperationException("DPoP replay window must be greater than or equal to zero."); | ||||
|         } | ||||
|  | ||||
|         if (allowedAlgorithms.Count == 0) | ||||
|         { | ||||
|             throw new InvalidOperationException("At least one allowed DPoP algorithm must be configured."); | ||||
|         } | ||||
|  | ||||
|         NormalizedAlgorithms = allowedAlgorithms | ||||
|             .Select(static algorithm => algorithm.Trim().ToUpperInvariant()) | ||||
|             .Where(static algorithm => algorithm.Length > 0) | ||||
|             .ToImmutableHashSet(StringComparer.Ordinal); | ||||
|  | ||||
|         if (NormalizedAlgorithms.Count == 0) | ||||
|         { | ||||
|             throw new InvalidOperationException("Allowed DPoP algorithms cannot be empty after normalization."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user