feat(auth): cut MxGateway API keys over to ZB.MOM.WW.Auth.ApiKeys 0.1.2; keep constraint enforcement+gRPC+CLI on top (Task 1.3)
This commit is contained in:
+19
-12
@@ -1,9 +1,13 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZB.MOM.WW.Auth.Abstractions.ApiKeys;
|
||||
using ZB.MOM.WW.MxGateway.Server.Configuration;
|
||||
using ZB.MOM.WW.MxGateway.Server.Security.Authentication;
|
||||
|
||||
// The mapped identity is the gateway's constraint-bearing type; disambiguate from the library's.
|
||||
using ApiKeyIdentity = ZB.MOM.WW.MxGateway.Server.Security.Authentication.ApiKeyIdentity;
|
||||
|
||||
namespace ZB.MOM.WW.MxGateway.Tests.Security.Authentication;
|
||||
|
||||
public sealed class ApiKeyAdminCliRunnerTests : IDisposable
|
||||
@@ -33,14 +37,14 @@ public sealed class ApiKeyAdminCliRunnerTests : IDisposable
|
||||
string apiKey = ReadApiKey(output.ToString());
|
||||
|
||||
IApiKeyVerifier verifier = services.GetRequiredService<IApiKeyVerifier>();
|
||||
ApiKeyVerificationResult verification = await verifier.VerifyAsync($"Bearer {apiKey}", CancellationToken.None);
|
||||
ApiKeyVerification verification = await verifier.VerifyAsync($"Bearer {apiKey}", CancellationToken.None);
|
||||
|
||||
Assert.True(verification.Succeeded);
|
||||
Assert.NotNull(verification.Identity);
|
||||
Assert.Equal("operator01", verification.Identity.KeyId);
|
||||
Assert.Contains("session:open", verification.Identity.Scopes);
|
||||
|
||||
IReadOnlyList<ApiKeyAuditRecord> auditRecords = await services
|
||||
IReadOnlyList<ApiKeyAuditEntry> auditRecords = await services
|
||||
.GetRequiredService<IApiKeyAuditStore>()
|
||||
.ListRecentAsync(10, CancellationToken.None);
|
||||
|
||||
@@ -98,14 +102,14 @@ public sealed class ApiKeyAdminCliRunnerTests : IDisposable
|
||||
TextWriter.Null,
|
||||
CancellationToken.None);
|
||||
|
||||
ApiKeyVerificationResult verification = await services
|
||||
ApiKeyVerification verification = await services
|
||||
.GetRequiredService<IApiKeyVerifier>()
|
||||
.VerifyAsync($"Bearer {apiKey}", CancellationToken.None);
|
||||
|
||||
Assert.False(verification.Succeeded);
|
||||
Assert.Equal(ApiKeyVerificationFailure.KeyRevoked, verification.Failure);
|
||||
Assert.Equal(ApiKeyFailure.KeyRevoked, verification.Failure);
|
||||
|
||||
IReadOnlyList<ApiKeyAuditRecord> auditRecords = await services
|
||||
IReadOnlyList<ApiKeyAuditEntry> auditRecords = await services
|
||||
.GetRequiredService<IApiKeyAuditStore>()
|
||||
.ListRecentAsync(10, CancellationToken.None);
|
||||
|
||||
@@ -141,11 +145,11 @@ public sealed class ApiKeyAdminCliRunnerTests : IDisposable
|
||||
Assert.Equal(1, CountOccurrences(rotateJson, newApiKey));
|
||||
|
||||
IApiKeyVerifier verifier = services.GetRequiredService<IApiKeyVerifier>();
|
||||
ApiKeyVerificationResult oldVerification = await verifier.VerifyAsync($"Bearer {oldApiKey}", CancellationToken.None);
|
||||
ApiKeyVerificationResult newVerification = await verifier.VerifyAsync($"Bearer {newApiKey}", CancellationToken.None);
|
||||
ApiKeyVerification oldVerification = await verifier.VerifyAsync($"Bearer {oldApiKey}", CancellationToken.None);
|
||||
ApiKeyVerification newVerification = await verifier.VerifyAsync($"Bearer {newApiKey}", CancellationToken.None);
|
||||
|
||||
Assert.False(oldVerification.Succeeded);
|
||||
Assert.Equal(ApiKeyVerificationFailure.SecretMismatch, oldVerification.Failure);
|
||||
Assert.Equal(ApiKeyFailure.SecretMismatch, oldVerification.Failure);
|
||||
Assert.True(newVerification.Succeeded);
|
||||
}
|
||||
|
||||
@@ -203,13 +207,16 @@ public sealed class ApiKeyAdminCliRunnerTests : IDisposable
|
||||
CancellationToken.None);
|
||||
|
||||
string apiKey = ReadApiKey(output.ToString());
|
||||
ApiKeyVerificationResult verification = await services
|
||||
ApiKeyVerification verification = await services
|
||||
.GetRequiredService<IApiKeyVerifier>()
|
||||
.VerifyAsync($"Bearer {apiKey}", CancellationToken.None);
|
||||
|
||||
Assert.True(verification.Succeeded);
|
||||
Assert.Equal(["Area1/*"], verification.Identity!.EffectiveConstraints.BrowseSubtrees);
|
||||
Assert.True(verification.Identity.EffectiveConstraints.ReadAlarmOnly);
|
||||
// The shared verifier returns the opaque constraints JSON; map it to the gateway identity so
|
||||
// the strongly-typed effective constraints round-trip can be asserted.
|
||||
ApiKeyIdentity gatewayIdentity = GatewayApiKeyIdentityMapper.ToGatewayIdentity(verification.Identity!);
|
||||
Assert.Equal(["Area1/*"], gatewayIdentity.EffectiveConstraints.BrowseSubtrees);
|
||||
Assert.True(gatewayIdentity.EffectiveConstraints.ReadAlarmOnly);
|
||||
}
|
||||
|
||||
|
||||
@@ -246,7 +253,7 @@ public sealed class ApiKeyAdminCliRunnerTests : IDisposable
|
||||
ServiceCollection services = new();
|
||||
services.AddSingleton<IConfiguration>(configuration);
|
||||
services.AddGatewayConfiguration(configuration);
|
||||
services.AddSqliteAuthStore();
|
||||
services.AddSqliteAuthStore(configuration);
|
||||
|
||||
return services.BuildServiceProvider(validateScopes: true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user