Files
Musify/backend/Hosts/Musify.StreamingGateway/Authentication/TicketValidator.cs
T
Admin c4cf5af7f1 Make the Worker validate its service container and align Worker and Gateway hosts
The Worker now registers the Application layer, observability and stream tickets, validates the
container on build and ships a complete appsettings. The Gateway drops underscore fields and uses a
placeholder bucket in its default YARP transform.
2026-09-24 12:40:18 +02:00

61 lines
2.1 KiB
C#

using System.Security.Cryptography;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;
using Musify.StreamingGateway.Configuration;
namespace Musify.StreamingGateway.Authentication;
public sealed record TicketValidationResult(string Prefix, long? MaxBytes)
{
public static readonly TicketValidationResult Invalid = new(string.Empty, null);
public bool IsValid => Prefix.Length > 0;
}
public sealed class TicketValidator : IDisposable
{
private readonly RSA rsa;
private readonly TokenValidationParameters validationParameters;
private readonly JsonWebTokenHandler handler = new();
public TicketValidator(StreamTicketValidationConfiguration configuration)
{
rsa = RSA.Create();
rsa.ImportFromPem(File.ReadAllText(configuration.PublicKeyPath));
validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = configuration.Issuer,
ValidateAudience = true,
ValidAudience = configuration.Audience,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new RsaSecurityKey(rsa),
ValidAlgorithms = [SecurityAlgorithms.RsaSha256],
ClockSkew = TimeSpan.FromSeconds(30),
};
}
public async Task<TicketValidationResult> ValidateTicketAsync(string? token)
{
if (string.IsNullOrWhiteSpace(token))
return TicketValidationResult.Invalid;
var result = await handler.ValidateTokenAsync(token, validationParameters);
if (!result.IsValid)
return TicketValidationResult.Invalid;
var prefix = result.ClaimsIdentity?.FindFirst("prefix")?.Value;
if (string.IsNullOrEmpty(prefix))
return TicketValidationResult.Invalid;
var maxBytesClaim = result.ClaimsIdentity?.FindFirst("maxBytes")?.Value;
var maxBytes = long.TryParse(maxBytesClaim, out var parsed) ? parsed : (long?)null;
return new TicketValidationResult(prefix, maxBytes);
}
public void Dispose() => rsa.Dispose();
}