fix(security): resolve Security-009,010,011 — LDAP connection timeout, design-doc correction, security-path test coverage; Security-008 deferred
This commit is contained in:
@@ -672,6 +672,81 @@ public class SecurityReviewRegressionTests2
|
||||
|
||||
#endregion
|
||||
|
||||
#region Code Review Regression Tests — Security-009/011
|
||||
|
||||
/// <summary>
|
||||
/// Regression tests for Security-009 (no LDAP connection timeout — a hung server can
|
||||
/// pin a thread-pool thread indefinitely because <c>ct</c> only guards work-item
|
||||
/// scheduling) and the remaining Security-011 coverage gaps.
|
||||
/// </summary>
|
||||
public class SecurityReviewRegressionTests3
|
||||
{
|
||||
// --- Security-009: LDAP connection timeout must be configurable and bounded ---
|
||||
|
||||
[Fact]
|
||||
public void SecurityOptions_LdapConnectionTimeout_HasSaneDefault()
|
||||
{
|
||||
var options = new SecurityOptions();
|
||||
// A positive, finite default so a hung LDAP server cannot pin a thread forever.
|
||||
Assert.True(options.LdapConnectionTimeoutMs > 0);
|
||||
Assert.True(options.LdapConnectionTimeoutMs <= 60_000,
|
||||
"Default LDAP connection timeout should be bounded (<= 60s).");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AuthenticateAsync_UnreachableHost_FailsWithinConfiguredTimeout()
|
||||
{
|
||||
// A routable-but-non-responsive address would otherwise hang for the OS default
|
||||
// (often minutes). With LdapConnectionTimeoutMs applied to the LdapConnection the
|
||||
// call must give up promptly. 198.51.100.0/24 (TEST-NET-2, RFC 5737) is reserved
|
||||
// and not routed, so the connect attempt stalls until the timeout fires.
|
||||
var options = new SecurityOptions
|
||||
{
|
||||
LdapServer = "198.51.100.1",
|
||||
LdapPort = 389,
|
||||
LdapTransport = LdapTransport.None,
|
||||
AllowInsecureLdap = true,
|
||||
LdapSearchBase = "dc=example,dc=com",
|
||||
LdapConnectionTimeoutMs = 2_000
|
||||
};
|
||||
var service = new LdapAuthService(Options.Create(options), NullLogger<LdapAuthService>.Instance);
|
||||
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
var result = await service.AuthenticateAsync("user", "password");
|
||||
sw.Stop();
|
||||
|
||||
Assert.False(result.Success);
|
||||
// Generous ceiling: the 2s timeout plus scheduling/CI overhead, far below the
|
||||
// multi-minute OS default that an unconfigured connection would incur.
|
||||
Assert.True(sw.Elapsed < TimeSpan.FromSeconds(30),
|
||||
$"Authentication did not honour the LDAP connection timeout: took {sw.Elapsed}.");
|
||||
}
|
||||
|
||||
// --- Security-011: additional coverage for the no-service-account / DN paths ---
|
||||
|
||||
[Fact]
|
||||
public void BuildFallbackUserDn_NoSearchBase_ReturnsBareRdn()
|
||||
{
|
||||
var dn = LdapAuthService.BuildFallbackUserDn("alice", "", "uid");
|
||||
Assert.Equal("uid=alice", dn);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EscapeLdapDn_LeadingHash_IsEscaped()
|
||||
{
|
||||
Assert.Equal(@"\#admin", LdapAuthService.EscapeLdapDn("#admin"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EscapeLdapDn_NullOrEmpty_ReturnedUnchanged()
|
||||
{
|
||||
Assert.Equal("", LdapAuthService.EscapeLdapDn(""));
|
||||
Assert.Null(LdapAuthService.EscapeLdapDn(null!));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region WP-9: Authorization Policy Tests
|
||||
|
||||
public class AuthorizationPolicyTests
|
||||
|
||||
Reference in New Issue
Block a user