aaieduhr/aosi-module-libldifmanip

AOSI LibLdifManip Module

Maintainers

Package info

gitlab.opencode.hr/srce/aai-eduhr/aosi/aosi-module-libldifmanip

Type:aosi-module

pkg:composer/aaieduhr/aosi-module-libldifmanip

Statistics

Installs: 18

Dependents: 2

Suggesters: 0

v5.0.0 2026-04-14 10:56 UTC

This package is auto-updated.

Last update: 2026-04-14 10:58:11 UTC


README

Ovaj modul sluša AOSI evente za dodavanje/brisanje korisnika i promjene atributa te na temelju toga generira LDIF zapise. Zapisi se appendaju u LDIF datoteke u data/LDIFSync, po realm-u. Ideja je da drugi modul (LDIFSync) kasnije preuzima te datoteke i odrađuje sinkronizaciju.

Modul je "headless": nema sučelje, nema menu stavke i ne izbacuje SOAP API.

Funkcionalnost

  • AfterAddUser: zapisuje changetype: add za korisnika; ako nema objectClass, dodaje defaultnu listu (person, organizationalPerson, inetOrgPerson, hrEduPerson, schacContactLocation).
  • AfterDeleteUser: zapisuje changetype: delete.
  • AfterAddUserAttribute: zapisuje changetype: modify s add operacijama.
  • AfterModifyUserAttribute: zapisuje changetype: modify s replace operacijama.
  • AfterDeleteUserAttribute: zapisuje changetype: modify s delete operacijama.
  • Atribut jpegPhoto se preskače.
  • Base DN provjera osigurava da se zapisuju samo promjene za očekivani realm.
  • LDIF linije se foldaju prema RFC 2849 (max 76 znakova + continuation).
  • Vrijednosti koje zahtijevaju base64 (prazno, leading space, ':', newline, non-ASCII) zapisuju se s ::.
  • Kod kreiranja direktorija/upisa u datoteku provjerava se rezultat operacije. Ako kreiranje ili upis ne uspije (npr. permission problem), zapisuje se error log s putanjom i razlogom greške iz PHP-a.

Filtriranje atributa

Filtriranje se radi u dva koraka:

1) Shema: dozvoljeni su samo atributi koji postoje u LDAP shemi (dohvaćeni preko Aosi::getAllSchemaAttributeNames()), plus objectClass.
2) Allowlist: ako je definiran po profilu, predstavlja dodatni filter (podskup sheme).

Posebna pravila:

  • jpegPhoto se uvijek preskače.
  • objectClass se uvijek propušta (i kod add i kod modify).

Lokacija LDIF datoteka

Po defaultu se generiraju datoteke za profile LDIFSync i o365 (ovisno o write_profiles):

  • data/LDIFSync/LDIFSync_<realm>.ldif (profil LDIFSync)
  • data/o365connect/o365connect_<realm>.ldif (profil o365)

Naziv je usklađen sa starim Perl modulom (LDIFManip/LDIFSync). Dump datoteke koriste isti file_prefix kao i sync, ali s dodatnim suffixom _dumpAll, pa ne prepisuju standardne LDIFSync datoteke.

Konfiguracija

Konfiguracija je u config/libldifmanip.php i učitava se u ConfigInterface kao libldifmanip (load se radi u config/bootstrap.php). Najvažnije postavke:

  • libldifmanip.outputs - mapa profila izlaza (multi-file)
    • dir - direktorij unutar data/
    • file_prefix - prefiks datoteke
    • file_ext - ekstenzija
    • per_realm - dodaje li se _realm
    • allowlist - opcionalni popis atributa (dodatni filter uz shemu)
  • libldifmanip.write_profiles - profili koje listeneri zapisuju (npr. ['LDIFSync', 'o365'])
  • libldifmanip.write_profiles može biti prazno polje [] ako ne želite da listeneri ništa zapisuju.
  • libldifmanip.default_object_classes - default objectClass lista

Default profili:

  • LDIFSync - legacy profil za LDIFSync (ponašanje stare aplikacije).
  • o365 - profil prema starim o365connect.* datotekama (prefix i allowlist).

Za o365 je allowlist preuzet iz o365connectAttributes.pm (attr_map): cn, givenName, sn, hrEduPersonUniqueID, uid, hrEduPersonPersistentID, hrEduPersonPrimaryAffiliation.

Konfiguracija profila se nalazi u config/libldifmanip.php i sadrži i zakomentirani "custom" primjer koji se može kopirati i prilagoditi.

Ako libldifmanip.outputs nije definiran, modul ne zapisuje ništa.

Rotacija LDIF datoteka (logrotate)

Servis LdifRotator omogućuje rotaciju LDIF datoteka u .1/.2/... formatu. Ako je logrotate dostupna, koristi se vanjski logrotate. Ako nije (npr. macOS), koristi se PHP fallback.

Konfiguracija:

  • libldifmanip.logrotate.exe - naziv izvršne datoteke (default logrotate)
  • libldifmanip.logrotate.exe_path - PATH za traženje izvršne datoteke
  • libldifmanip.logrotate.dir - direktorij za logrotate config (default app.logs.dir)
  • libldifmanip.logrotate.file_prefix / file_ext
  • libldifmanip.logrotate.status_prefix
  • libldifmanip.logrotate.rotate - broj rotacija (default 5)
  • libldifmanip.logrotate.notifempty - preskoči rotaciju praznih datoteka
  • libldifmanip.logrotate.create_mode / create_user / create_group

Napomena: Ovaj servis koristi modul libldifsync za type=2.

Dump LDAP-a (LDIFSync type=6)

Servis LdifDumper radi potpuni izvoz LDAP zapisa u LDIF datoteku. Root/admin bind se izvodi preko core LDAP servisa (aosi-module-core), koji koristi aosi.ldap.rootdn / aosi.ldap.pass iz konfiguracije. Nakon binda, LdifDumper izravno radi LDAP pretragu i filtrira atribute prema shemi, uz dodatni allowlist ako je definiran u profilu.

Ako dump ne može kreirati direktorij, otvoriti dump datoteku ili upisati zapis, metoda vraća grešku i zapisuje detaljan error log (putanja + razlog).

Kod velikih imenika LdifDumper koristi LDAP paginaciju (page_size) kad je podržana od runtime-a i LDAP servera, kako bi se smanjila potrošnja memorije. Također koristi lock datoteku (*.lock) da spriječi paralelni dump nad istim izlazom.

Dump koristi istu konfiguraciju profila kao i sync, ali na file_prefix dodaje suffix _dumpAll. Primjer za profil LDIFSync:

  • sync: data/LDIFSync/LDIFSync_<realm>.ldif
  • dump: data/LDIFSync/LDIFSync_dumpAll_<realm>.ldif

CLI: dumpAll za bilo koji profil

U rootu modula postoji jednostavna CLI skripta:

php vendor/aaieduhr/aosi-module-libldifmanip/AosiDumpAll.php <profil> [realm]

Parametri:

  • <profil>: naziv profila iz libldifmanip.outputs (npr. LDIFSync, o365)
  • [realm]: naziv realm-a iz aosi.realm (npr. srce, intsrce)
    • realm se mapira na base DN kao dc=<realm>,dc=hr
    • ako nije zadan, koristi se defaultni realm iz konfiguracije

Primjeri:

  • php vendor/aaieduhr/aosi-module-libldifmanip/AosiDumpAll.php LDIFSync srce
  • php vendor/aaieduhr/aosi-module-libldifmanip/AosiDumpAll.php o365

<profil> mora postojati u libldifmanip.outputs. Ako realm nije zadan, koristi se defaultni realm iz konfiguracije.

CLI ispisuje strukturirani status:

  • STATUS=RUNNING - pokrenut dump za profil/realm/base
  • STATUS=OK - dump uspješno završen (ispisuje FILE i SIZE)
  • STATUS=WARNING - dump datoteka je kreirana, ali je prazna (SIZE=0)
  • STATUS=ERROR - dump nije uspio (ispisuje razlog u MESSAGE)

Exit kodovi:

  • 0 - uspjeh
  • 1 - greška
  • 2 - warning (prazna dump datoteka)

Opcije dumpa u konfiguraciji:

  • libldifmanip.dump.page_size - broj zapisa po LDAP stranici (default 500)

Primjer: root/admin bind preko core LDAP servisa

Ako u svom modulu trebate napraviti root/admin bind bez direktnog ldap_*, koristite core LDAP servis (AaiEduHr\Aosi\Module\Core\Ldap).

Primjer (u servisu/handleru):

use AaiEduHr\Aosi\Module\Core\Ldap;

final class SomeService
{
    public function __construct(
        private readonly Ldap $ldap,
    ) {
    }

    public function doSomething(): void
    {
        $conn = $this->ldap->rootBind();
        if ($conn === false) {
            $code = $this->ldap->err_code();
            $msg = $this->ldap->err_message();
            // obradi grešku
            return;
        }

        // ... LDAP operacije nad $conn
    }
}

Napomena: rootBind() koristi konfiguraciju aosi.ldap.rootdn i aosi.ldap.pass. Na grešci puni err_code i err_message u Ldap objektu.

Poziv iz drugih modula

Ručno pisanje LDIF zapisa iz drugih modula više nije predviđeno. Modul radi isključivo na temelju libldifmanip.outputs i libldifmanip.write_profiles konfiguracije.

Testovi

Testovi su u:

  • tests/EventListeners/LdifManipListenersTest.php
  • tests/LdifDumperTest.php
  • tests/LdifRotatorTest.php

Pokriveni su, između ostalog:

  • filtriranje atributa prema shemi (nema clear_userpassword, nema jpegPhoto)
  • objectClass prolazi u add/modify/delete eventima
  • defaultni objectClass pri add user kada ga event ne sadrži
  • base DN provjere (uključujući ; separator)
  • generiranje per-realm datoteka i rad s per_realm=false
  • custom file_prefix i normalizacija file_ext
  • multi-profile upis (više datoteka)
  • allowlist filtriranje u profilu
  • RFC 2849 folding za duge linije
  • base64 kodiranje za non-ASCII, vrijednost s newlineom, vodeći razmak i praznu vrijednost
  • dumpall preko LdifDumper servisa (generiranje datoteke i skip jpegPhoto)
  • dump lock koliziju (Dump is already running) i mapiranje LDAP bind greške
  • PHP fallback rotaciju: missing file, empty file i poštivanje max depth-a
  • error logiranje kada kreiranje direktorija ili upis datoteke ne uspije
  • rotaciju preko LdifRotator uz PHP fallback

Pokretanje testova:

vendor/bin/phpunit

Test summary (zadnje lokalno pokretanje 2026-02-23):

  • OK (31 tests, 112 assertions)

Napomena

Rotaciju LDIF datoteka i full LDAP dump sada preuzima libldifmanip kroz servise LdifRotator i LdifDumper, dok libldifsync ostaje SOAP "frontend". libldifsync za LDIFSync uvijek koristi konfiguraciju iz libldifmanip.outputs['LDIFSync'], pa je dovoljno promijeniti taj profil kako bi SOAP i file putanje ostale usklađene.

Autorstvo i alati

Autor: Krešimir Mihalj (kresimir.mihalj@srce.hr).
Kod je razvijen u PHPStormu uz asistenciju Codex‑a.