Infrastructure

Deming ISMS — Déploiement Docker, LDAP et correction de bugs upstream

Déploiement de l'outil ISMS Deming sur Docker avec authentification LDAP Active Directory — deux bugs découverts, corrigés et mergés en upstream (PR #688 et #690).

Table des matières

Deming est un outil open source de gestion de la conformité ISMS (ISO 27001) développé par sourcentis. Ce guide couvre son déploiement Docker complet avec LDAP, les deux bugs rencontrés et leur correction upstream.

Déploiement Docker

# docker-compose.yml
services:
  deming:
    image: sourcentis/deming:latest
    container_name: deming
    restart: unless-stopped
    ports:
      - "8080:80"
    environment:
      APP_ENV: production
      APP_KEY: ${APP_KEY}
      DB_HOST: mariadb
      DB_DATABASE: deming
      DB_USERNAME: deming
      DB_PASSWORD: ${DB_PASSWORD}
      LDAP_HOST: ${LDAP_HOST}
      LDAP_PORT: 389
      LDAP_BASE_DN: ${LDAP_BASE_DN}
      LDAP_USERNAME: ${LDAP_USERNAME}
      LDAP_PASSWORD: ${LDAP_PASSWORD}
    volumes:
      - deming_storage:/var/www/html/storage
    depends_on:
      - mariadb

  mariadb:
    image: mariadb:10.11
    container_name: deming-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: deming
      MYSQL_USER: deming
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - deming_db:/var/lib/mysql

volumes:
  deming_storage:
  deming_db:
# Générer la clé APP Laravel
docker compose run --rm deming php artisan key:generate --show
# Copier la valeur dans .env

docker compose up -d
docker compose exec deming php artisan migrate --force

Bug #1 — Filtre LDAP AND/OR incorrect

Symptôme

L’authentification LDAP échoue avec des attributs multiples :

LDAP Error: Invalid filter syntax
ldap_search(): Search: Bad search filter

Cause

Le filtre LDAP généré était syntaxiquement incorrect lors de l’utilisation de plusieurs attributs d’identification (ex: sAMAccountName ET mail) :

// Code original (bugué)
// Génère : (&(objectClass=user)(attr1=val)(attr2=val))
// Correct pour 1 attr, INVALIDE pour plusieurs en OR
$filter = "(&(objectClass=user)" . implode('', $conditions) . ")";

Le filtre correct pour plusieurs attributs en OR doit encapsuler dans (|...) :

// Pour 1 attribut :  (&(objectClass=user)(sAMAccountName=foo))       ✅
// Pour plusieurs :   (&(objectClass=user)(|(sAMAccountName=foo)(mail=foo@bar.com)))  ✅
// Généré (bugué) :   (&(objectClass=user)(sAMAccountName=foo)(mail=foo@bar.com))    ❌

Fix (PR #688)

// Après correction
if (count($conditions) > 1) {
    $filter = "(&(objectClass=user)(|" . implode('', $conditions) . "))";
} else {
    $filter = "(&(objectClass=user)" . $conditions[0] . ")";
}

Bug #2 — Email auto-provision hardcodé à null

Symptôme

À la première connexion d’un utilisateur LDAP non encore en base, l’auto-provisionnement échoue :

SQLSTATE[23000]: Integrity constraint violation:
1062 Duplicate entry 'null' for key 'users_email_unique'

Cause

Le code récupérait l’attribut mail depuis LDAP, mais en cas d’absence (compte de service, compte sans email configuré), il fallait à null hardcodé plutôt qu’utiliser le sAMAccountName comme fallback :

// Code original (bugué)
$email = $ldapUser->getAttribute('mail')[0] ?? null;
// → null si pas de mail → contrainte unique violée au second utilisateur sans mail

Fix (PR #690)

// Après correction — fallback sur sAMAccountName@domaine
$defaultDomain = config('ldap.default_domain', 'domain.local');
$email = $ldapUser->getAttribute('mail')[0]
      ?? ($ldapUser->getAttribute('sAMAccountName')[0] . '@' . $defaultDomain)
      ?? null;

Tester la connexion LDAP

# Depuis le conteneur
docker exec -it deming ldapsearch \
  -H ldap://DC_IP \
  -D "CN=svc-compte,OU=Services,DC=domain,DC=local" \
  -w PASS \
  -b "DC=domain,DC=local" \
  "(sAMAccountName=testuser)" \
  sAMAccountName mail displayName

# Tester le filtre corrigé manuellement
docker exec -it deming ldapsearch \
  -H ldap://DC_IP \
  -D "CN=svc-compte,OU=Services,DC=domain,DC=local" \
  -w PASS \
  -b "DC=domain,DC=local" \
  "(&(objectClass=user)(|(sAMAccountName=testuser)(mail=test@domain.local)))"

Contribuer le fix upstream

# Fork + clone
git clone https://github.com/VOTRE_FORK/deming.git
cd deming
git checkout -b fix/ldap-filter-and-or

# Modifier le code (voir fixes ci-dessus)
# ...

git add .
git commit -m "Fix LDAP login filter incorrect AND/OR grouping with multiple attributes"
git push origin fix/ldap-filter-and-or
# → Ouvrir la PR sur github.com/sourcentis/deming

Les deux PRs ont été mergées dans la version 2026.06.16 :

  • PR #688 — Fix LDAP login filter AND/OR grouping
  • PR #690 — Fix hardcoded LDAP auto-provision email fallback
Open source

Contribuer upstream profite à toute la communauté. Si vous trouvez un bug en déployant un projet open source, prenez 30 minutes pour soumettre une PR — c’est souvent simple et très apprécié.

Configuration HAProxy

backend deming_backend
    option forwardfor
    option http-server-close
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    timeout tunnel 1h
    server deming 192.168.x.x:8080 check

Comments