perf(auth): allocation-free token parsing; single partition-key build per RPC
This commit is contained in:
@@ -196,6 +196,55 @@ public sealed class CachingApiKeyVerifierTests
|
||||
Assert.Equal(2, inner.MarkUsedCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pins the header parse that arms the revoke-vs-in-flight generation guard. It runs on every
|
||||
/// cache miss and is written to allocate only the returned key id; these cases hold it to the
|
||||
/// rules the original <c>Split('_')</c> form applied. Note this parse is deliberately laxer than
|
||||
/// the interceptor's partition parse — it applies no key-id length cap and does not require a
|
||||
/// non-empty third segment — because a wrong <em>id</em> here would disarm the guard, whereas
|
||||
/// an over-long one merely fails to match any generation.
|
||||
/// </summary>
|
||||
/// <param name="authorizationHeader">The presented header value.</param>
|
||||
/// <param name="expected">The key id the parse must yield, or <see langword="null"/>.</param>
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData("", null)]
|
||||
[InlineData(" ", null)]
|
||||
[InlineData("Bearer", null)]
|
||||
[InlineData("Bearer ", null)]
|
||||
[InlineData("Bearer mxgw_operator01_super-secret", "operator01")]
|
||||
[InlineData("bearer mxgw_operator01_super-secret", "operator01")]
|
||||
[InlineData(" Bearer mxgw_operator01_super-secret ", "operator01")]
|
||||
[InlineData("mxgw_operator01_super-secret", "operator01")]
|
||||
[InlineData("Bearer mxgw_abc_sec_ret", "abc")]
|
||||
[InlineData("Bearer mxgw_a_b_c", "a")]
|
||||
|
||||
// Laxer than the interceptor: an empty or absent third segment still yields the key id.
|
||||
[InlineData("Bearer mxgw_abc_", "abc")]
|
||||
[InlineData("Bearer mxgw_abc__secret", "abc")]
|
||||
[InlineData("Bearer mxgw_abc", null)]
|
||||
[InlineData("Bearer mxgwabcsecret", null)]
|
||||
[InlineData("Bearer mxgw__secret", null)]
|
||||
[InlineData("Bearer _mxgw_abc_secret", null)]
|
||||
[InlineData("Bearer MXGW_abc_secret", null)]
|
||||
[InlineData("Bearer xmxgw_abc_secret", null)]
|
||||
[InlineData("Bearer mxgw", null)]
|
||||
[InlineData("Bearer mxgw_", null)]
|
||||
[InlineData("Bearer ___", null)]
|
||||
public void TryParseKeyId_MatchesTokenShapeRules(string? authorizationHeader, string? expected)
|
||||
{
|
||||
Assert.Equal(expected, CachingApiKeyVerifier.TryParseKeyId(authorizationHeader));
|
||||
}
|
||||
|
||||
/// <summary>The guard parse applies no key-id length cap: an over-long id is still returned whole.</summary>
|
||||
[Fact]
|
||||
public void TryParseKeyId_LongKeyId_ReturnedWhole()
|
||||
{
|
||||
string keyId = new('a', 65);
|
||||
|
||||
Assert.Equal(keyId, CachingApiKeyVerifier.TryParseKeyId($"Bearer mxgw_{keyId}_secret"));
|
||||
}
|
||||
|
||||
private static MemoryCache NewCache() => new(new MemoryCacheOptions());
|
||||
|
||||
private static ApiKeyVerification Success(string keyId) => new(
|
||||
|
||||
Reference in New Issue
Block a user