aaieduhr / aosi-module-libldifmanip
AOSI LibLdifManip Module
Package info
gitlab.opencode.hr/srce/aai-eduhr/aosi/aosi-module-libldifmanip
Type:aosi-module
pkg:composer/aaieduhr/aosi-module-libldifmanip
Requires
- php: >=8.2
- ext-ldap: *
Requires (Dev)
- aaieduhr/aosi: ^5
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpunit/phpunit: ^10 || ^11
- rector/rector: ^2.0
- slevomat/coding-standard: ^8
- squizlabs/php_codesniffer: ^3
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: addza korisnika; ako nemaobjectClass, dodaje defaultnu listu (person, organizationalPerson, inetOrgPerson, hrEduPerson, schacContactLocation). - AfterDeleteUser: zapisuje
changetype: delete. - AfterAddUserAttribute: zapisuje
changetype: modifysaddoperacijama. - AfterModifyUserAttribute: zapisuje
changetype: modifysreplaceoperacijama. - AfterDeleteUserAttribute: zapisuje
changetype: modifysdeleteoperacijama. - Atribut
jpegPhotose 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
errorlog 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:
jpegPhotose uvijek preskače.objectClassse 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(profilLDIFSync)data/o365connect/o365connect_<realm>.ldif(profilo365)
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 unutardata/file_prefix- prefiks datotekefile_ext- ekstenzijaper_realm- dodaje li se_realmallowlist- opcionalni popis atributa (dodatni filter uz shemu)
libldifmanip.write_profiles- profili koje listeneri zapisuju (npr.['LDIFSync', 'o365'])libldifmanip.write_profilesmož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 starimo365connect.*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 (defaultlogrotate)libldifmanip.logrotate.exe_path- PATH za traženje izvršne datotekelibldifmanip.logrotate.dir- direktorij za logrotate config (defaultapp.logs.dir)libldifmanip.logrotate.file_prefix/file_extlibldifmanip.logrotate.status_prefixlibldifmanip.logrotate.rotate- broj rotacija (default 5)libldifmanip.logrotate.notifempty- preskoči rotaciju praznih datotekalibldifmanip.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 izlibldifmanip.outputs(npr.LDIFSync,o365)[realm]: naziv realm-a izaosi.realm(npr.srce,intsrce)- realm se mapira na base DN kao
dc=<realm>,dc=hr - ako nije zadan, koristi se defaultni realm iz konfiguracije
- realm se mapira na base DN kao
Primjeri:
php vendor/aaieduhr/aosi-module-libldifmanip/AosiDumpAll.php LDIFSync srcephp 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/baseSTATUS=OK- dump uspješno završen (ispisujeFILEiSIZE)STATUS=WARNING- dump datoteka je kreirana, ali je prazna (SIZE=0)STATUS=ERROR- dump nije uspio (ispisuje razlog uMESSAGE)
Exit kodovi:
0- uspjeh1- greška2- warning (prazna dump datoteka)
Opcije dumpa u konfiguraciji:
libldifmanip.dump.page_size- broj zapisa po LDAP stranici (default500)
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.phptests/LdifDumperTest.phptests/LdifRotatorTest.php
Pokriveni su, između ostalog:
- filtriranje atributa prema shemi (nema
clear_userpassword, nemajpegPhoto) objectClassprolazi u add/modify/delete eventima- defaultni
objectClasspri 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_prefixi normalizacijafile_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
LdifDumperservisa (generiranje datoteke i skipjpegPhoto) - 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
LdifRotatoruz 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.