Merge all changes
This commit is contained in:
@@ -65,35 +65,35 @@ public class AuthAbstractionsConstantsTests
|
||||
[nameof(StellaOpsClaimTypes.SessionId)] = "sid"
|
||||
};
|
||||
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.Subject)], StellaOpsClaimTypes.Subject);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.Tenant)], StellaOpsClaimTypes.Tenant);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.Project)], StellaOpsClaimTypes.Project);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.ClientId)], StellaOpsClaimTypes.ClientId);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.ServiceAccount)], StellaOpsClaimTypes.ServiceAccount);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.TokenId)], StellaOpsClaimTypes.TokenId);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.AuthenticationMethod)], StellaOpsClaimTypes.AuthenticationMethod);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.Scope)], StellaOpsClaimTypes.Scope);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.ScopeItem)], StellaOpsClaimTypes.ScopeItem);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.Audience)], StellaOpsClaimTypes.Audience);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.IdentityProvider)], StellaOpsClaimTypes.IdentityProvider);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.OperatorReason)], StellaOpsClaimTypes.OperatorReason);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.OperatorTicket)], StellaOpsClaimTypes.OperatorTicket);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.QuotaReason)], StellaOpsClaimTypes.QuotaReason);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.QuotaTicket)], StellaOpsClaimTypes.QuotaTicket);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.BackfillReason)], StellaOpsClaimTypes.BackfillReason);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.BackfillTicket)], StellaOpsClaimTypes.BackfillTicket);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.PolicyDigest)], StellaOpsClaimTypes.PolicyDigest);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.PolicyTicket)], StellaOpsClaimTypes.PolicyTicket);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.PolicyReason)], StellaOpsClaimTypes.PolicyReason);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.PackRunId)], StellaOpsClaimTypes.PackRunId);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.PackGateId)], StellaOpsClaimTypes.PackGateId);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.PackPlanHash)], StellaOpsClaimTypes.PackPlanHash);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.PolicyOperation)], StellaOpsClaimTypes.PolicyOperation);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.IncidentReason)], StellaOpsClaimTypes.IncidentReason);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.VulnerabilityEnvironment)], StellaOpsClaimTypes.VulnerabilityEnvironment);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.VulnerabilityOwner)], StellaOpsClaimTypes.VulnerabilityOwner);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.VulnerabilityBusinessTier)], StellaOpsClaimTypes.VulnerabilityBusinessTier);
|
||||
Assert.Equal(expected[nameof(StellaOpsClaimTypes.SessionId)], StellaOpsClaimTypes.SessionId);
|
||||
Assert.Equal(StellaOpsClaimTypes.Subject, expected[nameof(StellaOpsClaimTypes.Subject)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.Tenant, expected[nameof(StellaOpsClaimTypes.Tenant)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.Project, expected[nameof(StellaOpsClaimTypes.Project)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.ClientId, expected[nameof(StellaOpsClaimTypes.ClientId)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.ServiceAccount, expected[nameof(StellaOpsClaimTypes.ServiceAccount)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.TokenId, expected[nameof(StellaOpsClaimTypes.TokenId)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.AuthenticationMethod, expected[nameof(StellaOpsClaimTypes.AuthenticationMethod)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.Scope, expected[nameof(StellaOpsClaimTypes.Scope)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.ScopeItem, expected[nameof(StellaOpsClaimTypes.ScopeItem)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.Audience, expected[nameof(StellaOpsClaimTypes.Audience)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.IdentityProvider, expected[nameof(StellaOpsClaimTypes.IdentityProvider)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.OperatorReason, expected[nameof(StellaOpsClaimTypes.OperatorReason)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.OperatorTicket, expected[nameof(StellaOpsClaimTypes.OperatorTicket)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.QuotaReason, expected[nameof(StellaOpsClaimTypes.QuotaReason)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.QuotaTicket, expected[nameof(StellaOpsClaimTypes.QuotaTicket)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.BackfillReason, expected[nameof(StellaOpsClaimTypes.BackfillReason)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.BackfillTicket, expected[nameof(StellaOpsClaimTypes.BackfillTicket)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.PolicyDigest, expected[nameof(StellaOpsClaimTypes.PolicyDigest)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.PolicyTicket, expected[nameof(StellaOpsClaimTypes.PolicyTicket)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.PolicyReason, expected[nameof(StellaOpsClaimTypes.PolicyReason)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.PackRunId, expected[nameof(StellaOpsClaimTypes.PackRunId)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.PackGateId, expected[nameof(StellaOpsClaimTypes.PackGateId)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.PackPlanHash, expected[nameof(StellaOpsClaimTypes.PackPlanHash)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.PolicyOperation, expected[nameof(StellaOpsClaimTypes.PolicyOperation)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.IncidentReason, expected[nameof(StellaOpsClaimTypes.IncidentReason)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.VulnerabilityEnvironment, expected[nameof(StellaOpsClaimTypes.VulnerabilityEnvironment)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.VulnerabilityOwner, expected[nameof(StellaOpsClaimTypes.VulnerabilityOwner)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.VulnerabilityBusinessTier, expected[nameof(StellaOpsClaimTypes.VulnerabilityBusinessTier)]);
|
||||
Assert.Equal(StellaOpsClaimTypes.SessionId, expected[nameof(StellaOpsClaimTypes.SessionId)]);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
|
||||
@@ -72,7 +72,7 @@ public class ServiceCollectionExtensionsTests
|
||||
using var provider = services.BuildServiceProvider();
|
||||
|
||||
var cache = provider.GetRequiredService<StellaOpsDiscoveryCache>();
|
||||
var configuration = await cache.GetAsync(CancellationToken.None);
|
||||
var configuration = await cache.GetAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(new Uri("https://authority.test/connect/token"), configuration.TokenEndpoint);
|
||||
Assert.Equal(2, attemptCount);
|
||||
|
||||
@@ -47,12 +47,12 @@ public class StellaOpsDiscoveryCacheTests
|
||||
var monitor = new TestOptionsMonitor<StellaOpsAuthClientOptions>(options);
|
||||
var cache = new StellaOpsDiscoveryCache(httpClient, monitor, timeProvider, NullLogger<StellaOpsDiscoveryCache>.Instance);
|
||||
|
||||
var configuration = await cache.GetAsync(CancellationToken.None);
|
||||
var configuration = await cache.GetAsync(TestContext.Current.CancellationToken);
|
||||
Assert.Equal(new Uri("https://authority.test/connect/token"), configuration.TokenEndpoint);
|
||||
|
||||
timeProvider.Advance(TimeSpan.FromMinutes(1) + TimeSpan.FromSeconds(5));
|
||||
|
||||
configuration = await cache.GetAsync(CancellationToken.None);
|
||||
configuration = await cache.GetAsync(TestContext.Current.CancellationToken);
|
||||
Assert.Equal(new Uri("https://authority.test/connect/token"), configuration.TokenEndpoint);
|
||||
Assert.Equal(2, callCount);
|
||||
|
||||
@@ -66,7 +66,7 @@ public class StellaOpsDiscoveryCacheTests
|
||||
HttpRequestException? exception = null;
|
||||
try
|
||||
{
|
||||
await cache.GetAsync(CancellationToken.None);
|
||||
await cache.GetAsync(TestContext.Current.CancellationToken);
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
|
||||
@@ -52,12 +52,12 @@ public class StellaOpsJwksCacheTests
|
||||
var discoveryCache = new StellaOpsDiscoveryCache(discoveryClient, monitor, timeProvider, NullLogger<StellaOpsDiscoveryCache>.Instance);
|
||||
var jwksCache = new StellaOpsJwksCache(jwksClient, discoveryCache, monitor, timeProvider, NullLogger<StellaOpsJwksCache>.Instance);
|
||||
|
||||
var keys = await jwksCache.GetAsync(CancellationToken.None);
|
||||
var keys = await jwksCache.GetAsync(TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(keys);
|
||||
|
||||
timeProvider.Advance(TimeSpan.FromMinutes(1) + TimeSpan.FromSeconds(5));
|
||||
|
||||
keys = await jwksCache.GetAsync(CancellationToken.None);
|
||||
keys = await jwksCache.GetAsync(TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(keys);
|
||||
Assert.Equal(2, jwksCallCount);
|
||||
|
||||
@@ -68,7 +68,7 @@ public class StellaOpsJwksCacheTests
|
||||
|
||||
Assert.True(offlineExpiry < timeProvider.GetUtcNow());
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => jwksCache.GetAsync(CancellationToken.None));
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => jwksCache.GetAsync(TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
private static HttpResponseMessage CreateJsonResponse(string json)
|
||||
|
||||
@@ -38,7 +38,7 @@ public class StellaOpsAuthorityConfigurationManagerTests
|
||||
var initialMetadataRequests = handler.MetadataRequests;
|
||||
var initialJwksRequests = handler.JwksRequests;
|
||||
|
||||
var second = await manager.GetConfigurationAsync(CancellationToken.None);
|
||||
var second = await manager.GetConfigurationAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
// Cache must return same instance
|
||||
Assert.Same(first, second);
|
||||
@@ -70,11 +70,11 @@ public class StellaOpsAuthorityConfigurationManagerTests
|
||||
timeProvider,
|
||||
NullLogger<StellaOpsAuthorityConfigurationManager>.Instance);
|
||||
|
||||
var first = await manager.GetConfigurationAsync(CancellationToken.None);
|
||||
var first = await manager.GetConfigurationAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
timeProvider.Advance(TimeSpan.FromMinutes(2));
|
||||
|
||||
var second = await manager.GetConfigurationAsync(CancellationToken.None);
|
||||
var second = await manager.GetConfigurationAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Same(first, second);
|
||||
Assert.Equal(2, handler.MetadataRequests);
|
||||
@@ -100,12 +100,12 @@ public class StellaOpsAuthorityConfigurationManagerTests
|
||||
timeProvider,
|
||||
NullLogger<StellaOpsAuthorityConfigurationManager>.Instance);
|
||||
|
||||
await manager.GetConfigurationAsync(CancellationToken.None);
|
||||
await manager.GetConfigurationAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
var updated = CreateOptions("https://authority2.test");
|
||||
optionsMonitor.Set(updated);
|
||||
|
||||
await manager.GetConfigurationAsync(CancellationToken.None);
|
||||
await manager.GetConfigurationAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(2, handler.MetadataRequests);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ public sealed class InMemoryLdapClaimsCacheTests
|
||||
["displayName"] = "Alice Example"
|
||||
});
|
||||
|
||||
await cache.SetAsync("uid=alice,ou=people,dc=example,dc=internal", claims, CancellationToken.None);
|
||||
var fetched = await cache.GetAsync("uid=alice,ou=people,dc=example,dc=internal", CancellationToken.None);
|
||||
await cache.SetAsync("uid=alice,ou=people,dc=example,dc=internal", claims, TestContext.Current.CancellationToken);
|
||||
var fetched = await cache.GetAsync("uid=alice,ou=people,dc=example,dc=internal", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.NotNull(fetched);
|
||||
Assert.Contains("operators", fetched!.Roles);
|
||||
@@ -35,10 +35,10 @@ public sealed class InMemoryLdapClaimsCacheTests
|
||||
var timeProvider = new TestTimeProvider(new DateTimeOffset(2025, 11, 9, 6, 0, 0, TimeSpan.Zero));
|
||||
var cache = CreateCache(enabled: true, ttlSeconds: 60, timeProvider: timeProvider);
|
||||
|
||||
await cache.SetAsync("uid=expired,ou=people,dc=example,dc=internal", new LdapCachedClaims(Array.Empty<string>(), new Dictionary<string, string>()), CancellationToken.None);
|
||||
await cache.SetAsync("uid=expired,ou=people,dc=example,dc=internal", new LdapCachedClaims(Array.Empty<string>(), new Dictionary<string, string>()), TestContext.Current.CancellationToken);
|
||||
|
||||
timeProvider.Advance(TimeSpan.FromMinutes(5));
|
||||
var fetched = await cache.GetAsync("uid=expired,ou=people,dc=example,dc=internal", CancellationToken.None);
|
||||
var fetched = await cache.GetAsync("uid=expired,ou=people,dc=example,dc=internal", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Null(fetched);
|
||||
}
|
||||
@@ -48,11 +48,11 @@ public sealed class InMemoryLdapClaimsCacheTests
|
||||
{
|
||||
var cache = CreateCache(enabled: true, ttlSeconds: 600, maxEntries: 1);
|
||||
|
||||
await cache.SetAsync("uid=first,ou=people,dc=example,dc=internal", new LdapCachedClaims(Array.Empty<string>(), new Dictionary<string, string>()), CancellationToken.None);
|
||||
await cache.SetAsync("uid=second,ou=people,dc=example,dc=internal", new LdapCachedClaims(Array.Empty<string>(), new Dictionary<string, string>()), CancellationToken.None);
|
||||
await cache.SetAsync("uid=first,ou=people,dc=example,dc=internal", new LdapCachedClaims(Array.Empty<string>(), new Dictionary<string, string>()), TestContext.Current.CancellationToken);
|
||||
await cache.SetAsync("uid=second,ou=people,dc=example,dc=internal", new LdapCachedClaims(Array.Empty<string>(), new Dictionary<string, string>()), TestContext.Current.CancellationToken);
|
||||
|
||||
var first = await cache.GetAsync("uid=first,ou=people,dc=example,dc=internal", CancellationToken.None);
|
||||
var second = await cache.GetAsync("uid=second,ou=people,dc=example,dc=internal", CancellationToken.None);
|
||||
var first = await cache.GetAsync("uid=first,ou=people,dc=example,dc=internal", TestContext.Current.CancellationToken);
|
||||
var second = await cache.GetAsync("uid=second,ou=people,dc=example,dc=internal", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Null(first);
|
||||
Assert.NotNull(second);
|
||||
|
||||
@@ -41,7 +41,7 @@ public class LdapClaimsEnricherTests
|
||||
var identity = new ClaimsIdentity();
|
||||
var context = CreateContext("uid=j.doe,ou=people,dc=example,dc=internal");
|
||||
|
||||
await enricher.EnrichAsync(identity, context, CancellationToken.None);
|
||||
await enricher.EnrichAsync(identity, context, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Contains(identity.Claims, claim => claim.Type == ClaimTypes.Role && claim.Value == "operators");
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public class LdapClaimsEnricherTests
|
||||
var identity = new ClaimsIdentity();
|
||||
var context = CreateContext("uid=ops,ou=people,dc=example,dc=internal");
|
||||
|
||||
await enricher.EnrichAsync(identity, context, CancellationToken.None);
|
||||
await enricher.EnrichAsync(identity, context, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Contains(identity.Claims, claim => claim.Type == ClaimTypes.Role && claim.Value == "incident");
|
||||
}
|
||||
@@ -107,7 +107,7 @@ public class LdapClaimsEnricherTests
|
||||
var identity = new ClaimsIdentity();
|
||||
var context = CreateContext("uid=alice,ou=people,dc=example,dc=internal");
|
||||
|
||||
await enricher.EnrichAsync(identity, context, CancellationToken.None);
|
||||
await enricher.EnrichAsync(identity, context, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Contains(identity.Claims, claim => claim.Type == "displayName" && claim.Value == "Alice Example");
|
||||
Assert.Contains(identity.Claims, claim => claim.Type == "email" && claim.Value == "alice@example.test");
|
||||
@@ -134,11 +134,11 @@ public class LdapClaimsEnricherTests
|
||||
var identity = new ClaimsIdentity();
|
||||
var context = CreateContext("uid=cached,ou=people,dc=example,dc=internal");
|
||||
|
||||
await enricher.EnrichAsync(identity, context, CancellationToken.None);
|
||||
await enricher.EnrichAsync(identity, context, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Contains(identity.Claims, claim => claim.Type == ClaimTypes.Role && claim.Value == "operators");
|
||||
Assert.Contains(identity.Claims, claim => claim.Type == "displayName" && claim.Value == "Cached User");
|
||||
Assert.Equal(0, connection.Operations.Count);
|
||||
Assert.Empty(connection.Operations);
|
||||
Assert.Equal(0, cache.SetCount);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ public class LdapCapabilityProbeTests
|
||||
checkClientProvisioning: true,
|
||||
checkBootstrap: true,
|
||||
options.CapabilityProbe.Timeout,
|
||||
CancellationToken.None);
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(snapshot.ClientProvisioningWritable);
|
||||
Assert.True(snapshot.BootstrapWritable);
|
||||
@@ -47,7 +47,7 @@ public class LdapCapabilityProbeTests
|
||||
checkClientProvisioning: true,
|
||||
checkBootstrap: true,
|
||||
options.CapabilityProbe.Timeout,
|
||||
CancellationToken.None);
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.False(snapshot.ClientProvisioningWritable);
|
||||
Assert.False(snapshot.BootstrapWritable);
|
||||
|
||||
@@ -49,7 +49,7 @@ public sealed class LdapClientProvisioningStoreTests
|
||||
allowedScopes: new[] { "signer.sign" },
|
||||
allowedAudiences: new[] { "signer" });
|
||||
|
||||
var result = await store.CreateOrUpdateAsync(registration, CancellationToken.None);
|
||||
var result = await store.CreateOrUpdateAsync(registration, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(result.Succeeded);
|
||||
Assert.True(clientStore.Documents.ContainsKey("svc-bootstrap"));
|
||||
@@ -88,7 +88,7 @@ public sealed class LdapClientProvisioningStoreTests
|
||||
SecretHash = "hash"
|
||||
};
|
||||
|
||||
var result = await store.DeleteAsync("svc-bootstrap", CancellationToken.None);
|
||||
var result = await store.DeleteAsync("svc-bootstrap", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(result.Succeeded);
|
||||
Assert.DoesNotContain("svc-bootstrap", clientStore.Documents.Keys);
|
||||
@@ -124,7 +124,7 @@ public sealed class LdapClientProvisioningStoreTests
|
||||
allowedGrantTypes: new[] { "client_credentials" },
|
||||
allowedScopes: new[] { "signer.sign" });
|
||||
|
||||
var result = await store.CreateOrUpdateAsync(registration, CancellationToken.None);
|
||||
var result = await store.CreateOrUpdateAsync(registration, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Equal("disabled", result.ErrorCode);
|
||||
|
||||
@@ -44,7 +44,7 @@ public class LdapCredentialStoreTests
|
||||
monitor,
|
||||
new FakeLdapConnectionFactory(connection));
|
||||
|
||||
var result = await store.VerifyPasswordAsync("J.Doe", "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("J.Doe", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(result.Succeeded);
|
||||
Assert.Equal(2, bindCalls.Count);
|
||||
@@ -86,7 +86,7 @@ public class LdapCredentialStoreTests
|
||||
monitor,
|
||||
new FakeLdapConnectionFactory(connection));
|
||||
|
||||
var result = await store.VerifyPasswordAsync("J.Doe", "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("J.Doe", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(result.Succeeded);
|
||||
Assert.NotNull(result.User);
|
||||
@@ -119,7 +119,7 @@ public class LdapCredentialStoreTests
|
||||
new FakeLdapConnectionFactory(connection),
|
||||
delayAsync: (_, _) => Task.CompletedTask);
|
||||
|
||||
var result = await store.VerifyPasswordAsync("jdoe", "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("jdoe", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(result.Succeeded);
|
||||
Assert.Equal(2, attempts);
|
||||
@@ -142,7 +142,7 @@ public class LdapCredentialStoreTests
|
||||
new FakeLdapConnectionFactory(connection),
|
||||
delayAsync: (_, _) => Task.CompletedTask);
|
||||
|
||||
var result = await store.VerifyPasswordAsync("jdoe", "bad", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("jdoe", "bad", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Equal(AuthorityCredentialFailureCode.InvalidCredentials, result.FailureCode);
|
||||
@@ -176,7 +176,7 @@ public class LdapCredentialStoreTests
|
||||
monitor,
|
||||
new FakeLdapConnectionFactory(connection));
|
||||
|
||||
var result = await store.FindBySubjectAsync("uid=j.doe,ou=people,dc=example,dc=internal", CancellationToken.None);
|
||||
var result = await store.FindBySubjectAsync("uid=j.doe,ou=people,dc=example,dc=internal", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("uid=j.doe,ou=people,dc=example,dc=internal", result!.SubjectId);
|
||||
@@ -201,7 +201,7 @@ public class LdapCredentialStoreTests
|
||||
email: "bootstrap@example.internal",
|
||||
requirePasswordReset: true);
|
||||
|
||||
var result = await store.UpsertUserAsync(registration, CancellationToken.None);
|
||||
var result = await store.UpsertUserAsync(registration, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(result.Succeeded);
|
||||
Assert.Contains(connection.Operations, op => op.StartsWith("add:uid=bootstrap.user", StringComparison.OrdinalIgnoreCase));
|
||||
@@ -234,7 +234,7 @@ public class LdapCredentialStoreTests
|
||||
email: "bootstrap@example.internal",
|
||||
requirePasswordReset: false);
|
||||
|
||||
var result = await store.UpsertUserAsync(registration, CancellationToken.None);
|
||||
var result = await store.UpsertUserAsync(registration, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(result.Succeeded);
|
||||
Assert.Contains(connection.Operations, op => op.StartsWith("modify:uid=bootstrap.user", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
@@ -61,7 +61,7 @@ public sealed class LdapConnectorResilienceTests
|
||||
var store = CreateStore(options, connection);
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("noname", "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("noname", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeTrue("Missing displayName should not prevent authentication");
|
||||
@@ -88,7 +88,7 @@ public sealed class LdapConnectorResilienceTests
|
||||
var store = CreateStore(options, connection);
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("nomail", "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("nomail", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeTrue("Missing mail should not prevent authentication");
|
||||
@@ -113,7 +113,7 @@ public sealed class LdapConnectorResilienceTests
|
||||
var store = CreateStore(options, connection);
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("nogroups", "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("nogroups", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeTrue("Empty memberOf should not prevent authentication");
|
||||
@@ -135,7 +135,7 @@ public sealed class LdapConnectorResilienceTests
|
||||
var store = CreateStore(options, connection);
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("nonexistent", "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("nonexistent", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeFalse("Nonexistent user should fail authentication");
|
||||
@@ -177,7 +177,7 @@ public sealed class LdapConnectorResilienceTests
|
||||
var store = CreateStore(options, new FakeLdapConnectionFactory(connection));
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("user", "WrongPassword!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("user", "WrongPassword!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeFalse("Wrong password should fail authentication");
|
||||
@@ -200,7 +200,7 @@ public sealed class LdapConnectorResilienceTests
|
||||
var store = CreateStore(options, connection);
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("malformed", "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("malformed", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert - should handle gracefully (either succeed with warning or fail cleanly)
|
||||
// The exact behavior depends on implementation
|
||||
@@ -225,7 +225,7 @@ public sealed class LdapConnectorResilienceTests
|
||||
var store = CreateStore(options, new FakeLdapConnectionFactory(connection));
|
||||
|
||||
// Act
|
||||
Func<Task> act = async () => await store.VerifyPasswordAsync("user", "Password1!", CancellationToken.None);
|
||||
Func<Task> act = async () => await store.VerifyPasswordAsync("user", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
await act.Should().ThrowAsync<TimeoutException>();
|
||||
@@ -247,7 +247,7 @@ public sealed class LdapConnectorResilienceTests
|
||||
var store = CreateStore(options, new FakeLdapConnectionFactory(connection));
|
||||
|
||||
// Act
|
||||
Func<Task> act = async () => await store.VerifyPasswordAsync("user", "Password1!", CancellationToken.None);
|
||||
Func<Task> act = async () => await store.VerifyPasswordAsync("user", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
await act.Should().ThrowAsync<InvalidOperationException>();
|
||||
@@ -303,7 +303,7 @@ public sealed class LdapConnectorResilienceTests
|
||||
var store = CreateStore(options, connection);
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("münchen-user", "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("münchen-user", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeTrue("Unicode username should be handled");
|
||||
@@ -329,7 +329,7 @@ public sealed class LdapConnectorResilienceTests
|
||||
var store = CreateStore(options, connection);
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("user+test", "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("user+test", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeTrue("Special characters in DN should be handled");
|
||||
|
||||
@@ -69,7 +69,7 @@ public sealed class LdapConnectorSecurityTests
|
||||
var store = CreateStore(options, new FakeLdapConnectionFactory(connection));
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync(maliciousUsername, "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync(maliciousUsername, "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeFalse("Injection attempt should fail");
|
||||
@@ -103,7 +103,7 @@ public sealed class LdapConnectorSecurityTests
|
||||
var store = CreateStore(options, new FakeLdapConnectionFactory(connection));
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync(emptyUsername, "Password1!", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync(emptyUsername, "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeFalse("Empty username should be rejected");
|
||||
@@ -120,7 +120,7 @@ public sealed class LdapConnectorSecurityTests
|
||||
var store = CreateStore(options, new FakeLdapConnectionFactory(connection));
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("user", null!, CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("user", null!, TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeFalse("Null password should be rejected");
|
||||
@@ -137,7 +137,7 @@ public sealed class LdapConnectorSecurityTests
|
||||
var store = CreateStore(options, new FakeLdapConnectionFactory(connection));
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("user", "", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("user", "", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.Succeeded.Should().BeFalse("Empty password should be rejected");
|
||||
@@ -169,7 +169,7 @@ public sealed class LdapConnectorSecurityTests
|
||||
var store = CreateStore(options, new FakeLdapConnectionFactory(connection));
|
||||
|
||||
// Act
|
||||
Func<Task> act = async () => await store.VerifyPasswordAsync("user", "Password1!", CancellationToken.None);
|
||||
Func<Task> act = async () => await store.VerifyPasswordAsync("user", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
await act.Should().ThrowAsync<InvalidOperationException>();
|
||||
@@ -201,7 +201,7 @@ public sealed class LdapConnectorSecurityTests
|
||||
var store = CreateStore(options, new FakeLdapConnectionFactory(connection));
|
||||
|
||||
// Act
|
||||
await store.VerifyPasswordAsync("targetuser", "Password1!", CancellationToken.None);
|
||||
await store.VerifyPasswordAsync("targetuser", "Password1!", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
bindDns.Should().HaveCountGreaterThanOrEqualTo(2, "Should bind as service then as user");
|
||||
@@ -289,7 +289,7 @@ public sealed class LdapConnectorSecurityTests
|
||||
// Act
|
||||
try
|
||||
{
|
||||
await store.VerifyPasswordAsync("user", "SuperSecret123!", CancellationToken.None);
|
||||
await store.VerifyPasswordAsync("user", "SuperSecret123!", TestContext.Current.CancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -308,7 +308,7 @@ public sealed class LdapConnectorSecurityTests
|
||||
var store = CreateStore(options, new FakeLdapConnectionFactory(connection));
|
||||
|
||||
// Act
|
||||
var result = await store.VerifyPasswordAsync("user", "MyPassword123", CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("user", "MyPassword123", TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
var resultString = result.ToString();
|
||||
|
||||
@@ -112,13 +112,13 @@ public sealed class LdapConnectorSnapshotTests
|
||||
{
|
||||
// Arrange
|
||||
var fixtureFiles = Directory.Exists(FixturesPath)
|
||||
? Directory.EnumerateFiles(FixturesPath, "*.json").Select(Path.GetFileNameWithoutExtension).ToList()
|
||||
? Directory.EnumerateFiles(FixturesPath, "*.json").Select(Path.GetFileNameWithoutExtension).Where(n => n is not null).Cast<string>().ToList()
|
||||
: new List<string>();
|
||||
|
||||
var expectedFiles = Directory.Exists(ExpectedPath)
|
||||
? Directory.EnumerateFiles(ExpectedPath, "*.canonical.json")
|
||||
.Select(f => Path.GetFileNameWithoutExtension(f).Replace(".canonical", ""))
|
||||
.ToList()
|
||||
.Select(f => Path.GetFileNameWithoutExtension(f)?.Replace(".canonical", ""))
|
||||
.Where(n => n is not null).Cast<string>().ToList()
|
||||
: new List<string>();
|
||||
|
||||
// Assert
|
||||
|
||||
@@ -52,7 +52,7 @@ public sealed class OidcCredentialStoreTests
|
||||
username: "user@example.com",
|
||||
signingCredentials: new SigningCredentials(symmetricKey, SecurityAlgorithms.HmacSha256));
|
||||
|
||||
var result = await store.VerifyPasswordAsync("user@example.com", token, CancellationToken.None);
|
||||
var result = await store.VerifyPasswordAsync("user@example.com", token, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Equal(AuthorityCredentialFailureCode.InvalidCredentials, result.FailureCode);
|
||||
@@ -102,10 +102,10 @@ public sealed class OidcCredentialStoreTests
|
||||
username: "user2@example.com",
|
||||
signingCredentials: new SigningCredentials(rsaKey, SecurityAlgorithms.RsaSha256));
|
||||
|
||||
var result = await storeA.VerifyPasswordAsync("user2@example.com", token, CancellationToken.None);
|
||||
var result = await storeA.VerifyPasswordAsync("user2@example.com", token, TestContext.Current.CancellationToken);
|
||||
Assert.True(result.Succeeded);
|
||||
|
||||
var cached = await storeB.FindBySubjectAsync("user-2", CancellationToken.None);
|
||||
var cached = await storeB.FindBySubjectAsync("user-2", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Null(cached);
|
||||
}
|
||||
@@ -220,8 +220,8 @@ public sealed class OidcCredentialStoreTests
|
||||
|
||||
public OidcPluginOptions CurrentValue => options.Values.First();
|
||||
|
||||
public OidcPluginOptions Get(string name)
|
||||
=> options.TryGetValue(name, out var value) ? value : options.Values.First();
|
||||
public OidcPluginOptions Get(string? name)
|
||||
=> name is not null && options.TryGetValue(name, out var value) ? value : options.Values.First();
|
||||
|
||||
public IDisposable OnChange(Action<OidcPluginOptions, string> listener)
|
||||
=> new NoopDisposable();
|
||||
|
||||
@@ -23,7 +23,7 @@ public sealed class OidcIdentityProviderPluginTests
|
||||
{
|
||||
var (plugin, _) = CreatePlugin(HttpStatusCode.OK);
|
||||
|
||||
var result = await plugin.CheckHealthAsync(CancellationToken.None);
|
||||
var result = await plugin.CheckHealthAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(AuthorityPluginHealthStatus.Healthy, result.Status);
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public sealed class OidcIdentityProviderPluginTests
|
||||
{
|
||||
var (plugin, _) = CreatePlugin(HttpStatusCode.ServiceUnavailable);
|
||||
|
||||
var result = await plugin.CheckHealthAsync(CancellationToken.None);
|
||||
var result = await plugin.CheckHealthAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(AuthorityPluginHealthStatus.Degraded, result.Status);
|
||||
}
|
||||
@@ -132,7 +132,7 @@ public sealed class OidcIdentityProviderPluginTests
|
||||
|
||||
public OidcPluginOptions CurrentValue => options;
|
||||
|
||||
public OidcPluginOptions Get(string name)
|
||||
public OidcPluginOptions Get(string? name)
|
||||
=> string.Equals(name, pluginName, StringComparison.Ordinal) ? options : options;
|
||||
|
||||
public IDisposable OnChange(Action<OidcPluginOptions, string> listener)
|
||||
|
||||
@@ -129,13 +129,13 @@ public sealed class OidcConnectorSnapshotTests
|
||||
{
|
||||
// Arrange
|
||||
var fixtureFiles = Directory.Exists(FixturesPath)
|
||||
? Directory.EnumerateFiles(FixturesPath, "*.json").Select(Path.GetFileNameWithoutExtension).ToList()
|
||||
? Directory.EnumerateFiles(FixturesPath, "*.json").Select(Path.GetFileNameWithoutExtension).Where(n => n is not null).Cast<string>().ToList()
|
||||
: new List<string>();
|
||||
|
||||
var expectedFiles = Directory.Exists(ExpectedPath)
|
||||
? Directory.EnumerateFiles(ExpectedPath, "*.canonical.json")
|
||||
.Select(f => Path.GetFileNameWithoutExtension(f)?.Replace(".canonical", ""))
|
||||
.ToList()
|
||||
.Where(n => n is not null).Cast<string>().ToList()
|
||||
: new List<string>();
|
||||
|
||||
// Assert
|
||||
|
||||
@@ -23,7 +23,7 @@ public sealed class SamlIdentityProviderPluginTests
|
||||
{
|
||||
var plugin = CreatePlugin(HttpStatusCode.OK);
|
||||
|
||||
var result = await plugin.CheckHealthAsync(CancellationToken.None);
|
||||
var result = await plugin.CheckHealthAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(AuthorityPluginHealthStatus.Healthy, result.Status);
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public sealed class SamlIdentityProviderPluginTests
|
||||
{
|
||||
var plugin = CreatePlugin(HttpStatusCode.ServiceUnavailable);
|
||||
|
||||
var result = await plugin.CheckHealthAsync(CancellationToken.None);
|
||||
var result = await plugin.CheckHealthAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(AuthorityPluginHealthStatus.Degraded, result.Status);
|
||||
}
|
||||
@@ -130,7 +130,7 @@ public sealed class SamlIdentityProviderPluginTests
|
||||
|
||||
public SamlPluginOptions CurrentValue => options;
|
||||
|
||||
public SamlPluginOptions Get(string name)
|
||||
public SamlPluginOptions Get(string? name)
|
||||
=> string.Equals(name, pluginName, StringComparison.Ordinal) ? options : options;
|
||||
|
||||
public IDisposable OnChange(Action<SamlPluginOptions, string> listener)
|
||||
|
||||
@@ -122,13 +122,13 @@ public sealed class SamlConnectorSnapshotTests
|
||||
{
|
||||
// Arrange
|
||||
var fixtureFiles = Directory.Exists(FixturesPath)
|
||||
? Directory.EnumerateFiles(FixturesPath, "*.xml").Select(Path.GetFileNameWithoutExtension).ToList()
|
||||
? Directory.EnumerateFiles(FixturesPath, "*.xml").Select(Path.GetFileNameWithoutExtension).Where(n => n is not null).Cast<string>().ToList()
|
||||
: new List<string>();
|
||||
|
||||
var expectedFiles = Directory.Exists(ExpectedPath)
|
||||
? Directory.EnumerateFiles(ExpectedPath, "*.canonical.json")
|
||||
.Select(f => Path.GetFileNameWithoutExtension(f)?.Replace(".canonical", ""))
|
||||
.ToList()
|
||||
.Where(n => n is not null).Cast<string>().ToList()
|
||||
: new List<string>();
|
||||
|
||||
// Assert
|
||||
|
||||
@@ -39,7 +39,7 @@ public class StandardCredentialAuditLoggerTests
|
||||
failureCode: null,
|
||||
reason: null,
|
||||
properties: Array.Empty<AuthEventProperty>(),
|
||||
CancellationToken.None);
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
var record = Assert.Single(sink.Records);
|
||||
Assert.Equal("authority.plugin.standard.password_verification", record.EventType);
|
||||
@@ -92,7 +92,7 @@ public class StandardCredentialAuditLoggerTests
|
||||
failureCode: AuthorityCredentialFailureCode.InvalidCredentials,
|
||||
reason: "Invalid credentials.",
|
||||
properties,
|
||||
CancellationToken.None);
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
var record = Assert.Single(sink.Records);
|
||||
Assert.Equal(AuthEventOutcome.Failure, record.Outcome);
|
||||
@@ -147,7 +147,7 @@ public class StandardCredentialAuditLoggerTests
|
||||
failureCode: AuthorityCredentialFailureCode.LockedOut,
|
||||
reason: "Account locked.",
|
||||
properties,
|
||||
CancellationToken.None);
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
var record = Assert.Single(sink.Records);
|
||||
Assert.Equal(AuthEventOutcome.LockedOut, record.Outcome);
|
||||
@@ -189,7 +189,7 @@ public class StandardCredentialAuditLoggerTests
|
||||
failureCode: AuthorityCredentialFailureCode.RequiresMfa,
|
||||
reason: "MFA required.",
|
||||
properties: null,
|
||||
CancellationToken.None);
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
var record = Assert.Single(sink.Records);
|
||||
var property = Assert.Single(record.Properties);
|
||||
|
||||
@@ -43,7 +43,7 @@ public class StandardClaimsEnricherTests
|
||||
var identity = new ClaimsIdentity();
|
||||
var enricher = new StandardClaimsEnricher();
|
||||
|
||||
await enricher.EnrichAsync(identity, context, CancellationToken.None);
|
||||
await enricher.EnrichAsync(identity, context, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Contains(identity.Claims, claim => claim.Type == ClaimTypes.Role && claim.Value == "admin");
|
||||
Assert.Contains(identity.Claims, claim => claim.Type == ClaimTypes.Role && claim.Value == "ops");
|
||||
|
||||
@@ -32,7 +32,7 @@ public class StandardClientProvisioningStoreTests
|
||||
allowedGrantTypes: new[] { "client_credentials" },
|
||||
allowedScopes: new[] { "scopeA" });
|
||||
|
||||
var result = await provisioning.CreateOrUpdateAsync(registration, CancellationToken.None);
|
||||
var result = await provisioning.CreateOrUpdateAsync(registration, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(result.Succeeded);
|
||||
Assert.True(store.Documents.TryGetValue("bootstrap-client", out var document));
|
||||
@@ -40,7 +40,7 @@ public class StandardClientProvisioningStoreTests
|
||||
Assert.Equal(AuthoritySecretHasher.ComputeHash("SuperSecret1!"), document!.SecretHash);
|
||||
Assert.Equal("standard", document.Plugin);
|
||||
|
||||
var descriptor = await provisioning.FindByClientIdAsync("bootstrap-client", CancellationToken.None);
|
||||
var descriptor = await provisioning.FindByClientIdAsync("bootstrap-client", TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(descriptor);
|
||||
Assert.Equal("bootstrap-client", descriptor!.ClientId);
|
||||
Assert.True(descriptor.Confidential);
|
||||
@@ -65,13 +65,13 @@ public class StandardClientProvisioningStoreTests
|
||||
allowedScopes: new[] { "scopeA" },
|
||||
tenant: " Tenant-Alpha " );
|
||||
|
||||
await provisioning.CreateOrUpdateAsync(registration, CancellationToken.None);
|
||||
await provisioning.CreateOrUpdateAsync(registration, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(store.Documents.TryGetValue("tenant-client", out var document));
|
||||
Assert.NotNull(document);
|
||||
Assert.Equal("tenant-alpha", document!.Properties[AuthorityClientMetadataKeys.Tenant]);
|
||||
|
||||
var descriptor = await provisioning.FindByClientIdAsync("tenant-client", CancellationToken.None);
|
||||
var descriptor = await provisioning.FindByClientIdAsync("tenant-client", TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(descriptor);
|
||||
Assert.Equal("tenant-alpha", descriptor!.Tenant);
|
||||
}
|
||||
@@ -92,14 +92,14 @@ public class StandardClientProvisioningStoreTests
|
||||
allowedScopes: new[] { "signer.sign" },
|
||||
allowedAudiences: new[] { "attestor", "signer" });
|
||||
|
||||
var result = await provisioning.CreateOrUpdateAsync(registration, CancellationToken.None);
|
||||
var result = await provisioning.CreateOrUpdateAsync(registration, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(result.Succeeded);
|
||||
Assert.True(store.Documents.TryGetValue("signer", out var document));
|
||||
Assert.NotNull(document);
|
||||
Assert.Equal("attestor signer", document!.Properties[AuthorityClientMetadataKeys.Audiences]);
|
||||
|
||||
var descriptor = await provisioning.FindByClientIdAsync("signer", CancellationToken.None);
|
||||
var descriptor = await provisioning.FindByClientIdAsync("signer", TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(descriptor);
|
||||
Assert.Equal(new[] { "attestor", "signer" }, descriptor!.AllowedAudiences.OrderBy(value => value, StringComparer.Ordinal));
|
||||
}
|
||||
@@ -132,7 +132,7 @@ public class StandardClientProvisioningStoreTests
|
||||
allowedAudiences: new[] { "signer" },
|
||||
certificateBindings: new[] { bindingRegistration });
|
||||
|
||||
await provisioning.CreateOrUpdateAsync(registration, CancellationToken.None);
|
||||
await provisioning.CreateOrUpdateAsync(registration, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(store.Documents.TryGetValue("mtls-client", out var document));
|
||||
Assert.NotNull(document);
|
||||
@@ -164,9 +164,9 @@ public class StandardClientProvisioningStoreTests
|
||||
allowedGrantTypes: new[] { "client_credentials" },
|
||||
allowedScopes: new[] { "scopeA" });
|
||||
|
||||
await provisioning.CreateOrUpdateAsync(registration, CancellationToken.None);
|
||||
await provisioning.CreateOrUpdateAsync(registration, TestContext.Current.CancellationToken);
|
||||
|
||||
var result = await provisioning.DeleteAsync("delete-me", CancellationToken.None);
|
||||
var result = await provisioning.DeleteAsync("delete-me", TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(result.Succeeded);
|
||||
Assert.False(store.Documents.ContainsKey("delete-me"));
|
||||
|
||||
@@ -58,7 +58,7 @@ public class StandardIdentityProviderPluginTests
|
||||
new StandardClaimsEnricher(),
|
||||
NullLogger<StandardIdentityProviderPlugin>.Instance);
|
||||
|
||||
var health = await plugin.CheckHealthAsync(CancellationToken.None);
|
||||
var health = await plugin.CheckHealthAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(AuthorityPluginHealthStatus.Healthy, health.Status);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class StandardPluginBootstrapperTests
|
||||
using var provider = services.BuildServiceProvider();
|
||||
var bootstrapper = provider.GetRequiredService<StandardPluginBootstrapper>();
|
||||
|
||||
var exception = await Record.ExceptionAsync(() => bootstrapper.StartAsync(CancellationToken.None));
|
||||
var exception = await Record.ExceptionAsync(() => bootstrapper.StartAsync(TestContext.Current.CancellationToken));
|
||||
|
||||
Assert.Null(exception);
|
||||
}
|
||||
|
||||
@@ -228,6 +228,7 @@ public class StandardUserCredentialStoreTests : IAsyncLifetime
|
||||
|
||||
var updated = await store.UpsertUserAsync(update, CancellationToken.None);
|
||||
Assert.True(updated.Succeeded);
|
||||
Assert.NotNull(updated.Value);
|
||||
Assert.Contains("editor", updated.Value.Roles);
|
||||
Assert.Contains("admin", updated.Value.Roles);
|
||||
Assert.Equal("us", updated.Value.Attributes["region"]);
|
||||
@@ -250,6 +251,7 @@ public class StandardUserCredentialStoreTests : IAsyncLifetime
|
||||
|
||||
var created = await store.UpsertUserAsync(registration, CancellationToken.None);
|
||||
Assert.True(created.Succeeded);
|
||||
Assert.NotNull(created.Value);
|
||||
|
||||
var found = await store.FindBySubjectAsync(created.Value.SubjectId, CancellationToken.None);
|
||||
Assert.NotNull(found);
|
||||
|
||||
@@ -115,7 +115,7 @@ public sealed class AdvisoryAiRemoteInferenceEndpointTests : IClassFixture<Autho
|
||||
var expectedHash = ComputeSha256(payload.Prompt);
|
||||
Assert.Equal(expectedHash, body["prompt_hash"]);
|
||||
|
||||
var doc = Assert.Single(lastLoginAttemptStore!.Records.Where(record => record.EventType == "authority.advisory_ai.remote_inference"));
|
||||
var doc = Assert.Single(lastLoginAttemptStore!.Records, record => record.EventType == "authority.advisory_ai.remote_inference");
|
||||
Assert.Equal("authority.advisory_ai.remote_inference", doc.EventType);
|
||||
var properties = doc.Properties.ToDictionary(p => p.Name, p => p.Value);
|
||||
Assert.Equal(expectedHash, properties["advisory_ai.prompt.hash"]);
|
||||
|
||||
@@ -77,7 +77,7 @@ public class AuthorityAuditSinkTests
|
||||
Assert.Equal(record.OccurredAt, document.OccurredAt);
|
||||
Assert.Equal(new[] { "openid", "profile" }, document.Scopes);
|
||||
|
||||
var pluginProperty = Assert.Single(document.Properties.Where(property => property.Name == "plugin.failed_attempts"));
|
||||
var pluginProperty = Assert.Single(document.Properties, property => property.Name == "plugin.failed_attempts");
|
||||
Assert.Equal("0", pluginProperty.Value);
|
||||
Assert.Equal("none", pluginProperty.Classification);
|
||||
|
||||
|
||||
@@ -2926,9 +2926,9 @@ public class ClientCredentialsHandlersTests
|
||||
Assert.False(validateContext.IsRejected);
|
||||
Assert.False(validateContext.Transaction.Properties.ContainsKey(AuthorityOpenIddictConstants.SenderConstraintProperty));
|
||||
|
||||
var bypassEvent = Assert.Single(auditSink.Events.Where(record => record.EventType == "authority.dpop.proof.bypass"));
|
||||
var bypassEvent = Assert.Single(auditSink.Events, record => record.EventType == "authority.dpop.proof.bypass");
|
||||
Assert.Equal(AuthEventOutcome.Success, bypassEvent.Outcome);
|
||||
var reasonProperty = Assert.Single(bypassEvent.Properties.Where(property => property.Name == "dpop.reason_code"));
|
||||
var reasonProperty = Assert.Single(bypassEvent.Properties, property => property.Name == "dpop.reason_code");
|
||||
Assert.Equal("bypass", reasonProperty.Value.Value);
|
||||
}
|
||||
|
||||
@@ -3387,7 +3387,7 @@ public class ClientCredentialsHandlersTests
|
||||
var grantEvent = authSink.Events.LastOrDefault(evt => evt.EventType == "authority.client_credentials.grant");
|
||||
Assert.NotNull(grantEvent);
|
||||
|
||||
var serviceProperty = Assert.Single(grantEvent!.Properties.Where(prop => prop.Name == "delegation.service_account"));
|
||||
var serviceProperty = Assert.Single(grantEvent!.Properties, prop => prop.Name == "delegation.service_account");
|
||||
Assert.Equal(serviceAccount.AccountId, serviceProperty.Value.Value);
|
||||
|
||||
var actorPropertyValues = grantEvent.Properties
|
||||
|
||||
@@ -22,6 +22,9 @@ namespace StellaOps.Authority.ConfigDiff.Tests;
|
||||
[Trait("BlastRadius", TestCategories.BlastRadius.Auth)]
|
||||
public class AuthorityConfigDiffTests : ConfigDiffTestBase
|
||||
{
|
||||
private static readonly DateTimeOffset SnapshotTimestamp =
|
||||
new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthorityConfigDiffTests"/> class.
|
||||
/// </summary>
|
||||
@@ -61,7 +64,8 @@ public class AuthorityConfigDiffTests : ConfigDiffTestBase
|
||||
async config => await GetSessionBehaviorAsync(config),
|
||||
async config => await GetRefreshBehaviorAsync(config),
|
||||
async config => await GetAuthenticationBehaviorAsync(config)
|
||||
]);
|
||||
],
|
||||
ct: TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.Should().BeTrue(
|
||||
@@ -93,7 +97,8 @@ public class AuthorityConfigDiffTests : ConfigDiffTestBase
|
||||
changedConfig,
|
||||
getBehavior: async config => await CaptureSessionBehaviorAsync(config),
|
||||
computeDelta: ComputeBehaviorSnapshotDelta,
|
||||
expectedDelta: expectedDelta);
|
||||
expectedDelta: expectedDelta,
|
||||
ct: TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.Should().BeTrue(
|
||||
@@ -119,7 +124,8 @@ public class AuthorityConfigDiffTests : ConfigDiffTestBase
|
||||
[
|
||||
async config => await GetSessionBehaviorAsync(config),
|
||||
async config => await GetPasswordPolicyBehaviorAsync(config)
|
||||
]);
|
||||
],
|
||||
ct: TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.Should().BeTrue(
|
||||
@@ -151,7 +157,8 @@ public class AuthorityConfigDiffTests : ConfigDiffTestBase
|
||||
changedConfig,
|
||||
getBehavior: async config => await CapturePasswordPolicyBehaviorAsync(config),
|
||||
computeDelta: ComputeBehaviorSnapshotDelta,
|
||||
expectedDelta: expectedDelta);
|
||||
expectedDelta: expectedDelta,
|
||||
ct: TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
@@ -176,7 +183,8 @@ public class AuthorityConfigDiffTests : ConfigDiffTestBase
|
||||
[
|
||||
async config => await GetTokenBehaviorAsync(config),
|
||||
async config => await GetSessionBehaviorAsync(config)
|
||||
]);
|
||||
],
|
||||
ct: TestContext.Current.CancellationToken);
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.Should().BeTrue(
|
||||
@@ -216,11 +224,11 @@ public class AuthorityConfigDiffTests : ConfigDiffTestBase
|
||||
ConfigurationId: $"sessions-{config.MaxConcurrentSessions}",
|
||||
Behaviors:
|
||||
[
|
||||
new CapturedBehavior("SessionLimit", config.MaxConcurrentSessions.ToString(), DateTimeOffset.UtcNow),
|
||||
new CapturedBehavior("SessionLimit", config.MaxConcurrentSessions.ToString(), SnapshotTimestamp),
|
||||
new CapturedBehavior("ConcurrencyPolicy",
|
||||
config.MaxConcurrentSessions > 5 ? "permissive" : "restrictive", DateTimeOffset.UtcNow)
|
||||
config.MaxConcurrentSessions > 5 ? "permissive" : "restrictive", SnapshotTimestamp)
|
||||
],
|
||||
CapturedAt: DateTimeOffset.UtcNow);
|
||||
CapturedAt: SnapshotTimestamp);
|
||||
|
||||
return Task.FromResult(snapshot);
|
||||
}
|
||||
@@ -232,11 +240,11 @@ public class AuthorityConfigDiffTests : ConfigDiffTestBase
|
||||
Behaviors:
|
||||
[
|
||||
new CapturedBehavior("PasswordComplexity",
|
||||
config.MinPasswordLength >= 12 ? "enhanced" : "standard", DateTimeOffset.UtcNow),
|
||||
config.MinPasswordLength >= 12 ? "enhanced" : "standard", SnapshotTimestamp),
|
||||
new CapturedBehavior("ValidationRejectionRate",
|
||||
config.MinPasswordLength >= 12 ? "increase" : "standard", DateTimeOffset.UtcNow)
|
||||
config.MinPasswordLength >= 12 ? "increase" : "standard", SnapshotTimestamp)
|
||||
],
|
||||
CapturedAt: DateTimeOffset.UtcNow);
|
||||
CapturedAt: SnapshotTimestamp);
|
||||
|
||||
return Task.FromResult(snapshot);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public sealed class AuthorityPostgresFixture : PostgresIntegrationFixture, IColl
|
||||
public PostgresOptions CreateOptions()
|
||||
{
|
||||
var options = Fixture.CreateOptions();
|
||||
options.SchemaName = SchemaName;
|
||||
options.SchemaName = AuthorityDataSource.DefaultSchemaName;
|
||||
options.MaxPoolSize = 10;
|
||||
options.MinPoolSize = 0;
|
||||
return options;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Threading;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -7,6 +6,7 @@ using Npgsql;
|
||||
using StellaOps.Authority.Core.Verdicts;
|
||||
using StellaOps.Authority.Persistence.Postgres;
|
||||
using StellaOps.TestKit;
|
||||
using System.Text.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Authority.Persistence.Tests;
|
||||
@@ -37,7 +37,7 @@ public sealed class VerdictManifestStoreTests : IAsyncLifetime
|
||||
[Fact]
|
||||
public async Task StoreAndGetById_RoundTripsManifest()
|
||||
{
|
||||
var evaluatedAt = DateTimeOffset.Parse("2025-01-15T10:00:00Z");
|
||||
var evaluatedAt = new DateTimeOffset(2025, 1, 15, 10, 0, 0, TimeSpan.Zero);
|
||||
var manifest = CreateManifest("tenant-1", "manifest-001", evaluatedAt, VexStatus.NotAffected);
|
||||
|
||||
await _store.StoreAsync(manifest);
|
||||
@@ -58,12 +58,15 @@ public sealed class VerdictManifestStoreTests : IAsyncLifetime
|
||||
[Fact]
|
||||
public async Task StoreAsync_WritesStringEnumJson()
|
||||
{
|
||||
var evaluatedAt = DateTimeOffset.Parse("2025-01-15T11:00:00Z");
|
||||
var evaluatedAt = new DateTimeOffset(2025, 1, 15, 11, 0, 0, TimeSpan.Zero);
|
||||
var manifest = CreateManifest("tenant-2", "manifest-002", evaluatedAt, VexStatus.UnderInvestigation);
|
||||
|
||||
await _store.StoreAsync(manifest);
|
||||
|
||||
await using var conn = await _dataSource.OpenConnectionAsync(manifest.Tenant, "reader", CancellationToken.None);
|
||||
await using var conn = await _dataSource.OpenConnectionAsync(
|
||||
manifest.Tenant,
|
||||
"reader",
|
||||
TestContext.Current.CancellationToken);
|
||||
await using var cmd = new NpgsqlCommand("""
|
||||
SELECT result_json::text
|
||||
FROM verdict_manifests
|
||||
@@ -77,7 +80,8 @@ public sealed class VerdictManifestStoreTests : IAsyncLifetime
|
||||
|
||||
var json = (string?)await cmd.ExecuteScalarAsync();
|
||||
json.Should().NotBeNull();
|
||||
json.Should().Contain("\"status\":\"under_investigation\"");
|
||||
using var document = JsonDocument.Parse(json!);
|
||||
document.RootElement.GetProperty("status").GetString().Should().Be("under_investigation");
|
||||
}
|
||||
|
||||
private static VerdictManifest CreateManifest(string tenant, string manifestId, DateTimeOffset evaluatedAt, VexStatus status)
|
||||
|
||||
Reference in New Issue
Block a user