103 lines
4.9 KiB
C#
103 lines
4.9 KiB
C#
// GLAuth integration test — opt-in only.
|
|
//
|
|
// Prerequisites
|
|
// -------------
|
|
// 1. A running GLAuth instance (plaintext LDAP, no TLS).
|
|
// A ready-made Docker Compose stack lives in the sibling repo:
|
|
// ~/Desktop/ScadaBridge/infra/glauth
|
|
// Start it with: docker compose up -d
|
|
// Default listen address: localhost:3893
|
|
//
|
|
// 2. Set the following environment variables before running:
|
|
// ZB_LDAP_IT=1 (required — gates the test)
|
|
// ZB_LDAP_SERVER=localhost (optional, default localhost)
|
|
// ZB_LDAP_PORT=3893 (optional, default 3893)
|
|
// ZB_LDAP_BASE=dc=lmxopcua,dc=local (optional)
|
|
// ZB_LDAP_SVC_DN=cn=svc,dc=lmxopcua,dc=local (service-account DN)
|
|
// ZB_LDAP_SVC_PW=svcpass (service-account password)
|
|
// ZB_LDAP_USER=alice (test user login)
|
|
// ZB_LDAP_PW=alicepass (test user password)
|
|
// ZB_LDAP_USERATTR=cn (optional, default cn)
|
|
//
|
|
// Run command:
|
|
// ZB_LDAP_IT=1 ZB_LDAP_SVC_DN=... ZB_LDAP_SVC_PW=... \
|
|
// ZB_LDAP_USER=... ZB_LDAP_PW=... \
|
|
// dotnet test tests/ZB.MOM.WW.Auth.Ldap.Tests \
|
|
// --filter "FullyQualifiedName~GLAuthIntegrationTests"
|
|
//
|
|
// Without ZB_LDAP_IT=1 the test is SKIPPED — it does not affect the normal CI run.
|
|
|
|
using System.Net.Sockets;
|
|
using ZB.MOM.WW.Auth.Abstractions.Ldap;
|
|
using ZB.MOM.WW.Auth.Ldap;
|
|
|
|
namespace ZB.MOM.WW.Auth.Ldap.Tests.Integration;
|
|
|
|
public sealed class GLAuthIntegrationTests
|
|
{
|
|
/// <summary>
|
|
/// Performs a real bind-then-search-then-bind against a live GLAuth instance.
|
|
/// Verifies that authentication succeeds and that at least one LDAP group is returned.
|
|
/// Skipped unless <c>ZB_LDAP_IT=1</c> is set; skipped again if the server is unreachable.
|
|
/// </summary>
|
|
[SkippableFact]
|
|
public async Task Authenticate_AgainstRealGLAuth_Succeeds()
|
|
{
|
|
// ------------------------------------------------------------------ opt-in gate
|
|
Skip.IfNot(
|
|
Environment.GetEnvironmentVariable("ZB_LDAP_IT") == "1",
|
|
"Set ZB_LDAP_IT=1 and a reachable GLAuth to run.");
|
|
|
|
// ------------------------------------------------------------------ read config
|
|
var server = Environment.GetEnvironmentVariable("ZB_LDAP_SERVER") ?? "localhost";
|
|
var port = int.TryParse(Environment.GetEnvironmentVariable("ZB_LDAP_PORT"), out var p) ? p : 3893;
|
|
var baseDn = Environment.GetEnvironmentVariable("ZB_LDAP_BASE") ?? "dc=lmxopcua,dc=local";
|
|
var svcDn = Environment.GetEnvironmentVariable("ZB_LDAP_SVC_DN") ?? "";
|
|
var svcPw = Environment.GetEnvironmentVariable("ZB_LDAP_SVC_PW") ?? "";
|
|
var user = Environment.GetEnvironmentVariable("ZB_LDAP_USER") ?? "";
|
|
var pw = Environment.GetEnvironmentVariable("ZB_LDAP_PW") ?? "";
|
|
var userAttr = Environment.GetEnvironmentVariable("ZB_LDAP_USERATTR") ?? "cn";
|
|
|
|
// ------------------------------------------------------------------ reachability probe
|
|
try
|
|
{
|
|
using var tcp = new TcpClient();
|
|
// 3-second connect timeout to keep the test suite snappy when the server is absent
|
|
var connectTask = tcp.ConnectAsync(server, port);
|
|
if (!connectTask.Wait(TimeSpan.FromSeconds(3)))
|
|
Skip.If(true, $"GLAuth not reachable at {server}:{port} (connect timed out).");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Skip.If(true, $"GLAuth not reachable at {server}:{port}: {ex.Message}");
|
|
}
|
|
|
|
// ------------------------------------------------------------------ build options
|
|
var options = new LdapOptions
|
|
{
|
|
Enabled = true,
|
|
Server = server,
|
|
Port = port,
|
|
Transport = LdapTransport.None,
|
|
AllowInsecure = true,
|
|
SearchBase = baseDn,
|
|
ServiceAccountDn = svcDn,
|
|
ServiceAccountPassword = svcPw,
|
|
UserNameAttribute = userAttr,
|
|
// GLAuth returns memberOf by default; keep the library default
|
|
GroupAttribute = "memberOf",
|
|
};
|
|
|
|
// ------------------------------------------------------------------ exercise the real service
|
|
// Uses the public single-argument constructor, which wires up NovellLdapConnectionFactory
|
|
// internally — no test seam involved.
|
|
var svc = new LdapAuthService(options);
|
|
var result = await svc.AuthenticateAsync(user, pw, default);
|
|
|
|
// ------------------------------------------------------------------ assertions
|
|
Assert.True(result.Succeeded,
|
|
$"Authentication failed: {result.Failure} (server={server}:{port}, user={user})");
|
|
Assert.NotEmpty(result.Groups);
|
|
}
|
|
}
|