Active Directory Nedir - LDAP Nedir - Dizin (Directory) ve LDAP (Lightweight Directory Access Protocol) Kavramlar

Dizin ve LDAP kavramları ,özellikle kurumsal ortamlarda sıkça karşılaştığımız kavramlardandır. Peki nedir bunlar ve ne işe yararlar? 
Dizin(Directory): Belirli türden nesnelerden oluşan küme ve bu küme üzerinde sorgulama imkanı sağlayan yapı şeklinde özetlenebilir.Aslında dizin, bir veritabanıdır ve genellikle okuma ve arama gibi amaçlar için düzenlenmiş/optimize edilmiştir.İlk akla gelen örnekler telefon rehberi uygulamaları, bir ağ üzerinde bulunan bilgisayarlar hakkında tutulan kayıtlar vb. olabilir.
Hem veritabanında hem de dizin de bilgileri depolama vardır.Ama bu bilgilerin tutulma şeklileri farklıdır.
Normal bir veritabanı sisteminde verileri istenilen mantıkta ve yapıda tutmak mümkün iken, dizin mantığında bilgiler bir hiyerarşiye göre tutulur.Bu sebeble arama ve okuma işlemleri aynı işi yapan bir veritabanı uygulamasına gore daha performanslıdır denilebilir. Veritabanında rollback, transaction gibi kompleks işlemler desteklenirken dizin desteklemez. Yine veritabanı genelde dinamik iken dizin de statik bilgiler tutulur.Özetle veritabanı, veriler arasında bağlantıya ihtiyaç duyan uygulamalar için(ERP,Muhasebe gibi), dizin ise dağıtık çalışmaya ihtiyaç duyan uygulamalar için (kurumsal e-posta adres defteri, DNS sistemi gibi) tercih edilirler.
LDAP : 
Açılımı Lightweight Directory Access Protocol olan LDAP, X.500 standardı ile tanımlanan dizin erişim protokolünün hafifletilmiş sürümüdür.İletişim protokolü TCP/IP dir.(DAP(Directory Access Protocol), sunucu ve istemci arasındaki haberleşmeyi tanımlar.OSI modelinin uygulama katmanında çalışan bir protokoldür.Çalışabilmesi için tüm OSI katmanlarına ihtiyaç duyar.)

Ancak ihtiyaçlar geliştikçe X.500 (dolayısyla DAP protokolü) yetersiz kalmaya başladı.Bu aşamada LDAP geliştirildi.Önceleri X.500 dizin servislerine ulaşmak için düşünülmüş ise de sonradan kendisi bir dizin servisi haline geldi.
X.500 :
  • OSI protokol kümesini kullanırken LDAP TCP/IP protokolünü kullanır.
  • Daha karmaşıktır.
  • OSI kullanmasında dolayı özellikle masaüstü ve küçük sistemler için uygun değildir.
LDAP ise çok kaynak istemez ve TCP/IP ye ihtiyaç duyduğundan yaygın olarak kullanılabilmektedir.LDAP Client-Server mimarisi aşağıdaki gibi özetlemek mümkündür.



Domain Component (DC) - DNS İsmi

Firmanın DNS isminin noktalar hariç ayrılmış hali olara düşünülebilir. Örneğin DNS ismi firma.com ise dc aşağıdaki gibiolacaktır.
dc=firma,dc=com. 

Organizational Unit (OU) - Kullanıcının Ait Olduğu Grup

Kişinin ait olduğu gruplar olarak düşünülebilir. Örneğin ben personel ve muhasebe grubuna aitsem ou aşağıdaki gibi olacaktır.
ou=personel,ou=muhasebe
CN (Common Name) - Kullanıcı Ad Soyad

Bir nesneye verilen isim olarak düşünülebilir. Örneğin bir kullanıcı nesnesi için aşağıdaki gibi olacaktır.
cn = Cin Ali. cn genellikle ad ve soyad bilgisini içerir.

sAMAccountName
Kullanıcının login adı. Artık pek kullanılmıyor.

SN (Surname) - Kullanıcı Soyadı
Kullanıcının soyadı

Distinguished Name (DN)

DN bir nesneyi diğerlerinden ayırt edilebilir yapar. DN yukarıda belirtilen CN, OU ve DC'lerin bileşimidir. Yukarıdaki örneklere göre benim dn tanımım aşağıdaki gibi olacaktır.
cn=cin ali, ou=personel,ou=muhasebe,dn=firma,dn=com
Web adreslerinde önce DNS'ten başlanır sonra istenilen sayfa adresi gelir. Yani bir nevi büyükten küçüğe doğru gidilirken LDAP'te DN isminin oluşturulması için en küçükten en büyüğe doğru gidildiğine dikkat etmek lazım. Mastering LDAP Searchsayfasında şöyle bi cümle geçiyordu.
 objects “above” another object are notated as being to the right of the object in LDIF.

How do I build this LDAP connection string? sorusunda da cevaplandığı gibi aşağıdaki birimi sorgulamak için

"LDAP://ofmdcoly302.ofm.wa.lcl/ou=AR,ou=Citrix,ou=Users - OFMGOV,dc=ofm,dc=wa,dc=lcl" stringini kullanmak lazım.

LDIF
Herşeyi birleştiren bir LDIF dosyası şöyle



dn: dc=demo,dc=com
objectclass: top
objectclass: domain
dc: demo

dn: ou=Users,dc=demo,dc=com
objectClass: organizationalUnit
objectClass: top
ou: Users
description: demo.Com Users


dn: uid=bob,ou=Users,dc=demo,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: User Test
sn: Test
displayName: User Test
givenName: User
mail: bob@demo.com
ou: Users
uid: bob
userPassword:: e1NTSEF9MGhuUjhnWkFNZFpKVUNwZXFwcFEzeUQ2YkJNOTVQUVo4WU9JSUE9P
 Q==
ldap sunucu urlsi
Sunuc url'si şuna benzer.

ldap://xxxx.com:389

objectClass Nedir

objectClass bir girdinin tipi hakkında bilgi verir. Örnek



LDAP ve Encoding

LDAP v3 UTF-8 encoding kullanır.

LDAP ve Büyük Küçük Harf
Microsoft LDAP schema case sensitive sorusunda da cevaplandığı gibi LDAP ile harf farklılığına bakmayı zorlamak için aşağıdaki gibi kullanmak lazım.

LDAP ve Hata Kodları
Buradaki soruda LDAP hata kodları ile ilgili verilmiş. Ancak AD hata kodları LDAP hata kodlarından biraz daha farklı olarak sub-code mantığı kullanıyor. Örneğin 49 authentication error. sub-code 773 ise şifre değiştirilmeli anlamına geliyor.

Java ve Ldap
Java ile Ldap'e bind edebilmek için kullanılan sınıfların hiyerarşisi kabaca aşağıdaki gibi.


DirContext sınıfı 
LDAP yazısına taşıdım.

Context sınıfı
Bu sınıf ile bir çok string hard-code tanımlı.
Context.SECURITY_AUTHENTICATION
Kullanılacak olan doğrulama mekanizması belirtiliyor. Mesela DIGEST-MD5 kullanılabilir. Örnek:
Hashtable env = new Hashtable();
env.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5");
DirContext ctx = new InitialDirContext(env);

Ldap ve timeout
Spring LDAP: Connection reset by peer sorusuna verilen cevap aşağıda.

Görüldüğü gibi tüm string sabitleri Context sınıfı tarafından tanımlanmıyor.

DirContext arayüzü
search metodu

DirContext.search metodu ile LDAP üzerinden arama yapmak mümkün. Aşağıda metodun aldığı parametreler var.


name olarak aşağıdaki gibi örnekler verilebilir.

final String name= "dc=ad,dc=my-domain,dc=com";

LDAP'ten bilgi çekerken arama filtresi olarak aşağıdaki örnekler gibi bir filtre verilir.


String filterExpr= "(&(objectClass=user)(userPrincipalName={0}))";
String filterExpr = "(&(objectClass=user)(sAMAccountName={0}))";

SearchControls sınıfı
Bu sınıf ile beraber iki tane scope seçeneği kullanılabilir. Bunlar Scope = ONELEVEL_SCOPE ve SUBTREE_SCOPE. İlki ağacın sadece verilen dalında arama yapar. İkincisi ise, verilen daldan aşağıdaki dalları da aramaya dahil eder.

NamingEnumeration sınıfı
Bu sınıf klasik bir enumeration. hasMoreElements() metodu ile dolaşılması mümkün.
Örnek:
NamingEnumeration<SearchResult> results = ctx.search(...);
SearchResult searchResult = null;
if(results.hasMoreElements()) {
    searchResult = (SearchResult) results.nextElement();
}
return searchResult;
SearchResult sınıfı

getAttributes
Örnek:
SearchResult srLdapUser = //...
String strPrimaryGroupID = (String)srLdapUser.getAttributes().get("primaryGroupID").get();

Spring ve Ldap
Sun tarafından sağlanan Java sınıflarını kullanmak zor olduğu için Spring ile gelen LdapTemplate sınıfı kullanılabilir. Aşağıdaki kodu LDAP Authentication sorusundan aldım.


C# ve LDAP
Bu sınıfları kullanmak için
using System.DirectoryServices;
yapmak gerekir.Ancak bu sınıfların sunduğu arayüzler biraz karışık.

DirectoryEntry sınıfı
ActiveDirectory'deki bir düğümü temsil eder.

DirectorySearcher sınıfı

PropertiesToLoad metodu
Aynı SQL'deki gibi aranan nesnenin hangi sütun/özelliklerinin sonuca dahil edilmesi gerektiği belirtilir.


DirectorySearcher dsLookFor = new DirectorySearcher(directoryEntry);
...
dsLookFor.PropertiesToLoad.Add("cn");
dsLookFor.PropertiesToLoad.Add("samAccountName");

FindOne metodu
SearchResult döner.

Örnekte kullanıcı doğrulaması gösterilmiş.

using System.DirectoryServices;
string domain, string username, string pwd;//Populate
string domainAndUsername = domain + @"\" + username;
 DirectoryEntry entry = new DirectoryEntry( _path,
                                             domainAndUsername,
                                               pwd);
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");//cn common name, kullanıcı adı
SearchResult result = search.FindOne();
if(null == result)
{
  return false;
}
return true;
FindAll metodu
SearchResultCollection döner. SearchResultCollection for döngüsü ile yürünebililir. Her bir SearchResult nesnesinin Properties alanı ile sorgudaki bilgilere erişilebilir.


SearchResultCollection srcUsers = dsLookFor.FindAll();
foreach (SearchResult srcUser in srcUsers)
{
  Console.WriteLine("{0}", srcUser.Path);
  Console.WriteLine("{0}", srcUser.Properties["samAccountName"][0]);
}

System.DirectoryServices.AccountManagement altındaki sınıflar System.DirectoryServices'in altındaki sınıflara göre kullanması daha kolay arayüzler sunuyorlar.

UserPrincipal sınıfı
FindByIdentity
Örnek:

PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "server","CN=Users,DC=doom,DC=home","ldapuser","password");

 // get user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.Name, username);

 //is user locked
var locked = user.Enabled; 

Active Directory Notları

.net view /domain komutu ile domain'ler listelenebilir
.net view /domain:mydomain ile mydomain'e ait bilgisayarlar listelenebilir.

Bu blogdaki popüler yayınlar

Interface , Class ve Abstract Class || inheritance ve implemente