Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
root = true

# =========================================================
# GLOBAL DEFAULTS (apply to all files)
# =========================================================
[*]
indent_style = space
indent_size = 4
tab_width = 4
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

# =========================================================
# C# (Visual Studio, .NET APIs, microservices)
# =========================================================
[*.cs]
indent_style = space
indent_size = 4
dotnet_sort_system_directives_first = true
csharp_new_line_before_open_brace = all

# =========================================================
# Java (Spring Boot microservices, shared libs)
# =========================================================
[*.java]
indent_style = space
indent_size = 4

# =========================================================
# Python (ML scripts, utilities, automation)
# =========================================================
[*.py]
indent_style = space
indent_size = 4
max_line_length = 120

# =========================================================
# JavaScript / TypeScript (React, Angular)
# =========================================================
[*.js]
indent_size = 2

[*.jsx]
indent_size = 2

[*.ts]
indent_size = 2

[*.tsx]
indent_size = 2

# =========================================================
# HTML / CSS / SCSS (UI templates)
# =========================================================
[*.html]
indent_size = 2

[*.css]
indent_size = 2

[*.scss]
indent_size = 2

# =========================================================
# JSON / YAML / XML (configs, pipelines, manifests)
# =========================================================
[*.json]
indent_size = 2

[*.yml]
indent_size = 2

[*.yaml]
indent_size = 2

[*.xml]
indent_size = 2

# =========================================================
# Dockerfiles
# =========================================================
[Dockerfile]
indent_style = space
indent_size = 4

# =========================================================
# Shell scripts
# =========================================================
[*.sh]
indent_style = space
indent_size = 2
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI

on:
push:
pull_request:
merge_group:
workflow_dispatch:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
build-test:
runs-on: ubuntu-latest
env:
DOTNET_NOLOGO: true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true

steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
cache: true
cache-dependency-path: |
**/*.csproj
**/*.fsproj
**/*.props
**/*.targets
**/nuget.config
global.json
Directory.Packages.props

- name: dotnet info
run: dotnet --info

- name: Restore
run: dotnet restore Bitai.Ldap.Helper.sln

- name: Build
run: dotnet build Bitai.Ldap.Helper.sln --configuration Release --no-restore

- name: Test
run: dotnet test Bitai.Ldap.Helper.sln --configuration Release --no-build --no-restore --verbosity normal
4 changes: 2 additions & 2 deletions LDAP Helper Libraries.sln → Bitai.Ldap.Helper.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33213.308
# Visual Studio Version 18
VisualStudioVersion = 18.6.11822.322 stable
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bitai.LDAPHelper.DTO", "src\Bitai.LDAPHelper.DTO\Bitai.LDAPHelper.DTO.csproj", "{2386A126-F237-43FD-9A7C-FDF6718ACAD7}"
EndProject
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Bitai.LDAPHelper ![Logo](resources/hierarchy_32.png)

A high-performance **.NET 8.0** library wrapping **Novell.Directory.Ldap.NETStandard** functionality to interact with LDAP-compliant Directory Services (such as Microsoft Active Directory). It simplifies operations like searching, authenticating users, and creating, modifying, disabling, or deleting accounts.
A high-performance library wrapping **Novell.Directory.Ldap.NETStandard** functionality to interact with LDAP-compliant Directory Services (such as Microsoft Active Directory). It simplifies operations like searching, authenticating users, and creating, modifying, disabling, or deleting accounts.

This library is a key component of the [Bitai.LDAPWebApi](https://github.com/bitai-cs/LDAPWebApi) solution ecosystem.

Expand All @@ -12,16 +12,16 @@ The library is organized into specialized helper classes targeting specific dire

### 🛡️ 1. Authentication (`Authenticator`)
Enables quick and secure validation of user credentials on the LDAP/AD server.
- Supports both **User Distinguished Name (DN)** (`LDAPDistinguishedNameCredential`) and **Domain Account Name** (`LDAPDomainAccountCredential`) credential structures.
- Supports both **User Distinguished Name (DN)** (`LDAPDistinguishedNameCredential`) and **Domain Username** (`LDAPDomainAccountCredential`) credential structures.
- Provides a simple authentication bind check (`AuthenticateAsync(credential)`).
- Provides a comprehensive, pre-validated authentication workflow that first searches the user entry in Active Directory to ensure uniqueness and validity before attempting the bind (`AuthenticateAsync(credential, searchLimits, searchCredential)`).

### 👤 2. Account Management (`AccountManager`)
Simplifies user provisioning and lifecycle management within Active Directory.
- **Create User Accounts** (`CreateUserAccountForMsAD`): Provision new Active Directory entries (`LDAPMsADUserAccount`) with extensive attribute mappings (such as UPN, sAMAccountName, unicodePwd, department, memberOf, object classes, and user control flags).
- **Create MS AD User Accounts** (`CreateUserAccountForMsAD`): Provision new Active Directory entries (`LDAPMsADUserAccount`) with extensive attribute mappings (such as UPN, sAMAccountName, unicodePwd, department, memberOf, object classes, and user control flags).
- **Set/Change Passwords** (`SetUserAccountPasswordForMsAD`): Safe password replacement utilizing secure Unicode encoding. It can optionally test immediate post-update authentication.
- **Disable Accounts** (`DisableUserAccountForMsAD`): Securely disables accounts by updating the `userAccountControl` attribute with the `ACCOUNTDISABLE` flag, dynamically preserving all other existing account flags to prevent unintended configuration loss.
- **Remove Accounts** (`RemoveUserAccountForMsAD`): Permanently deletes user entries from the directory service.
- **Disable MS AD Accounts** (`DisableUserAccountForMsAD`): Securely disables accounts by updating the `userAccountControl` attribute with the `ACCOUNTDISABLE` flag, dynamically preserving all other existing account flags to prevent unintended configuration loss.
- **Remove MS AD Accounts** (`RemoveUserAccountForMsAD`): Permanently deletes user entries from the directory service.

### 🔍 3. Directory Searching (`Searcher`)
Facilitates fast, flexible searching using highly customizable LDAP search configurations.
Expand Down Expand Up @@ -49,7 +49,7 @@ The solution `LDAP Helper Libraries.sln` consists of the following projects:

## ⚙️ Requirements & Dependencies

- **.NET 8.0 SDK** or higher.
- **.NET 10 SDK** or higher.
- **Novell.Directory.Ldap.NETStandard** (v4.0.0+) package dependency.

---
Expand Down
18 changes: 9 additions & 9 deletions demo/Bitai.LDAPHelper.Demo/Bitai.LDAPHelper.Demo.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>Bitai.LDAPHelper.Demo</RootNamespace>
<Authors>Viko Bastidas (BITAI)</Authors>
<Company>BITAI</Company>
Expand All @@ -10,17 +10,17 @@
<Copyright>© 2026 BITAI. All rights reserved.</Copyright>
<PackageId>Bitai.Bitai.LDAPHelper.Demo</PackageId>
<PackageIcon>hierarchy_32.png</PackageIcon>
<Version>8.6.0</Version>
<AssemblyVersion>8.6.0.0</AssemblyVersion>
<FileVersion>8.6.0.0</FileVersion>
<PackageReleaseNotes>.NET 8 ready</PackageReleaseNotes>
<Version>10.0.0</Version>
<AssemblyVersion>10.0.0</AssemblyVersion>
<FileVersion>10.0.0</FileVersion>
<PackageReleaseNotes>.NET 10 ready</PackageReleaseNotes>
<PackageTags>ldap-ad-identity-auth-openid-oauth-security</PackageTags>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.8" />
<PackageReference Include="Serilog" Version="4.3.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageReference Include="Spectre.Console" Version="0.55.2" />
</ItemGroup>
<ItemGroup>
Expand Down
14 changes: 7 additions & 7 deletions demo/Bitai.LDAPHelper.Demo/Program.DemoMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static async Task Demo_Authenticator_Authenticate_Simple(DemoContext cont

var domainAccountCredentialParts = domainAccountCredential.Split(new char[] { '\\' });

Log.Information("Authenticating account name...");
Log.Information("Authenticating domain username...");
var authenticationResult = await authenticator.AuthenticateAsync(
new LDAPDomainAccountCredential(domainAccountCredentialParts[0], domainAccountCredentialParts[1], accountPassword),
context.RequestLabel);
Expand All @@ -33,9 +33,9 @@ public static async Task Demo_Authenticator_Authenticate_Simple(DemoContext cont
Log.Information("{@model}", authenticationResult);

if (authenticationResult.IsAuthenticated)
Log.Information("Account name authenticated.");
Log.Information("Username authenticated.");
else
Log.Warning("Account name NOT authenticated.");
Log.Warning("Username NOT authenticated.");
}
else
{
Expand All @@ -58,7 +58,7 @@ public static async Task Demo_Authenticator_Authenticate_WithAccountValidation(D

var domainAccountCredentialParts = domainAccountCredential.Split(new char[] { '\\' });

Log.Information("Authenticating account name with account validation...");
Log.Information("Authenticating username with account validation...");
var authenticationResult = await authenticator.AuthenticateAsync(
new LDAPDomainAccountCredential(domainAccountCredentialParts[0], domainAccountCredentialParts[1], accountPassword),
context.GetSearchLimits(),
Expand All @@ -70,9 +70,9 @@ public static async Task Demo_Authenticator_Authenticate_WithAccountValidation(D
Log.Information("{@model}", authenticationResult);

if (authenticationResult.IsAuthenticated)
Log.Information("Account name authenticated.");
Log.Information("Username authenticated.");
else
Log.Warning("Account name NOT authenticated.");
Log.Warning("Username NOT authenticated.");
}
else
{
Expand Down Expand Up @@ -488,4 +488,4 @@ public static async Task Demo_GroupMembershipValidator_CheckGroupMembership(
}

#endregion
}
}
10 changes: 5 additions & 5 deletions src/Bitai.LDAPHelper.DTO/Bitai.LDAPHelper.DTO.csproj
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AssemblyVersion>8.6.0.0</AssemblyVersion>
<FileVersion>8.6.0.0</FileVersion>
<Version>8.6.0</Version>
<TargetFramework>net10.0</TargetFramework>
<AssemblyVersion>10.0.0</AssemblyVersion>
<FileVersion>10.0.0</FileVersion>
<Version>10.0.0</Version>
<AssemblyName>Bitai.LDAPHelper.DTO</AssemblyName>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>Viko Bastidas (BITAI)</Authors>
Expand All @@ -21,7 +21,7 @@
<RepositoryType>GitHub</RepositoryType>
<PackageTags>ldap, authentication, directory, helper</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReleaseNotes>.NET 8 ready</PackageReleaseNotes>
<PackageReleaseNotes>.NET 10 ready</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/Bitai.LDAPHelper.DTO/LDAPDistinguishedNameCredential.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand Down Expand Up @@ -32,7 +32,7 @@ public LDAPDistinguishedNameCredential()
public LDAPDistinguishedNameCredential(string distinguishedName, string password)
{
if (string.IsNullOrEmpty(distinguishedName))
throw new InvalidOperationException("The account name must be specified.");
throw new InvalidOperationException("A distinguished name is required: the account’s DN must be specified.");

DistinguishedName = distinguishedName;
Password = password;
Expand Down
14 changes: 7 additions & 7 deletions src/Bitai.LDAPHelper.DTO/LDAPDomainAccountCredential.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
Expand Down Expand Up @@ -28,21 +28,21 @@ public LDAPDomainAccountCredential()
/// <summary>
/// Constructor
/// </summary>
/// <param name="domainName">Domain name.</param>
/// <param name="accountName">Account name.</param>
/// <param name="domainName">Domain name</param>
/// <param name="username">Username</param>
/// <param name="domainAccountPassword">Account password.</param>
/// <exception cref="InvalidOperationException">Constructor exception.</exception>
public LDAPDomainAccountCredential(string domainName, string accountName, string domainAccountPassword)
public LDAPDomainAccountCredential(string domainName, string username, string domainAccountPassword)
{
if (string.IsNullOrEmpty(domainName))
throw new InvalidOperationException("The domain name must be specified.");

if (string.IsNullOrEmpty(accountName))
throw new InvalidOperationException("The account name must be specified.");
if (string.IsNullOrEmpty(username))
throw new InvalidOperationException("The username must be specified.");


DomainName = domainName;
AccountName = accountName;
AccountName = username;
DomainAccountPassword = domainAccountPassword;
}

Expand Down
Loading
Loading