Teoretický popis LDAPu je v článku Adresářové služby a LDAP. Pokud se na problematiku podíváme velmi přibližně, tak adresář je databáze a LDAP jsou funkce pro přístup k databázi. Proto v teoretickém použití LDAPu z PHP není problém. Pro PHP existuje rozšíření (extension) php_ldap
, které implementuje operace LDAPu.
LDAP
Pro zprovoznění LDAPu v PHP na operačním systému Windows, potřebujeme pouze zapnout PHP extension php_ldap
. To provedeme přidáním řádku do sekce extension v souboru php.ini
(případně jeho odkomentováním).
extension=php_ldap.dll
Potom již můžeme jednoduše přistupovat k LDAPu. Popis funkcí je v manuálu LDAP Functions, je zde implementováno všech 9 standardních operací z LDAP v3. Některé jsou rozděleny do více funkcí a je zde řada doplňujících funkcí pro jednodušší použití. Velice stručně se zmíním o základních funkcích.
ldap_connect()
- Vytvoří spojení na zadaný LDAP server, vrací ID linku nebo false. Pokud nespecifikujeme, tak se pro LDAP použije standardní port 389.
ldap_set_option()
- Nastaví hodnotu specifikované vlastnosti, třeba verze LDAPu.
ldap_bind()
- Navázání k adresáři pomocí ID linky. Provádí se autentizace podle jména a hesla, pokud se nezadá, tak se pokusí o anonymní připojení. Většinou se tak chová i v případě, pokud se vyplní pouze jméno a ne heslo. Server pak často vrátí true, to se stane i v případě AD, i když anonymní připojení není povoleno (a další přístup k adresáři není funkční). Jméno by se mělo zadávat pomocí DN (CN=Uzivatel,OU=Users,DC=firma,DC=local) , ale pro AD funguje i zadání pouze username (uzivatel) nebo UPN (uzivatel@firma.local).
ldap_search()
- Operace search z LDAPu. Zadáváme výchozí bod hledání a filtr, další parametry jsou volitelné. Vrací ID výsledku nebo false.
ldap_get_entries()
- Jedna z možností jak získat záznamy vrácené funkcí search (a dalších). Vrací vícerozměrné pole, kde jsou jednotlivé záznamy a pro každý záznam jeho atributy.
ldap_add()
- Vložení nového záznamu s daným DN a určenými atributy.
ldap_compare()
- Porovnání atributu s hodnotou pro daný záznam.
ldap_close()
- Korektní ukončení session, jedná se pouze o alias k ldap_unbind().
Ještě uvádím jednoduchý příklad, který se připojí k AD pod uživatelem a provede jednoduché hledání a výpis pár hodnot. Pro správné použití chybí ošetření řady událostí apod.
<?php function ldapQuery($filter, $baseDN = "OU=firma,DC=firma,DC=local", $server = "192.168.0.1") { $ldapCon = ldap_connect($server); if($ldapCon) { ldap_set_option($ldapCon, LDAP_OPT_PROTOCOL_VERSION, 3); // AD podporuje LDAPv3 ldap_set_option($ldapCon, LDAP_OPT_REFERRALS, 0); // pro AD se doporučuje vypnout referrals $res = ldap_bind($ldapCon, "CN=Uzivatel,OU=Users,DC=firma,DC=local", "Password"); if($res === false) { echo "<p>Autentizace selhala.</p>"; ldap_close($ldapCon); return false; } $rec = ldap_search($ldapCon, $baseDN, $filter); echo "<p>Počet vyhledaných záznamů: " . ldap_count_entries($ldapCon, $rec) . "</p>"; $info = ldap_get_entries($ldapCon, $rec); for($i=0; $i<$info["count"]; $i++) { echo "DN: ".iconv("UTF-8", "ISO-8859-2", $info[$i]["dn"])."<br />"; echo "První CN: ".iconv("UTF-8", "ISO-8859-2", $info[$i]["cn"][0])."<br />"; echo "První email: ".$info[$i]["mail"][0]."<br /><hr />"; } ldap_close($ldapCon); } else { echo "<p>Nepodařilo se připojit k LDAP serveru.</p>"; ldap_close($ldapCon); return false; } } ldapQuery("(memberOf=CN=Skupina,OU=firma,DC=firma,DC=local)"); ?>
Pozn.: Adresářové služby používají kódování UTF-8, takže pokud na stránce máme nějaké jiné, musíme hodnoty převádět.
Pozn.: Pokud v AD používáme v názvech (v DN) diakritiku, tak v příkazech můžeme použít znaky bez diakritiky (a nemusíme pak řešit problém s kódováním).
LDAPS
Při běžném použití LDAPu probíhá komunikace mezi webovým serverem a adresářovým serverem (budu uvažovat AD) v otevřené formě a při zachycení komunikace je vše čitelné. Největší nebezpečí je u autentizace operací bind
.
Pokud je pro nás problém pouze autentizace, tak můžeme použít SASL metodu autentizace. Pokud nám jde o zabezpečení veškerých dat, tak potřebujeme šifrovat veškerou komunikaci a to můžeme buď pomocí SSL nebo TLS. Já se budu věnovat SSL. LDAP, který běží nad SSL, se označuje jako LDAPS.
Pozn.: Pokud jsou ještě nějaká důležitá data (například právě autentizace uživatele do AD) posílána z klienta na webový server, tak je dobré šifrovat pomocí SSL i tuto komunikaci (HTTPS).
Jak rozchodit LDAPS
- LDAPS používá stejnou knihovnu jako LDAP, takže nejprve musíme zapnout extension
php_ldap.dll
- Protože chceme používat SSL, tak musíme rozchodit Apache se SSL, to je popsáno v článku Apache server (EasyPHP) se SSL na Windows.
- Musíme mít zprovozněné LDAPS na adresářovém serveru, takže AD server musí mít certifikát.
- Knihovna
php_ldap.dll
má v sobě napevno specifikovánu cestu ke svému konfiguračnímu souboru, která jeC:\openldap\sysconf\ldap.conf
(v Linuxu/etc/openldap/ldap.conf
). Musíme tedy vytvořit tyto adresáře a do nich soubor, do kterého vložíme následující řádek
TLS_REQCERT never // nekontroluje se certifikát serveru
A to je vše, nyní již můžeme využívat šifrované LDAPS. Abychom použili LDAPS v PHP, tak stačí ve funkci ldap_connect
použít adresu serveru ldaps://192.168.0.1
, případně s určením standardního portu 636 ldap_connect("192.168.0.1", 636)
.
Výše uvedený postup je zjednodušený, nepoužíváme certifikát klienta a ani nekontrolujeme certifikát serveru. Většina návodů na internetu obsahuje kroky, kde se stáhne certifikát kořenové autority, od které má adresářový server svůj certifikát. Ten se pomocí OpenSSL převede do formátu PEM a přidá se do konfiguračního souboru ldap.conf
pomocí parametru TLS_CACERT
.
Pozn.: Narazil jsem na problém, když startoval Apache a php_ldap.dll
se snažilo načíst certifikát, tak celý server spadnul. Pomohlo přehrání knihovny php_ldap.dll
z poslední verze PHP (php-4.4.7-Win32.zip).
Ladění
Pro řešení problémů s LDAPem můžeme zapnout debugovací mód. To provedeme zadáním následujícího příkazu do kódu ještě před ldap_connect
.
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
Následně se do logu errors.log
Apache serveru zapisují podrobně všechny prováděné operace s LDAPem.
Například pokud používáme LDAPS a nemáme správně certifikát či nepoužíváme TLS_REQCERT never
(třeba když vůbec neexistuje ldap.conf), tak se v logu objeví následující chyba a neproběhne bind.
TLS certificate verification: Error, unable to get local issuer certificate TLS trace: SSL3 alert write:fatal:unknown CA
Pokud nezapneme debug, tak se nedozvíme, proč se bind nepodařil.
Komentáře
Pekny clanek, diky za nej
Pekne clanky, ale nerozumim tomuto:
3.Musíme mít zprovozněné LDAPS na adresářovém serveru, takže AD server musí mít certifikát.
a pak kdyz pouziji:
"TLS_REQCERT never"
tak ctu "nekontroluje se certifikát serveru"
To znamena, ze AD server nemusi mit certifikat pri tomto nastaveni?
odpověď na [2]LaYosH: Aby mohla být komunikace šifrovaný (při SSL nebo TLS) tak se využívá certifikát a jeho klíč. Takže vždy tam ten certifikát musí být.
Druhá věc je, že certifikát se dá použít i k ověření, že server je opravdu ten, za který se vydává. To se provádí na straně klienta, ale tuto kontrolu nemusím použít.
Ahoj,
řeším také tento problém.
Mám XAMPP, kde SSL funguje (https://localhost běží).
Ale když se zkusím připojit na ldaps, tak dostanu přesně tu chybu, která je zmíněná na konci textu.
Žádný z návodů, které jsem našel nezabral.
Neví někdo, co s tím? (případně: otto.kovarik@gmail.com)
Díky, to je super článek. S Active Directory všeobecně jsem se pral hrozně dlouhou dobu než sem na je nějak "zdolal" Jinak PHP mi přijde jako jeden z nejlepších jazyků, nejen srozumitelně, ale i v rámci nějakýho uplatnění. A nejlépe uplatnění v cizině. Zkoušel jsem najít nějaké weby, které se tím specializují, nevíte nějaké osvědčené? Mě říkal kámoš o itprace-nemecko.cz/,prý mu tam sehnali nějakou brigádu, akorát jsem se ještě nedostal k tomu, abych tam napsal životopis... :D (snad neva ten odkaz, nemyslel jsem to jako spam, spíš jestli s touhle konkrétní firmou má někdo nějaké zkušenosti)