Skip to content

Tutorial B: Cesivi + dev-ldap + LiteDB on Docker

Overview

This tutorial guides you through setting up Cesivi Server with: - Authentication: NTLM with LDAP/Active Directory backend (via dev-ldap) - Storage: LiteDB (embedded NoSQL database) - Platform: Docker containers

Use Case: Enterprise development environment simulating Active Directory authentication with document-based storage.

Time Required: ~20 minutes


Prerequisites

  • Docker Desktop installed (Windows, Mac, or Linux)
  • Docker Compose (included with Docker Desktop)
  • Basic familiarity with Docker commands

Architecture

┌─────────────────────────────────────────────────────────────┐
│                      Docker Network                          │
│                                                              │
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────┐ │
│  │   dev-ldap   │     │ SharePoint   │     │   LiteDB     │ │
│  │   (LDAP)     │◄────│    Mock      │────►│  (Volume)    │ │
│  │   :389       │     │   :8080      │     │              │ │
│  └──────────────┘     └──────────────┘     └──────────────┘ │
│                              │                               │
└──────────────────────────────┼───────────────────────────────┘
                               │
                        Host: localhost:8080

Step 1: Create Project Directory

# Create tutorial directory
mkdir -p ~/cesivi-tutorial-b
cd ~/cesivi-tutorial-b

# Create subdirectories
mkdir -p data logs config

Step 2: Create dev-ldap Configuration

Create config/ldap-users.json with sample users:

{
  "baseDN": "dc=contoso,dc=com",
  "users": [
    {
      "dn": "cn=administrator,ou=users,dc=contoso,dc=com",
      "attributes": {
        "cn": "administrator",
        "sAMAccountName": "administrator",
        "userPrincipalName": "administrator@contoso.com",
        "mail": "admin@contoso.com",
        "displayName": "SharePoint Administrator",
        "memberOf": ["cn=Administrators,ou=groups,dc=contoso,dc=com", "cn=Site Owners,ou=groups,dc=contoso,dc=com"]
      },
      "password": "Admin@123"
    },
    {
      "dn": "cn=testuser,ou=users,dc=contoso,dc=com",
      "attributes": {
        "cn": "testuser",
        "sAMAccountName": "testuser",
        "userPrincipalName": "testuser@contoso.com",
        "mail": "testuser@contoso.com",
        "displayName": "Test User",
        "memberOf": ["cn=Users,ou=groups,dc=contoso,dc=com", "cn=Contributors,ou=groups,dc=contoso,dc=com"]
      },
      "password": "Test@123"
    },
    {
      "dn": "cn=reader,ou=users,dc=contoso,dc=com",
      "attributes": {
        "cn": "reader",
        "sAMAccountName": "reader",
        "userPrincipalName": "reader@contoso.com",
        "mail": "reader@contoso.com",
        "displayName": "Read Only User",
        "memberOf": ["cn=Visitors,ou=groups,dc=contoso,dc=com"]
      },
      "password": "Read@123"
    }
  ],
  "groups": [
    {
      "dn": "cn=Administrators,ou=groups,dc=contoso,dc=com",
      "attributes": {
        "cn": "Administrators",
        "description": "Full control administrators"
      }
    },
    {
      "dn": "cn=Site Owners,ou=groups,dc=contoso,dc=com",
      "attributes": {
        "cn": "Site Owners",
        "description": "Site collection owners"
      }
    },
    {
      "dn": "cn=Contributors,ou=groups,dc=contoso,dc=com",
      "attributes": {
        "cn": "Contributors",
        "description": "Can add, edit, and delete items"
      }
    },
    {
      "dn": "cn=Visitors,ou=groups,dc=contoso,dc=com",
      "attributes": {
        "cn": "Visitors",
        "description": "Read-only access"
      }
    }
  ]
}

Step 3: Create Cesivi Configuration

Create config/appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Cesivi": "Debug",
      "Cesivi.Common.Identity": "Debug"
    },
    "Console": {
      "FormatterName": "json",
      "FormatterOptions": {
        "SingleLine": true,
        "IncludeScopes": true
      }
    }
  },
  "Cesivi": {
    "DataRootPath": "/data",
    "LogPath": "/data/logs",
    "HostName": "localhost",
    "UseHttps": false,
    "HttpPort": 8080,

    "StorageProvider": "LiteDb",
    "LiteDbPath": "/data/sharepoint.litedb",

    "SearchEngine": "TfIdf",

    "Identity": {
      "Providers": {
        "NTLM": {
          "Enabled": true,
          "Priority": 100,
          "Backend": "ActiveDirectory",
          "ActiveDirectory": {
            "Server": "dev-ldap",
            "Port": 389,
            "UseSsl": false,
            "BaseDN": "dc=contoso,dc=com",
            "UserSearchBase": "ou=users,dc=contoso,dc=com",
            "GroupSearchBase": "ou=groups,dc=contoso,dc=com",
            "BindDN": "cn=admin,dc=contoso,dc=com",
            "BindPassword": "adminpass",
            "UserFilter": "(sAMAccountName={0})",
            "GroupFilter": "(member={0})"
          }
        },
        "AcceptAll": {
          "Enabled": true,
          "Priority": 1000,
          "DefaultUsername": "CONTOSO\\administrator"
        }
      }
    },

    "Authentication": {
      "AcceptAllCredentials": false,
      "AllowAnonymous": false,
      "EnableNTLM": true,
      "EnableJWT": false,
      "EnableBasic": true
    }
  }
}

Step 4: Create Docker Compose File

Create docker-compose.yml:

version: '3.8'

services:
  # Development LDAP server
  dev-ldap:
    image: osixia/openldap:1.5.0
    container_name: dev-ldap
    environment:
      LDAP_ORGANISATION: "Contoso Corporation"
      LDAP_DOMAIN: "contoso.com"
      LDAP_ADMIN_PASSWORD: "adminpass"
      LDAP_CONFIG_PASSWORD: "configpass"
      LDAP_BASE_DN: "dc=contoso,dc=com"
    volumes:
      - ldap-data:/var/lib/ldap
      - ldap-config:/etc/ldap/slapd.d
    ports:
      - "389:389"
      - "636:636"
    networks:
      - sharepoint-net
    healthcheck:
      test: ["CMD", "ldapsearch", "-x", "-H", "ldap://localhost", "-b", "dc=contoso,dc=com", "-D", "cn=admin,dc=contoso,dc=com", "-w", "adminpass"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 30s

  # LDAP admin UI (optional, for debugging)
  ldap-admin:
    image: osixia/phpldapadmin:0.9.0
    container_name: ldap-admin
    environment:
      PHPLDAPADMIN_LDAP_HOSTS: dev-ldap
      PHPLDAPADMIN_HTTPS: "false"
    ports:
      - "8081:80"
    networks:
      - sharepoint-net
    depends_on:
      - dev-ldap

  # Cesivi Server
  cesivi:
    build:
      context: ../../  # Adjust path to Cesivi2 root
      dockerfile: Dockerfile
    container_name: cesivi
    environment:
      ASPNETCORE_ENVIRONMENT: Docker
      Cesivi__StorageProvider: LiteDb
      Cesivi__LiteDbPath: /data/sharepoint.litedb
      Cesivi__SearchEngine: TfIdf
    volumes:
      - ./data:/data
      - ./logs:/data/logs
      - ./config/appsettings.json:/app/appsettings.Docker.json:ro
    ports:
      - "8080:8080"
    networks:
      - sharepoint-net
    depends_on:
      dev-ldap:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/_vti_bin/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

networks:
  sharepoint-net:
    driver: bridge

volumes:
  ldap-data:
  ldap-config:

Step 5: Create LDAP Seed Script

Create scripts/seed-ldap.sh:

#!/bin/bash

# Wait for LDAP to be ready
sleep 10

# Add organizational units
ldapadd -x -H ldap://dev-ldap -D "cn=admin,dc=contoso,dc=com" -w adminpass << EOF
dn: ou=users,dc=contoso,dc=com
objectClass: organizationalUnit
ou: users

dn: ou=groups,dc=contoso,dc=com
objectClass: organizationalUnit
ou: groups
EOF

# Add users
ldapadd -x -H ldap://dev-ldap -D "cn=admin,dc=contoso,dc=com" -w adminpass << EOF
dn: cn=administrator,ou=users,dc=contoso,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
cn: administrator
sn: Administrator
uid: administrator
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/administrator
userPassword: Admin@123
mail: admin@contoso.com
displayName: SharePoint Administrator

dn: cn=testuser,ou=users,dc=contoso,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
cn: testuser
sn: User
uid: testuser
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/testuser
userPassword: Test@123
mail: testuser@contoso.com
displayName: Test User

dn: cn=reader,ou=users,dc=contoso,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
cn: reader
sn: Reader
uid: reader
uidNumber: 1002
gidNumber: 1002
homeDirectory: /home/reader
userPassword: Read@123
mail: reader@contoso.com
displayName: Read Only User
EOF

# Add groups
ldapadd -x -H ldap://dev-ldap -D "cn=admin,dc=contoso,dc=com" -w adminpass << EOF
dn: cn=Administrators,ou=groups,dc=contoso,dc=com
objectClass: groupOfNames
cn: Administrators
member: cn=administrator,ou=users,dc=contoso,dc=com

dn: cn=Contributors,ou=groups,dc=contoso,dc=com
objectClass: groupOfNames
cn: Contributors
member: cn=testuser,ou=users,dc=contoso,dc=com

dn: cn=Visitors,ou=groups,dc=contoso,dc=com
objectClass: groupOfNames
cn: Visitors
member: cn=reader,ou=users,dc=contoso,dc=com
EOF

echo "LDAP seeded successfully!"

Make it executable:

chmod +x scripts/seed-ldap.sh


Step 6: Start the Services

# Build and start all containers
docker-compose up -d

# Check status
docker-compose ps

# View logs
docker-compose logs -f cesivi

Wait for all services to be healthy:

# Check health status
docker inspect cesivi | jq '.[0].State.Health.Status'


Step 7: Seed LDAP with Users

# Run the seed script (from host, or exec into a container)
docker exec -it dev-ldap bash -c '
ldapadd -x -H ldap://localhost -D "cn=admin,dc=contoso,dc=com" -w adminpass << EOF
dn: ou=users,dc=contoso,dc=com
objectClass: organizationalUnit
ou: users
EOF
'

# Or use phpLDAPadmin
# Open http://localhost:8081
# Login: cn=admin,dc=contoso,dc=com / adminpass
# Add users through the UI

Step 8: Test NTLM Authentication

Using curl with NTLM

# Test with NTLM authentication
curl --ntlm -u "CONTOSO\\administrator:Admin@123" \
  http://localhost:8080/_api/web \
  -H "Accept: application/json;odata=verbose"

Using PowerShell

# Test from Windows host
$cred = New-Object System.Management.Automation.PSCredential(
    "CONTOSO\administrator",
    (ConvertTo-SecureString "Admin@123" -AsPlainText -Force)
)

Invoke-RestMethod -Uri "http://localhost:8080/_api/web" `
    -Credential $cred `
    -Headers @{ "Accept" = "application/json;odata=verbose" }

Step 9: Verify LiteDB Storage

LiteDB stores data in a single file. You can inspect it:

# Check the database file
docker exec cesivi ls -la /data/

# The file sharepoint.litedb contains all data

Access LiteDB from Host

# Copy database to host for inspection
docker cp cesivi:/data/sharepoint.litedb ./data/

# Use LiteDB Studio (download from https://github.com/mbdavid/LiteDB.Studio)

Step 10: Test CSOM with NTLM (Windows Host)

using Microsoft.SharePoint.Client;
using System.Net;

var context = new ClientContext("http://localhost:8080");
context.Credentials = new NetworkCredential(
    "administrator",
    "Admin@123",
    "CONTOSO"
);

var web = context.Web;
context.Load(web, w => w.Title, w => w.Url, w => w.CurrentUser);
context.ExecuteQuery();

Console.WriteLine($"Web Title: {web.Title}");
Console.WriteLine($"Web URL: {web.Url}");
Console.WriteLine($"Current User: {web.CurrentUser.Title}");

Step 11: Create Test Data

# Create a list via REST API
curl --ntlm -u "CONTOSO\\administrator:Admin@123" \
  -X POST \
  http://localhost:8080/_api/web/lists \
  -H "Accept: application/json;odata=verbose" \
  -H "Content-Type: application/json;odata=verbose" \
  -d '{
    "__metadata": { "type": "SP.List" },
    "Title": "Docker Test List",
    "BaseTemplate": 100
  }'

Troubleshooting

"LDAP connection refused"

Cause: dev-ldap container not ready

Solution:

# Check container status
docker-compose ps

# View LDAP logs
docker-compose logs dev-ldap

# Wait for health check
docker inspect dev-ldap | jq '.[0].State.Health'

"NTLM authentication failed"

Cause: User not found in LDAP or wrong credentials

Solution: 1. Check LDAP contains users:

docker exec dev-ldap ldapsearch -x -H ldap://localhost \
  -D "cn=admin,dc=contoso,dc=com" -w adminpass \
  -b "ou=users,dc=contoso,dc=com" "(objectClass=*)"
2. Use phpLDAPadmin (http://localhost:8081) to browse users 3. Check Cesivi logs for NTLM negotiation details

"LiteDB file not created"

Cause: Volume mount permissions

Solution:

# Check permissions
ls -la ./data/

# Fix permissions (Linux/Mac)
chmod 777 ./data/

# Restart container
docker-compose restart cesivi


Clean Up

# Stop all containers
docker-compose down

# Remove volumes (deletes all data!)
docker-compose down -v

# Remove images
docker-compose down --rmi all

# Clean up directory
rm -rf ~/cesivi-tutorial-b

Summary

You have successfully set up: - dev-ldap (OpenLDAP) as your LDAP directory - LiteDB as your NoSQL storage backend - Cesivi Server in Docker with NTLM authentication

Services Running

Service URL Purpose
Cesivi http://localhost:8080 Main API
phpLDAPadmin http://localhost:8081 LDAP management UI
OpenLDAP localhost:389 LDAP directory

Key Files Created

  • docker-compose.yml - Container orchestration
  • config/appsettings.json - Cesivi configuration
  • data/sharepoint.litedb - LiteDB database

Test Users

Username Password Role
CONTOSO\administrator Admin@123 Full Control
CONTOSO\testuser Test@123 Contributor
CONTOSO\reader Read@123 Visitor

Next Steps


See Also