fix(mesh): Batch B review fixes — bounded store read, cache poison guard, test hardening
This commit is contained in:
@@ -43,6 +43,12 @@ namespace ZB.MOM.WW.OtOpcUa.Host.Configuration;
|
||||
/// unavoidably observable and are not sensitive.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Header reads go through <see cref="GrpcRequestHeaders"/>, shared with
|
||||
/// <see cref="CentralCommandAuthInterceptor"/> — the two are clones, and header parsing is
|
||||
/// the one place a clone pair can diverge into two different answers about which of several
|
||||
/// <c>authorization</c> headers counts.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Exactly one public constructor.</b> <c>Grpc.AspNetCore</c> silently stops invoking an
|
||||
/// interceptor that has more than one public ctor — see
|
||||
/// <c>MeshCommandAuthInterceptorTests.HasExactlyOnePublicConstructor</c>.
|
||||
@@ -51,8 +57,6 @@ namespace ZB.MOM.WW.OtOpcUa.Host.Configuration;
|
||||
public sealed class MeshCommandAuthInterceptor : Interceptor
|
||||
{
|
||||
private const string ServicePrefix = "/mesh_transport.v1.NodeCommandService/";
|
||||
private const string AuthorizationHeader = "authorization";
|
||||
private const string BearerPrefix = "Bearer ";
|
||||
|
||||
private readonly IOptions<MeshTransportOptions> _options;
|
||||
private readonly ILogger<MeshCommandAuthInterceptor> _logger;
|
||||
@@ -137,7 +141,7 @@ public sealed class MeshCommandAuthInterceptor : Interceptor
|
||||
"Node command service is not accepting calls: no pre-shared key is configured on this node."));
|
||||
}
|
||||
|
||||
var presented = ExtractBearerToken(context.RequestHeaders);
|
||||
var presented = GrpcRequestHeaders.BearerToken(context.RequestHeaders);
|
||||
if (presented is null || !FixedTimeEquals(presented, expected))
|
||||
{
|
||||
_logger.LogWarning(
|
||||
@@ -150,23 +154,6 @@ public sealed class MeshCommandAuthInterceptor : Interceptor
|
||||
}
|
||||
}
|
||||
|
||||
private static string? ExtractBearerToken(Metadata headers)
|
||||
{
|
||||
// gRPC lowercases header keys on the wire; compare case-insensitively anyway so a hand-built
|
||||
// Metadata in a test behaves the same as a real request.
|
||||
foreach (var entry in headers)
|
||||
{
|
||||
if (!string.Equals(entry.Key, AuthorizationHeader, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
var value = entry.Value;
|
||||
if (value is not null && value.StartsWith(BearerPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
return value[BearerPrefix.Length..];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool FixedTimeEquals(string presented, string expected)
|
||||
=> CryptographicOperations.FixedTimeEquals(
|
||||
Encoding.UTF8.GetBytes(presented), Encoding.UTF8.GetBytes(expected));
|
||||
|
||||
Reference in New Issue
Block a user