Membahas cara mengintegrasikan aplikasi web dengan LDAP: autentikasi lewat PHP, Python, Java, Node.js, dan Go, perlindungan di level Apache dan Nginx, framework aplikasi, pola SSO dengan CAS, SAML, dan Keycloak, serta praktik terbaik untuk koneksi dan kredensial aplikasi.

Pada episode 20, LDAP melayani email dan address book. Episode 21 ini memakai directory yang sama untuk aplikasi web: autentikasi user di aplikasi yang ditulis dengan PHP, Python, Java, Node.js, dan Go; perlindungan akses di level web server; dukungan framework populer; hingga pola SSO yang lebih besar seperti CAS, SAML, OAuth2, dan Keycloak. Pola bind DN, base DN, dan filter yang kalian kuasai di episode sebelumnya akan dipakai terus di sini — hanya dengan pembungkus bahasa yang berbeda.
Semua integrasi LDAP dari aplikasi mengikuti pola yang sama: aplikasi melakukan bind dengan DN user yang mencoba login, dan jika bind berhasil, user terautentikasi. Langkah detailnya hampir selalu berupa:
uid).Pola ini disebut bind as user. Alternatifnya adalah bind as service: aplikasi memakai akun khusus untuk melakukan search dan memvalidasi password dengan membaca atribut hash — pola ini kurang disarankan karena memaksa aplikasi membaca password hash, padahal aturan directory modern menyimpan hash di luar jangkauan aplikasi.
Setiap ekosistem bahasa punya cara khas untuk berbicara dengan LDAP, tetapi semuanya mengimplementasikan pola dasar di atas.
PHP memiliki ekstensi ldap bawaan. Contoh autentikasi sederhana:
<?php
$ldap = ldap_connect("ldap.example.com");
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
$result = ldap_search($ldap, "ou=people,dc=example,dc=com",
"(uid=" . ldap_escape($username) . ")");
$entries = ldap_entries($result);
$dn = $entries[0]["dn"];
$auth = @ldap_bind($ldap, $dn, $password);Perhatikan ldap_escape — selalu sanitasi input username sebelum disisipkan ke filter untuk mencegah LDAP injection. Kesalahan klasik pemula adalah menyambung string filter langsung dari input user, yang membuka celah manipulasi filter.
Python punya dua library utama: python-ldap (bind ke libldap C) dan ldap3 (implementasi murni Python). ldap3 lebih mudah dipakai karena API-nya sederhana:
from ldap3 import Server, Connection, ALL
server = Server("ldap.example.com", get_info=ALL)
conn = Connection(server, "uid=budi,ou=people,dc=example,dc=com",
"password", auto_bind=True)auto_bind=True langsung melakukan bind saat koneksi dibuat. Jika bind gagal, exception dilempar dan aplikasi bisa menampilkan pesan login gagal. ldap3 juga menyediakan API yang bersih untuk search dan manipulasi entry.
Java memakai JNDI (Java Naming and Directory Interface) untuk mengakses LDAP. Pola bind user di Java melibatkan pembuatan konteks awal dengan environment properties:
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://ldap.example.com");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "uid=budi,ou=people,dc=example,dc=com");
env.put(Context.SECURITY_CREDENTIALS, "password");
DirContext ctx = new InitialDirContext(env);JNDI adalah fondasi dari banyak framework Java seperti Spring Security LDAP. Jika konstruksi InitialDirContext berhasil, autentikasi berhasil; exception AuthenticationException menandakan kredensial salah.
Di Node.js, library seperti ldapjs menyediakan klien LDAP dengan API berbasis event dan promise. Di Go, library seperti go-ldap adalah standar yang paling banyak dipakai. Keduanya mengimplementasikan bind, search, dan modify dengan cara yang idiomatis untuk ekosistem masing-masing. Semua pilihan bahasa di atas tetap memakai protokol LDAP yang sama — perbedaannya hanya di ergonomi API.
Kadang autentikasi tidak perlu ada di aplikasi — web server bisa melakukannya lebih dulu. Pendekatan ini melindungi seluruh aplikasi tanpa mengubah satu baris pun kode aplikasi.
Apache punya modul mod_authnz_ldap untuk autentikasi dan otorisasi berbasis LDAP:
AuthType Basic
AuthName "Area Terproteksi"
AuthBasicProvider ldap
AuthLDAPURL "ldap://ldap.example.com/ou=people,dc=example,dc=com?uid"
AuthLDAPBindDN "cn=apache,ou=system,dc=example,dc=com"
AuthLDAPBindPassword secret
Require valid-userAuthLDAPURL menentukan server, base, dan atribut yang dipakai untuk mencari user. Require valid-user berarti semua user yang valid di LDAP boleh masuk; untuk membatasi group, ganti dengan Require ldap-group cn=staff,ou=groups,dc=example,dc=com.
Nginx tidak punya modul LDAP bawaan, tetapi bisa bekerja sama dengan daemon nginx-ldap-auth (umumnya berbasis nginx-ldap-auth-ng). Nginx meneruskan permintaan ke daemon auth lewat subrequest; jika daemon memvalidasi kredensial ke LDAP, akses diteruskan ke aplikasi. Pola ini memberikan Basic Authentication LDAP dengan kinerja Nginx yang tinggi.
| Pendekatan | Kelebihan | Kekurangan |
|---|---|---|
| Auth di aplikasi | Kontrol penuh, fitur kaya | Harus diimplementasikan per aplikasi |
| Auth di web server | Terpusat, tanpa ubah aplikasi | Terbatas pada Basic Auth |
| SSO (Keycloak dll.) | Satu login banyak aplikasi | Infrastruktur tambahan |
Sebagian besar framework populer memiliki plugin LDAP yang siap pakai:
django-auth-ldap menyediakan backend autentikasi yang bisa dipasang di settings, lengkap dengan mapping group ke permission.spring-security-ldap menawarkan integration dengan JNDI dan support untuk bind dan otorisasi berbasis group.net-ldap ditambah pola authentication di model memberi autentikasi LDAP sederhana.laravel-ldap membungkus operasi LDAP ke dalam sistem auth Laravel yang sudah ada.Memakai plugin framework lebih aman daripada menulis dari nol: error handling, caching, dan mapping group sudah matang dan teruji.
Di skala enterprise, aplikasi jarang berautentikasi langsung ke LDAP. Sebagai gantinya, LDAP menjadi backend identity dari server SSO, dan aplikasi berautentikasi ke server SSO tersebut.
| Teknologi | Peran | Hubungan dengan LDAP |
|---|---|---|
| CAS (Central Authentication Service) | Server login terpusat | Melakukan bind ke LDAP |
| SAML | Standar federasi identitas | IdP membaca user dari LDAP |
| OAuth2/OIDC | Standar delegasi akses | Provider memvalidasi lewat LDAP |
| Keycloak | Platform IAM modern | User federation ke LDAP |
Keycloak adalah contoh paling populer: kalian menambah User Federation LDAP, menghubungkan ke server OpenLDAP, dan semua user LDAP langsung tersedia untuk login di Keycloak. Aplikasi kemudian memakai protokol OIDC atau SAML ke Keycloak, bukan ke LDAP secara langsung. Ini memisahkan autentikasi dari aplikasi dan memberi satu titik untuk MFA dan policy.
Integrasi LDAP yang rapuh dibangun dari disiplin operasional, bukan hanya kode yang benar:
Important
Filter yang menerima input user tanpa sanitasi adalah celah LDAP injection — serupa dengan SQL injection. Selalu escape nilai yang disisipkan ke filter, atau gunakan escape function yang disediakan library seperti ldap_escape di PHP dan escape_filter_chars di ldap3. Kredibilitas satu filter yang bisa dimanipulasi cukup untuk menghancurkan seluruh directory.
Pada episode 21 ini, kalian menghubungkan aplikasi web ke LDAP: pola dasar bind as user, autentikasi di PHP, Python, Java, Node.js, dan Go, perlindungan di level Apache dan Nginx, dukungan framework seperti Django dan Spring, integrasi SSO dengan CAS, SAML, dan Keycloak, serta praktik terbaik untuk koneksi pooling dan keamanan kredensial.
Inti yang harus dibawa pulang:
Di episode 22 berikutnya, kalian melebarkan penglihatan ke ekosistem Microsoft: Active Directory dan LDAP — bagaimana AD DS memakai LDAP sebagai protokol intinya, perbedaan schema dan atribut dengan OpenLDAP, serta cara Linux bergabung dengan domain AD. Pola bind dan filter yang kalian kuasai di episode ini tetap berlaku di sana.