Bitai.LDAPHelper.LdapAdapters.LdapHelperMock 10.2.0

dotnet add package Bitai.LDAPHelper.LdapAdapters.LdapHelperMock --version 10.2.0
                    
NuGet\Install-Package Bitai.LDAPHelper.LdapAdapters.LdapHelperMock -Version 10.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Bitai.LDAPHelper.LdapAdapters.LdapHelperMock" Version="10.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Bitai.LDAPHelper.LdapAdapters.LdapHelperMock" Version="10.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Bitai.LDAPHelper.LdapAdapters.LdapHelperMock" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Bitai.LDAPHelper.LdapAdapters.LdapHelperMock --version 10.2.0
                    
#r "nuget: Bitai.LDAPHelper.LdapAdapters.LdapHelperMock, 10.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Bitai.LDAPHelper.LdapAdapters.LdapHelperMock@10.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Bitai.LDAPHelper.LdapAdapters.LdapHelperMock&version=10.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Bitai.LDAPHelper.LdapAdapters.LdapHelperMock&version=10.2.0
                    
Install as a Cake Tool

.NET 10.0 License: MIT Package

An in-memory LDAP adapter implementation designed for unit testing, integration testing, offline prototyping, local development, and CI/CD pipelines in the Bitai LDAP Helper ecosystem.


Table of Contents


Overview

Bitai.LDAPHelper.LdapAdapters.LdapHelperMock provides lightweight, fast, in-memory mock implementations of the LDAP adapter contracts defined in Bitai.LDAPHelper.

It enables developers to test LDAP-dependent components—such as authentication services (Authenticator), user search providers (Searcher), group membership validators (GroupMembershipValidator), and Active Directory account management routines (AccountManager)—without requiring access to a physical Active Directory, OpenLDAP, or containerized LDAP instance.

Target Framework & Specifications

  • Target Framework: .NET 10.0 (net10.0)
  • Nullable Context: Enabled (<Nullable>enable</Nullable>)
  • Implicit Usings: Enabled (<ImplicitUsings>enable</ImplicitUsings>)
  • Project Reference: Depends on Bitai.LDAPHelper

Solution Architecture

In the Bitai.LDAPHelper ecosystem, core services interact exclusively with LDAP contract abstractions (ILdapConnectionFactoryAdapter, ILdapConnectionAdapter, ILdapEntryAdapter, etc.) rather than concrete directory implementations. LdapHelperMock acts as a drop-in replacement for production adapters such as Bitai.LDAPHelper.LdapAdapters.Novell.

┌─────────────────────────────────────────────────────────────────┐
│                      Consumer Application                       │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                       Bitai.LDAPHelper                          │
│     (Authenticator, Searcher, AccountManager, Validator)        │
└─────────────────────────────────────────────────────────────────┘
                                │
                   ILdapConnectionFactoryAdapter
                   ILdapConnectionAdapter
                                │
        ┌───────────────────────┴───────────────────────┐
        ▼                                               ▼
┌──────────────────────────────┐       ┌──────────────────────────────┐
│     LdapAdapters.Novell      │       │       LdapHelperMock         │
│  (Production / Live LDAP)    │       │  (In-Memory / Test Suite)    │
└──────────────────────────────┘       └──────────────────────────────┘
                                                        │
                                                        ▼
                                       ┌──────────────────────────────┐
                                       │     MockLdapDataStore        │
                                       │   (In-Memory Directory)      │
                                       └──────────────────────────────┘

Repository Projects Overview

Project Path Role & Purpose
Bitai.LDAPHelper.LdapAdapters.LdapHelperMock adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock In-memory mock adapter implementation & test seeder
Bitai.LDAPHelper src/Bitai.LDAPHelper Core helper library defining adapter interfaces & services
Bitai.LDAPHelper.DTO src/Bitai.LDAPHelper.DTO Data transfer objects, credentials, and operation results
Bitai.LDAPHelper.LdapAdapters.Novell adapters/Bitai.LDAPHelper.LdapAdapters.Novell Novell-backed LDAP connection adapter for live environments
Bitai.LDAPHelper.Tests tests/Bitai.LDAPHelper.Tests Unit and integration test suite consuming mock adapters

Key Features

  1. Persistent Shared State (MockLdapPersistentConnectionAdapter)
    • Simulates ConnectAsync, BindAsync, SearchAsync, AddEntryAsync, ModifyEntryAsync, and DeleteEntryAsync.
    • Supports registerable search results via AddSearchResult(filterPattern, entries).
    • Backed by MockLdapDataStore to persist entry creations, modifications, and deletions across multiple connections.
    • Evaluates search filters dynamically against stored records.
  2. Deterministic Directory Seeder (MockLdapDataSeeder)
    • Populates realistic Active Directory objects: domain roots, OUs (Users, Groups, Computers), standard accounts, service accounts, and nested group memberships.
    • Includes thread-safe progressive RID generation and structured logging via ILogger<MockLdapDataSeeder>.
  3. Side-Effect Inspection & Assertions
    • Tracks created entries (CreatedEntries), modifications (Modifications), and deletions (DeletedEntries) for assertion in unit tests.
  4. Multi-Attribute Filter Engine
    • Evaluates LDAP search filter criteria including wildcard matching (*) against sAMAccountName, distinguishedName, cn, objectSid, and objectClass.
  5. Active Directory SID Conversion
    • Includes binary SID parsing utilities (ConvertByteToStringSid) to match Windows Active Directory objectSid formatting (S-1-5-...).

Project Structure & Class Taxonomy

adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/
├── Bitai.LDAPHelper.LdapAdapters.LdapHelperMock.csproj
├── README.md
├── LICENSE.md
├── MockLdapPersistentConnectionAdapter.cs
├── MockLdapPersistentConnectionFactoryAdapter.cs
├── MockLdapEntryAdapter.cs
├── MockLdapAttributeSetAdapter.cs
├── MockLdapAttributeAdapter.cs
├── MockLdapModificationAdapter.cs
├── MockLdapMessageAdapter.cs
├── MockLdapSearchQueueAdapter.cs
└── LdapData/
    ├── MockLdapDataStore.cs
    └── MockLdapDataSeeder.cs

Class Roles Breakdown

Class Implemented Interface Primary Responsibility
MockLdapPersistentConnectionAdapter ILdapConnectionAdapter Persistent mock connection connected to the central MockLdapDataStore. Supports configurable search results & side-effect trackers.
MockLdapPersistentConnectionFactoryAdapter ILdapConnectionFactoryAdapter Factory producing MockLdapPersistentConnectionAdapter instances.
MockLdapEntryAdapter ILdapEntryAdapter Represents an LDAP entry with a DN and attribute set.
MockLdapAttributeSetAdapter ILdapAttributeSetAdapter Dictionary-backed container for entry attributes. Includes verification helpers.
MockLdapAttributeAdapter ILdapAttributeAdapter Represents individual attribute key-value pairs (string, string array, or byte array).
MockLdapModificationAdapter ILdapModificationAdapter Represents an LDAP entry modification (Add, Delete, Replace).
MockLdapMessageAdapter ILdapMessageAdapter Wraps single search result entries for message queue delivery.
MockLdapSearchQueueAdapter ILdapSearchQueueAdapter In-memory queue storing search result messages returned by SearchAsync.
MockLdapDataStore N/A (Singleton) Thread-safe in-memory directory store guarded by ReaderWriterLockSlim.
MockLdapDataSeeder N/A Seeds MockLdapDataStore with domain hierarchies, OUs, users, groups, and SIDs.

Quick Start

Installation

To add Bitai.LDAPHelper.LdapAdapters.LdapHelperMock to a test project:

dotnet add package Bitai.LDAPHelper.LdapAdapters.LdapHelperMock

Or via project reference:

<ItemGroup>
  <ProjectReference Include="..\..\adapters\Bitai.LDAPHelper.LdapAdapters.LdapHelperMock\Bitai.LDAPHelper.LdapAdapters.LdapHelperMock.csproj" />
</ItemGroup>

Basic Minimal Example

using Bitai.LDAPHelper;
using Bitai.LDAPHelper.DTO;
using Bitai.LDAPHelper.LdapAdapters.LdapHelperMock;

// 1. Create a persistent mock connection
var mockConnection = new MockLdapPersistentConnectionAdapter();

var userEntry = new MockLdapEntryAdapter("CN=John Doe,OU=Users,DC=example,DC=com");
userEntry.AddAttribute("cn", "John Doe");
userEntry.AddAttribute("sAMAccountName", "jdoe");
userEntry.AddAttribute("userPrincipalName", "jdoe@example.com");

mockConnection.AddSearchResult("(sAMAccountName=jdoe)", new List<MockLdapEntryAdapter> { userEntry });

// 2. Wrap in a factory
var factory = new MockLdapPersistentConnectionFactoryAdapter();

// 3. Initialize LDAPHelper services using the mock factory
var connectionInfo = new ConnectionInfo("localhost", 389, useSSL: false, connectionTimeout: 15);
var credential = new LDAPDomainAccountCredential("EXAMPLE", "service.account", "SecretPassword!");
var searchLimits = new SearchLimits("DC=example,DC=com");

var searcher = new Searcher(connectionInfo, searchLimits, credential, factory);

// 4. Perform search via Searcher
var user = await searcher.GetLdapEntryBySamAccountNameAsync("jdoe");
Console.WriteLine($"Found User: {user?.CN} ({user?.DistinguishedName})");

Detailed Usage Scenarios

Scenario 1: Isolated Unit Testing with Custom Search Results

For targeted unit tests where you want exact control over returned entries without global directory state:

using Xunit;
using Bitai.LDAPHelper;
using Bitai.LDAPHelper.DTO;
using Bitai.LDAPHelper.LdapAdapters.LdapHelperMock;

public class UserServiceTests
{
    [Fact]
    public async Task GetUser_ShouldReturnMatchingLdapEntry()
    {
        // Arrange
        var mockConnection = new MockLdapPersistentConnectionAdapter();
        
        var expectedDn = "CN=Alice Smith,OU=Engineering,DC=corp,DC=local";
        var entry = new MockLdapEntryAdapter(expectedDn);
        entry.AddAttribute("sAMAccountName", "asmith");
        entry.AddAttribute("mail", "alice.smith@corp.local");
        entry.AddAttribute("givenName", "Alice");
        entry.AddAttribute("sn", "Smith");

        mockConnection.AddSearchResult("asmith", new List<MockLdapEntryAdapter> { entry });
        
        var factory = new MockLdapPersistentConnectionFactoryAdapter();
        var searcher = new Searcher(
            new ConnectionInfo("ldap.corp.local", 389, false, 10),
            new SearchLimits("DC=corp,DC=local"),
            new LDAPDomainAccountCredential("CORP", "admin", "pass"),
            factory
        );

        // Act
        var result = await searcher.GetLdapEntryBySamAccountNameAsync("asmith");

        // Assert
        Assert.NotNull(result);
        Assert.Equal("asmith", result.SamAccountName);
        Assert.Equal(expectedDn, result.DistinguishedName);
    }
}

Scenario 2: Integration Testing with Persistent Seeded Data

When testing complex workflows that execute sequential searches, authentications, or group membership checks against a shared directory dataset:

using Xunit;
using Bitai.LDAPHelper;
using Bitai.LDAPHelper.DTO;
using Bitai.LDAPHelper.LdapAdapters.LdapHelperMock;
using Bitai.LDAPHelper.LdapAdapters.LdapHelperMock.LdapData;
using Microsoft.Extensions.Logging.Abstractions;

public class AuthenticationIntegrationTests
{
    public AuthenticationIntegrationTests()
    {
        // Seed the shared in-memory data store with realistic AD entities
        var seeder = new MockLdapDataSeeder(NullLogger<MockLdapDataSeeder>.Instance);
        seeder.SeedAllData();
    }

    [Fact]
    public async Task AuthenticateDomainAccount_WithSeededUser_ShouldSucceed()
    {
        // Arrange - use persistent connection factory
        var factory = new MockLdapPersistentConnectionFactoryAdapter();
        
        var connectionInfo = new ConnectionInfo("dc01.domain.com", 389, false, 30);
        var searchLimits = new SearchLimits("DC=domain,DC=com");
        var adminCreds = new LDAPDomainAccountCredential("DOMAIN", "Administrator", "AdminP@ss123");

        var authenticator = new Authenticator(connectionInfo, searchLimits, adminCreds, factory);

        // Act - Authenticate a user populated by MockLdapDataSeeder
        var targetUserCreds = new LDAPDomainAccountCredential("DOMAIN", "jdoe", "UserP@ssword1!");
        var authResult = await authenticator.AuthenticateDomainAccountAsync(targetUserCreds);

        // Assert
        Assert.NotNull(authResult);
        Assert.True(authResult.IsAuthenticated);
    }
}

Scenario 3: Verifying Account Management Side Effects

When testing routines that create, modify, or delete directory objects (e.g. AccountManager), use MockLdapPersistentConnectionAdapter to verify generated modifications:

using Xunit;
using Bitai.LDAPHelper;
using Bitai.LDAPHelper.DTO;
using Bitai.LDAPHelper.LdapAdapters;
using Bitai.LDAPHelper.LdapAdapters.LdapHelperMock;

public class AccountManagerTests
{
    [Fact]
    public async Task ModifyUserAttribute_ShouldRecordModification()
    {
        // Arrange
        var mockConnection = new MockLdapPersistentConnectionAdapter();
        var factory = new MockLdapPersistentConnectionFactoryAdapter();
        
        var connectionInfo = new ConnectionInfo("localhost", 389, false, 10);
        var searchLimits = new SearchLimits("DC=example,DC=com");
        var adminCreds = new LDAPDomainAccountCredential("EXAMPLE", "admin", "pass");

        var accountManager = new AccountManager(connectionInfo, searchLimits, adminCreds, factory);

        var userDn = "CN=Bob Jones,OU=Users,DC=example,DC=com";
        var modifications = new List<ILdapModificationAdapter>
        {
            new MockLdapModificationAdapter(LdapModificationType.Replace, "telephoneNumber", "+1-555-0199")
        };

        // Act
        await accountManager.ModifyEntryAsync(userDn, modifications);

        // Assert
        Assert.Single(mockConnection.Modifications);
        var recordedMod = mockConnection.Modifications[0];
        Assert.Equal(userDn, recordedMod.DistinguishedName);
        Assert.Equal("telephoneNumber", recordedMod.AttributeName);
        Assert.Equal("+1-555-0199", recordedMod.Value);
    }
}

Data Store & Seeding Infrastructure

MockLdapDataStore

MockLdapDataStore is a thread-safe singleton managing the in-memory LDAP hierarchy for persistent mock connections.

  • Thread-Safety: Operations are protected by ReaderWriterLockSlim.
  • Case-Insensitive Keys: Distinguished names are indexed using StringComparer.OrdinalIgnoreCase.
  • API Surface:
    • AddOrUpdateEntry(MockLdapEntryAdapter entry)
    • GetEntry(string distinguishedName)
    • SearchEntries(Func<MockLdapEntryAdapter, bool> predicate)
    • RemoveEntry(string distinguishedName)
    • GetAllEntries()
    • Clear()
    • Count

MockLdapDataSeeder

MockLdapDataSeeder generates a complete, realistic directory structure inside MockLdapDataStore.

Seeding Operations Executed by SeedAllData()
  1. Domain Structure: Seeds root domain DC=domain,DC=com.
  2. Organizational Units: OU=Users, OU=Groups, OU=Computers, OU=IT, OU=HR, OU=Finance.
  3. Standard Users: Generates standard accounts with attributes (cn, sAMAccountName, userPrincipalName, mail, givenName, sn, objectSid, userAccountControl).
  4. Security Groups: Seeds domain groups (Domain Admins, Domain Users, VPN Users, HR Staff, Finance Managers).
  5. Computer Objects: Seeds workstation and server entries.
  6. Group Memberships: Links users to groups (member and memberOf attributes).
  7. RID Allocation: Thread-safe RID counters starting at:
    • Users: 1000
    • Groups: 2000
    • Computers: 3000
    • Other Objects: 4000

Build, Test & Package

Prerequisites

  • .NET SDK 10.0 or newer installed.
  • PowerShell or standard Linux/macOS command shell.

Building the Project

dotnet build adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock.csproj -c Release

Running the Test Suite

Run the full repository test suite that consumes LdapHelperMock:

dotnet test tests/Bitai.LDAPHelper.Tests/Bitai.LDAPHelper.Tests.csproj -c Release

Creating the NuGet Package

dotnet pack adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock.csproj -c Release -o ./artifacts

Observability & Diagnostic Assertions

When debugging unit or integration tests, MockLdapPersistentConnectionAdapter provides diagnostic tracking properties:

// Inspect entries created during the test run
List<MockLdapEntryAdapter> created = mockConnection.CreatedEntries;

// Inspect all entry modifications executed
List<MockModification> mods = mockConnection.Modifications;

// Inspect deleted distinguished names
List<string> deleted = mockConnection.DeletedEntries;

MockLdapDataSeeder accepts an ILogger<MockLdapDataSeeder> parameter, emitting structured log statements during data population for full visibility in console outputs or test runner logs.


Troubleshooting

Issue / Symptom Probable Cause Recommended Fix
ConnectAsync throws Invalid server connection! host parameter is empty, "unknown", or "0.0.0.0", or port <= 0. Provide a valid non-empty host string and positive port number (e.g. "localhost", 389).
BindAsync throws Invalid credentials! Credentials contain "hacker" or "123456", or are null/empty. Use valid non-blacklisted mock credentials.
SearchAsync returns empty results in standard mode The filter string was not registered via AddSearchResult. Call mockConnection.AddSearchResult(filterPattern, entries) before executing queries.
Search returns empty results in persistent mode MockLdapDataSeeder was not executed, or filter attribute is unsupported. Execute seeder.SeedAllData() prior to testing. Ensure filter matches supported attributes (sAMAccountName, distinguishedName, cn, objectSid, objectClass).
ServerCertificateValidationByPass throws InvalidOperationException Method called on mock class. Certificate validation bypass is not applicable in mock mode. Remove call in test setups.

Security & Operational Guidance

  • Mock Credentials: Never hardcode or commit production passwords or sensitive Active Directory credentials into test scripts or seeder logic.
  • Deterministic Testing: Use fixed seeds or reset MockLdapDataStore.Instance.Clear() between tests to prevent inter-test state contamination.
  • Non-Production Purpose: This package is explicitly designed for testing, CI/CD, and local prototyping. Do not deploy mock adapters to production environments.

License

This project is licensed under the MIT License. See LICENSE.md for details.

© 2026 BITAI. All rights reserved.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.2.0 98 10/1/2026
10.0.0 138 7/21/2026