157 lines
4.0 KiB
C#
157 lines
4.0 KiB
C#
using ZB.MOM.WW.Auth.ApiKeys;
|
|
|
|
namespace ZB.MOM.WW.Auth.ApiKeys.Tests;
|
|
|
|
public class ApiKeyParserTests
|
|
{
|
|
// --- basic happy path ---
|
|
|
|
[Fact]
|
|
public void TryParse_SimpleToken_ReturnsParsedKey()
|
|
{
|
|
var result = ApiKeyParser.TryParse("mxgw_alice_SECRET", "mxgw");
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal("alice", result.KeyId);
|
|
Assert.Equal("SECRET", result.Secret);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_BearerPrefixCaseInsensitive_ReturnsParsedKey()
|
|
{
|
|
var result = ApiKeyParser.TryParse("Bearer mxgw_alice_SEC_RET", "mxgw");
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal("alice", result.KeyId);
|
|
Assert.Equal("SEC_RET", result.Secret);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_BearerLowercase_ReturnsParsedKey()
|
|
{
|
|
var result = ApiKeyParser.TryParse("bearer mxgw_alice_SECRET", "mxgw");
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal("alice", result.KeyId);
|
|
Assert.Equal("SECRET", result.Secret);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_SecretContainsUnderscores_SecretIsEverythingAfterFirstSplit()
|
|
{
|
|
var result = ApiKeyParser.TryParse("mxgw_k1_a_b_c", "mxgw");
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal("k1", result.KeyId);
|
|
Assert.Equal("a_b_c", result.Secret);
|
|
}
|
|
|
|
// --- custom prefix ---
|
|
|
|
[Fact]
|
|
public void TryParse_CustomPrefix_Works()
|
|
{
|
|
var result = ApiKeyParser.TryParse("myapp_user42_s3cr3t", "myapp");
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal("user42", result.KeyId);
|
|
Assert.Equal("s3cr3t", result.Secret);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_CustomPrefix_WithBearer()
|
|
{
|
|
var result = ApiKeyParser.TryParse("Bearer myapp_user42_s3cr3t", "myapp");
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal("user42", result.KeyId);
|
|
Assert.Equal("s3cr3t", result.Secret);
|
|
}
|
|
|
|
// --- rejection cases ---
|
|
|
|
[Fact]
|
|
public void TryParse_WrongPrefix_ReturnsNull()
|
|
{
|
|
var result = ApiKeyParser.TryParse("zzz_a_b", "mxgw");
|
|
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_NoDelimiters_ReturnsNull()
|
|
{
|
|
var result = ApiKeyParser.TryParse("nodelims", "mxgw");
|
|
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_NullInput_ReturnsNull()
|
|
{
|
|
var result = ApiKeyParser.TryParse(null, "mxgw");
|
|
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_EmptyInput_ReturnsNull()
|
|
{
|
|
var result = ApiKeyParser.TryParse("", "mxgw");
|
|
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_WhitespaceInput_ReturnsNull()
|
|
{
|
|
var result = ApiKeyParser.TryParse(" ", "mxgw");
|
|
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_OnlyPrefix_NoKeyIdOrSecret_ReturnsNull()
|
|
{
|
|
// "mxgw_" — prefix present but no key id segment
|
|
var result = ApiKeyParser.TryParse("mxgw_", "mxgw");
|
|
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_PrefixAndKeyIdButNoSecret_ReturnsNull()
|
|
{
|
|
// "mxgw_alice" — no second underscore after key id
|
|
var result = ApiKeyParser.TryParse("mxgw_alice", "mxgw");
|
|
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_PrefixAndUnderscoreButEmptySecret_ReturnsNull()
|
|
{
|
|
// "mxgw_alice_" — secret is empty
|
|
var result = ApiKeyParser.TryParse("mxgw_alice_", "mxgw");
|
|
|
|
Assert.Null(result);
|
|
}
|
|
|
|
// --- generator↔parser round-trip ---
|
|
|
|
[Fact]
|
|
public void TryParse_RealGeneratedSecret_RoundTripsKeyIdAndFullSecret()
|
|
{
|
|
// ApiKeySecretGenerator produces URL-safe base64 which may contain '_'.
|
|
// The parser must preserve the full secret even when it contains underscores.
|
|
string secret = ApiKeySecretGenerator.NewSecret();
|
|
string token = $"mxgw_someid_{secret}";
|
|
|
|
var result = ApiKeyParser.TryParse(token, "mxgw");
|
|
|
|
Assert.NotNull(result);
|
|
Assert.Equal("someid", result!.KeyId);
|
|
Assert.Equal(secret, result.Secret);
|
|
}
|
|
}
|