diff --git a/src/Tgstation.Server.Host/Security/ITokenFactory.cs b/src/Tgstation.Server.Host/Security/ITokenFactory.cs index 0dbb4a959d..707c5d78ff 100644 --- a/src/Tgstation.Server.Host/Security/ITokenFactory.cs +++ b/src/Tgstation.Server.Host/Security/ITokenFactory.cs @@ -12,9 +12,9 @@ namespace Tgstation.Server.Host.Security public interface ITokenFactory { /// - /// Gets or sets the 's signing key. + /// Gets or sets the 's signing key s. /// - ReadOnlySpan SigningKey { get; set; } + ReadOnlySpan SigningKeyBytes { get; set; } /// /// The for the . diff --git a/src/Tgstation.Server.Host/Security/TokenFactory.cs b/src/Tgstation.Server.Host/Security/TokenFactory.cs index b579c20faa..d2ab3c0527 100644 --- a/src/Tgstation.Server.Host/Security/TokenFactory.cs +++ b/src/Tgstation.Server.Host/Security/TokenFactory.cs @@ -20,49 +20,49 @@ namespace Tgstation.Server.Host.Security sealed class TokenFactory : ITokenFactory { /// - public TokenValidationParameters ValidationParameters { get; private set; } + public TokenValidationParameters ValidationParameters { get; } /// - public ReadOnlySpan SigningKey + public ReadOnlySpan SigningKeyBytes { - get => signingKey; + get => signingKey.Key; + [MemberNotNull(nameof(signingKey))] + [MemberNotNull(nameof(tokenHeader))] set { - signingKey = value.ToArray(); - SetValidationParameters(); + signingKey = new SymmetricSecurityKey(value.ToArray()); + tokenHeader = new JwtHeader( + new SigningCredentials( + signingKey, + SecurityAlgorithms.HmacSha256)); } } - /// - /// The for the . - /// - readonly IAssemblyInformationProvider assemblyInformationProvider; - /// /// The for the . /// readonly SecurityConfiguration securityConfiguration; - /// - /// The for generating tokens. - /// - readonly JwtHeader tokenHeader; - /// /// The used to generate s. /// readonly JwtSecurityTokenHandler tokenHandler; /// - /// Backing field for . + /// Backing field for . /// - byte[] signingKey; + SymmetricSecurityKey signingKey; + + /// + /// The for generating tokens. + /// + JwtHeader tokenHeader; /// /// Initializes a new instance of the class. /// /// The used for generating the . - /// The value of . + /// The used to generate the issuer name. /// The containing the value of . public TokenFactory( ICryptographySuite cryptographySuite, @@ -70,20 +70,33 @@ namespace Tgstation.Server.Host.Security IOptions securityConfigurationOptions) { ArgumentNullException.ThrowIfNull(cryptographySuite); + ArgumentNullException.ThrowIfNull(assemblyInformationProvider); - this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); securityConfiguration = securityConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(securityConfigurationOptions)); - signingKey = String.IsNullOrWhiteSpace(securityConfiguration.CustomTokenSigningKeyBase64) + SigningKeyBytes = String.IsNullOrWhiteSpace(securityConfiguration.CustomTokenSigningKeyBase64) ? cryptographySuite.GetSecureBytes(securityConfiguration.TokenSigningKeyByteCount) : Convert.FromBase64String(securityConfiguration.CustomTokenSigningKeyBase64); - SetValidationParameters(); + ValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKeyResolver = (_, _, _, _) => Enumerable.Repeat(signingKey, 1), + + ValidateIssuer = true, + ValidIssuer = assemblyInformationProvider.AssemblyName.Name, + + ValidateLifetime = true, + ValidateAudience = true, + ValidAudience = typeof(TokenResponse).Assembly.GetName().Name, + + ClockSkew = TimeSpan.FromMinutes(securityConfiguration.TokenClockSkewMinutes), + + RequireSignedTokens = true, + + RequireExpirationTime = true, + }; - tokenHeader = new JwtHeader( - new SigningCredentials( - ValidationParameters.IssuerSigningKey, - SecurityAlgorithms.HmacSha256)); tokenHandler = new JwtSecurityTokenHandler(); } @@ -133,29 +146,5 @@ namespace Tgstation.Server.Host.Security return tokenResponse; } - - /// - /// Initializes based on fields. - /// - [MemberNotNull(nameof(ValidationParameters))] - void SetValidationParameters() - => ValidationParameters = new TokenValidationParameters - { - ValidateIssuerSigningKey = true, - IssuerSigningKey = new SymmetricSecurityKey(signingKey), - - ValidateIssuer = true, - ValidIssuer = assemblyInformationProvider.AssemblyName.Name, - - ValidateLifetime = true, - ValidateAudience = true, - ValidAudience = typeof(TokenResponse).Assembly.GetName().Name, - - ClockSkew = TimeSpan.FromMinutes(securityConfiguration.TokenClockSkewMinutes), - - RequireSignedTokens = true, - - RequireExpirationTime = true, - }; } } diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index 82b2a9140d..9884ac7193 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -574,7 +574,7 @@ namespace Tgstation.Server.Host.Swarm SwarmRegistrationResponse CreateResponse() => new() { - TokenSigningKeyBase64 = Convert.ToBase64String(tokenFactory.SigningKey), + TokenSigningKeyBase64 = Convert.ToBase64String(tokenFactory.SigningKeyBytes), }; var registrationIdsAndTimes = this.registrationIdsAndTimes!; @@ -1320,7 +1320,7 @@ namespace Tgstation.Server.Host.Swarm return SwarmRegistrationResult.PayloadFailure; } - tokenFactory.SigningKey = Convert.FromBase64String(registrationResponse.TokenSigningKeyBase64); + tokenFactory.SigningKeyBytes = Convert.FromBase64String(registrationResponse.TokenSigningKeyBase64); } catch (Exception ex) { diff --git a/tests/Tgstation.Server.Host.Tests/Swarm/TestableSwarmNode.cs b/tests/Tgstation.Server.Host.Tests/Swarm/TestableSwarmNode.cs index 664729e966..2fbc888b1b 100644 --- a/tests/Tgstation.Server.Host.Tests/Swarm/TestableSwarmNode.cs +++ b/tests/Tgstation.Server.Host.Tests/Swarm/TestableSwarmNode.cs @@ -79,7 +79,7 @@ namespace Tgstation.Server.Host.Swarm.Tests private class MockTokenFactory : ITokenFactory { - public ReadOnlySpan SigningKey + public ReadOnlySpan SigningKeyBytes { get => [0, 1, 2, 3, 4]; set