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=*)"
"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 orchestrationconfig/appsettings.json- Cesivi configurationdata/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¶
- Try Tutorial A for OAuth2 authentication
- Try Tutorial E for simplified Docker setup
- Read NTLM Setup Guide for more NTLM options