BETA
Aby się zalogować, najpiew wybierz portal.
Aby się zarejestrować, najpiew wybierz portal.
Podaj słowa kluczowe
Słowa kluczowe muszą mieć co najmniej 3 sąsiadujące znaki alfanumeryczne
Pole zawiera niedozwolone znaki

Baza wiedzy











Active Directory Explorer, czyli programowy dostęp do usługi katalogowej AD z poziomu .NET

09-09-2004 17:49 | uzytkownik usuniety
Wykorzystanie DirectoryServices do budowy eksploratora usługi Active Directory

Zapewne każdy z nas słyszał wiele razy pojęcia „usługa katalogowa” czy też „katalog”. Niekiedy pojęcia te bywają nadużywane w celach marketingowych i promocyjnych, jednakże jedno jest pewne: usługi te zmieniły w dużym stopniu korzystanie z sieci komputerowych. Zanim jednak przedstawię Active Directory widziane oczami programisty .NET, musimy poznać i zrozumieć niezbędne podstawy katalogowych usług sieciowych a przede wszystkim Active Directory.

KATALOG I USŁUGA KATALOGOWA

Katalogiem nazywamy zbiór informacji, który zorganizowany jest w pewien szczególny, charakterystyczny dla siebie sposób. Organizacja katalogu pozwala na łatwy dostęp do potrzebnych danych oraz ułatwia ich wyszukiwanie i filtrowanie. Bardzo trafne jest porównanie katalogu do książki telefonicznej. Dane w książce uporządkowane są alfabetycznie wg. województw, powiatów, miejscowości i nazwisk. Możemy szybko znaleźć dowolny numer telefonu dysponując np. nazwiskiem danej osoby dlatego, iż dane zorganizowane są w znany nam sposób. Im większą ilość danych posiadamy, tym szybciej jesteśmy w stanie odnaleźć interesujący nas numer. Podobnie jest z usługami katalogowymi. Nie są one tak naprawdę wynalazkiem ostatnich lat. Jednakże w ciągu ostatniej dekady sieci komputerowe gwałtownie zmieniły swoje rozmiary. W wielu sieciach każdy użytkownik posiada własny komputer, wielkie ilości danych prywatnych i publicznych, korzysta z wielu usług sieciowych często rozproszonych po  wielu serwerach. Z łatwością doprowadzić to może do częstych nieporozumień, strat czasu poświęconych na wyszukiwanie i zarządzanie danymi, a to pozwala wątpić w istotę istnienia sieci. Usługi katalogowe to odpowiedź na potrzebę utrzymania porządku i umożliwienie łatwości zarządzania. Ich celem jest przyspieszenie odnajdywania interesujących danych przez użytkowników, a administratorowi ułatwienie zarządzania tymi właśnie użytkownikami i dostępnymi usługami w sieci. Usługa katalogowa centralnie przechowywuje dane oraz informacje, gdzie dane te znaleźć. Mówiąc dosyć ogólnie jest to specyficznie zorganizowana baza danych służąca wyżej wspomnianym celom.  

LDAP – KROK PRZED ACTIVE DIRECTORY    

Społeczność internetowa stworzyła standard, który umożliwia dostęp do usług katalogowych za pomocą protokołu warstwy aplikacji, opartego na sieciach TCP/IP. Standard ten nazywa się Lightweight Directory Access Protocol (LDAP) i jest publicznie dostępny. Istnieje wiele dokumentów RFC dostępnych na jego temat, z których większość dostępna jest na stonie ldapman.org. Dla nas, programistów, najciekawsze to: interfejs programistyczny LDAP (RFC1823) oraz  schemat LDAP (RFC2256). Active Directory oparte jest na protokole LDAP, dlatego warto zrozumieć jego podstawy.

Usługa katalogowa LDAP oparta jest na hierarchicznej bazie danych. Hierarchiczne bazy danych często stosowane są w wielu organizacjach, gdyż wiernie odwzorowują strukturę i podział organizacji. Charakteryzują się szybkim odczytem danych, ale za to wolnym zapisem. Tu warto wspomnieć o tym, iż projekt hierarchicznej bazy danych zakłada rzadkie zapisy, lecz bardzo częste odczyty przez wielu klientów sieciowych. Przykładem może być konto użytkownika: tworzone raz będzie wielokrotnie wykorzystywane do odczytu informacji, które to z rzadka będą modyfikowane. Tak, ale gdzie ta hierarchia? Hierarchia istnieje, gdyż obiekty przechowywane w bazie tworzą drzewiastą strukturę. Ze strukturalnego punktu widzenia możemy podzielić te obiekty na kontenery i te nie będące kontenerami. Oczywiście obiekty będące kontenerami zawierać mogą inne, dowolne obiekty. Poniższy schemat może być przykładem bardzo prostej bazy LDAP.

Rys.1 Przykładowa organizacja bazy LDAP

Na schemacie widać pewne podobieństwo do struktury DNS (Domain Name System) i nie jest ono przypadkowe. Struktura LDAP (oraz AD) zawiera w wielu przypadkach nazewnictwo systemu DNS wkomponowane we własną bazę. Na rysunku 1 widzimy schemat bazy dla domeny firma.net. Zawiera ona w sobie dwa obiekty: marketing i produkcja. Widzimy, iż marketing jest kontenerem (zawiera inne obiekty: maciek, komp01) a produkcja nie. Jednak produkcja jest jak najbardziej kontenerem, lecz pustym. Nasuwa się pytanie: dlaczego? Proszę zwrócić uwagę na literki przed znakiem równości. Oznaczają one nic innego jak typ obiektu. W bazie LDAP (w AD także) przechowywane może być wiele różnych obiektów, a nie tylko wyróżnione przez nas „kontenery” i „nie kontenery”. Najpopularniejsze typy obiektów LDAP to, np.:

  • DC (Directory Context), jest kontenerem ogólnego zastosowania, często używany do oznaczenia domeny

  • OU (Organizational Unit), czyli jednostka organizacyjna zawierająca inne obiekty, także kontener

  • CN (Common Name), często wykorzystywany do reprezentowania użytkowników, komputerów, drukarek. Często się zdarza, iż cn jest wykorzystywane do reprezentowania, np. komputerów. Jeżeli do komputera podpięte są drukarki, to jednocześnie może stać się on (obiekt reprezentujący komputer) kontenerem.

Tak więc ou=produkcja jest jednostką organizacyjną, kontenerem mogącym przechowywać inne obiekty.

Istnieje wiele innych typów obiektów. Te istniejące w LDAP zostały wyprowadzone ze standardu X.500,  co implikuje, iż istnieją także w AD. Każdy element w bazie LDAP jest jednoznacznie określany za pomocą bezwzględnej ścieżki dostępu (distinguished name, DN). Dla przykładu obiekt cn=maciek to cn=maciek,ou=marketing,dc=firma,dc=net, a obiekt ou=produkcja to ou=produkcja,dc=firma,dc=net. Można także podać ścieżkę względną (relative distinguished name, RDN), np. dla obiektu cn=maciek jego ścieżka względna w domenie (dc=firma,dc=net) to cn=maciek,cn=marketing. Co więcej, każdy obiekt implementować może w sobie różne klasy(określane są one nazwą objectClass). Definiują, jakie atrybuty musi koniecznie posiadać obiekt, a jakie może. Dla przykładu obiekt cn=maciek implementuje klasę objectClass=person, więc musi posiadać atrybuty cn oraz sn, a może posiadać atrybuty, np. description. Należy o tym pamiętać, kiedy będziemy programistycznie modyfikować zawartość katalogu. Często niepowodzeń w manipulacji danymi usługi katalogowej doszukiwać się można właśnie w niezgodności ze schematem usługi. Schemat jest to nic innego jak pewien szablon określający, jakie klasy objectClass  mogą być przez daną usługę implementowane w obiektach oraz jakie atrybuty muszą, a jakie mogą występować w obiektach implementujących dane klasy(objectClass). Widać tutaj pewne podobieństwo do programistycznego pojęcia obiektu. Wiemy już, iż obiekty usługi katalogowej implementują klasy. Co ciekawsze obiekty mogą implementować wiele klas w jednym obiekcie, a niektóre wartości atrybutów mogą występować jednokrotnie lub wielokrotnie (jako kolekcja) przyporządkowane do jednego atrybutu (rysunek 1 – tabelka przy cn=maciek: mamy 2 wartości description). Więcej informacji na temat schematu LDAP można znaleźć na stronie University of Florida - LDAP Schema

ACTIVE DIRECTORY    

Jak już pisałem wcześniej, Active Directory zostało wprowadzone wraz z Microsoft Windows 2000. Zastąpiło tym samym system zarządzania domeną Windows NT. Wprowadzając na rynek AD Microsoft zdecydował się oprzeć produkt o rozwiązanie znane z LDAP, które było i jest sprawdzonym, dopracowanym standardem. Naturalnie, dokonano wielu modyfikacji, by AD było bardziej elastyczne i dysponowało większymi możliwościami. Tym samym domena w sieci opartej na Windows stała się hierarchiczna, co znacznie ułatwiło administrowanie oraz zwiększyło możliwości. Warto jeszcze wspomnieć, iż w Windows NT domena była plaska „płaska”.

Active Directory przechowuje dane jako obiekty, czyli tak samo jak jest to w bazie danych LDAP. W AD mamy do czynienia z inną terminologią i odmiennymi rozwiązaniami niż te prezentowane w LDAP. Nadal podstawową jednostką danych przechowywaną w katalogu jest obiekt. Obiekt reprezentuje jednostkę w sieci: użytkownika, komputer, serwer, bazę danych czy też drukarkę. Każdy obiekt implementuje klasę określoną w schemacie usługi. Klasy te podzielić można na strukturalne(można tworzyć na ich podstawie obiekty), pomocnicze oraz abstrakcyjne(inne klasy z nich dziedziczą). Istnieje też Typ88, który w chwili obecnej śmiało można pominąć. Obiekt może implementować wiele klas i dane w nim przechowywane są silnie typowane. Oznacza to, iż dane muszą spełniać ściśle określone kryteria. Kolejną zmianą jest zmiana nazwy „atrybut” na „właściwość”. Jak nie jest trudno się domyślić nie ma to żadnego funkcjonalnego znaczenia. Schemat usługi Active Directory bardzo mocno różni się od LDAP. Już po pierwszym spojrzeniu zauważyć można, iż zarówno klas, jak i właściwości w Active Directory jest zdecydowanie więcej. Dodatkowo AD korzysta z dodatkowego oznaczania obiektów, a mianowicie przypisywania im numerów guid (globally unique identifier), który zostaje przyporządkowany obiektowi tylko raz, podczas jego dodania do katalogu. I oczywiście nie są to jedyne różnice! Nazwę obiektu można zmienić (tak jak wiele wartości właściwości) natomiast guid pozostaje zawsze taki sam. Polecam sprawdzić to samemu korzystając z aplikacji dołączonej do artykułu. Oczywiście aby tego dokonać należy dysponować dostępem do Active Directory. Dla celów edukacyjnych warto zainstalować, np. system Windows 2003 Server na VirtualPC i uczynić go kontrolerem domeny. Jak to uczynić opisane jest zwięźle w artykule windows2003.pl :: ActiveDirectory.          

ADSI – DOSTĘP DO USŁUG KATALOGOWYCH

Active Directory w myśl Microsoft wspiera otwarte standardy dostępu do usługi katalogowej. Jednym z najbardziej znanych standardów jest interfejs LDAP API umożliwiający dostęp do Active Directory za pomocą języka C. Jednakże to nie z niego skorzystano tworząc interfejs programistyczny dla Active Directory. Zalecanym interfejsem jest ADSI (Active Directory Service Interface). ADSI jest programistycznym interfejsem do łączenia z usługami katalogowymi. Definiuje interfejsy COM, które implementowane są poprzez usługodawców takich jak WinNT, IIS, NDS, czy znany nam już LDAP. Oczywiście może służyć on do komunikacji z Active Directory, katalogiem WinNT czy też usługami katalogowymi firmy Novell. Obiekt ADSI zawsze istnieje po stronie klienta, dlatego też istnienie tej biblioteki jest wymagane, aby uzyskać dostęp do AD z poziomu napisanych przeze mnie aplikacji. Wszystkie Windows 2000, Windows 2003 oraz Windows XP Professional posiadają tę bibliotekę. Dostępna jest także na stronach MSDN.

Dlaczego jest ona tak ważna? Rzekłbym nawet, iż dla klas z przestrzeni nazw System.DirectoryServices .NET Framework jest w chwili obecnej konieczna. Klasy te korzystają właśnie z interfejsów udostępnianych przez ADSI, z których najbardziej znane to (poza oczywiście IUnknown): IADs (do identyfikacji aktualnie podłączonego obiektu, odczytu i zapisu właściwości), IADsUser (do zarządzania obiektami użytkowników, ustawiania haseł) oraz IDirectorySearch (jak sama nazwa wskazuje: przeszukiwanie katalogu).    

PIERWSZY DOSTĘP DO ACTIVE DIRECTORY, PRZEGLĄDANIE DANYCH

Jak zaznaczyłem w tytule zajmować będziemy się dostępem do usługi katalogowej Active Directory z wykorzystaniem klas zawartych w .NET Framework. Kolejne paragrafy obejmować będą modyfikację, dodawanie i usuwanie obiektów oraz wyszukiwanie danych.  Specjalnie dla osób nie posiadających dostępu do kontrolera domeny Active Directory przygotowałem krótki opis, jak można dołączone przeze mnie aplikacje przetestować korzystając z darmowego serwera OpenLDAP (instrukcja w pliku examples.zip w katalogu OpenLDAP). Niestety niektóre zaimplementowane przeze mnie funkcjonalności (np. przeglądarka schematu usługi) dostępne są tylko dla Active Directory.  

Zatem zaczynamy pracę ze znaną nam już usługą katalogową Active Directory. Pierwszym krokiem, gdy zaczynamy korzystać z System.DirectoryServices jest dołączenie referencji do złożenia System.DirectoryServices.dll:

Rys.2. Złożenie DirectoryServices

Naszym pierwszym zadaniem będzie połączenie się z usługą i wypisanie na ekran wszystkich nazw i wartości właściwości, które należą do połączonego obiektu. Skorzystamy z klasy DirectoryEntry. Najpierw zainicjujemy nową instancję tej klasy odpowiednimi wartościami: adresem hosta (kontrolera domeny AD), nazwą użytkownika, hasłem i typem uwierzytelniania. Skorzystamy z AuthenticationTypes.ServerBind, które zaleca się gdy komputer, z którego się łączymy nie jest podłączony do domeny lub też gdy ścieżka ADsPath (czyli „LDAP://...”) zawiera adres hosta (w przypadku tego fragmentu aplikacji to localhost). Istnieją także inne metody uwierzytelniania klienta jak, np. użycie SSL, podpisywania pakietów oraz szyfrowanie połączenia (patrz proszę: AuthenticationTypes). Tu bardzo ważna jest konfiguracja serwera. Wróćmy zatem do aplikacji, której najważniejsze elementy to:

DirectoryEntry dirEnt =
new DirectoryEntry("LDAP://localhost/dc=ldaptest,dc=local", "cn=admin,dc=ldaptest,dc=local","adminpass",AuthenticationTypes.ServerBind);
PropertyCollection propCollection = dirEnt.Properties;
foreach(string name in propCollection.PropertyNames)
     foreach(object obj in propCollection[name])
          Console.WriteLine(name + " = " + obj.ToString());
dirEnt.Close();
(kod dostępny w examples.zip/01_ShowDirectoryProperties)

Powyższy kod uzyskuje kolekcję właściwości, a następnie przechodzi przez wszystkie ich nazwy. Wyświetla na ekran wszystkie wartości właściwości przypisane do obiektu dc=ldaptest,dc=local. Warte uwagi jest to, iż w środku pierwszej pętli foreach zagnieżdżona jest kolejna instrukcja sterująca foreach. Dlaczego? Odpowiedź jest umieszczona na rysunku 1 oraz w paragrafie opisującym LDAP. Druga instrukcja foreach potrzebna jest, gdyż wartości właściwości przechowywane mogą być jako kolekcje. Tak więc aby odczytać wszystkie wartości musimy przejść przez kolekcję wartości dla każdej właściwości.

Tutaj należy także wspomnieć, iż w momencie podania nieprawidłowych danych otrzymamy wyjątek System.Runtime.InteropServices.COMException, np.

Rys.3. Wyjątek COMException po nieudanej próbie zalogowania się

Wyjątki COMException są najczęściej występującymi wyjątkami podczas pracy z Active Directory oraz ogólnie z usługami katalogowymi. Przypominają one o tym, iż klasy z System.DirectoryServices są de facto opakowaniem interfejsu ADSI.

Podobnie do odczytania właściwości obiektu wygląda (z punktu widzenia programisty) wyświetlenie obiektów potomnych. Łączymy się tak samo, jak w poprzednim przypadku. Uzyskujemy z właściwości DirectoryEntry kolekcję obiektów potomnych będącą niczym innych jak kolekcją DirectoryEntries.  Fragment kodu:

// Zakładam istnienie obiektu DirecotryEntry
DirectoryEntries children = dirEnt.Children;
foreach(DirectoryEntry de in children)
     //praca na potomkach
(kod dostępny w examples.zip/03_ChildObjects)

EDYCJA OBIEKTÓW

Edycja obiektów Active Directory nie jest skomplikowanym zadaniem. W przypadku edycji wartości czy też dodawania obiektów potomnych wymaga połączenia z wybranym obiektem, wywołania odpowiednich metod i zamknięcia połączenia. Aby jednak uniknąć kłopotów warto znać przynajmniej podstawy funkcjonowania AD oraz ADSI. W przypadku usuwania obiektów pojawia się nieco więcej problemów.

Najprostszym rodzajem edycji obiektów jest dodawanie właściwości do już istniejącago obiektu. Należy się połączyć z interesującym nas obiektem a następnie uzyskać referencję do kolekcji właściwości, określić nazwę i wartość właściwości:

// zakładam istnienie dirEnt (typ DirectoryEntry)
// dodanie kolejnego opisu
dirEnt.Properties["description"].Add("kolejny opis");
// zapisujemy zmiany na serwerze, aby wartości
// trzymane w cache`u zostały zapisane
dirEnt.CommitChanges();
dirEnt.Close();
(kod dostępny w examples.zip/02_ModifyProperties)

Niestety, a może na szczęście nie możemy do katalogu dopisać, czego tylko sobie zażyczymy. Jak już wcześniej wspomniałem, wszystkie dodawane obiekty podlegają kontroli. Są one silnie typowane. Tak samo jest z wartościami właściwości. Ich dopuszczalne wartości są określone przez schemat właściwości usługi. Dla przykładu właściwość cn może być ciągiem znaków unicode o długości od 1 do 64. Co więcej nie możemy dodać dwóch identycznych wartości. Wtedy otrzymamy znany już nam wyjątek System.Runtime.InteropServices.COMException wraz z informacją, iż „określony atrybut lub wartość usługi katalogowej już istnieje”. Tutaj nasuwa się na myśl pewna ciekawostka związana z nazwą „atrybut” i „właściwość”. W podanym powyżej komunikacie jest mowa o atrybucie. Nie jest to do końca prawdą, gdyż jeśli mówimy o obiektach Active Directory to do czynienia mamy tylko z „właściwościami”. Natomiast gdy mówimy o innych usługach katalogowych, to zgadza się – są to wtedy „atrybuty”. Co ciekawsze w samym MS Windows2003 Enterprise Edition w konsoli mmc „Schemat usługi Active Directory” istnieje ten nazewniczy „błąd”: po lewej stronie widnieje napis „atrybuty” a po prawej już „właściwości”.  Lecz jest to tylko i wyłącznie ciekawostka, gdyż nadal oznaczają one jedno i to samo.

Kolejnym problemem związanym z edycją jest cache`owanie obiektów po stronie klienta, czyli przechowywanie kopii obiektów z serwera po stronie klienta usługi katalogowej. Domyślnie cache`owanie jest włączone. Możemy wyłączyć cache`owanie obiektów poprzez właściwość:

dirEnt.UsePropertyCache = false;

Używanie cache`u jest godne uwagi, ale jego stosowanie bywa niekiedy kłopotliwe. Wymaga od programisty sporej ostrożności. Przydaje się, gdy dokonujemy wielu edycji na obiektach. Wtedy pobierane są obiekty, modyfikowane i gdy jesteśmy już gotowi wywołujemy metodę dirEnt.CommitChanges(); i zmiany wędrują na serwer. Kłopotliwe, gdyż przez pewien czas inni pracować mogą na nieaktualnych danych. Zaletą jest jednak mniejsze obciążenie sieci, gdyż zmiany dokonywane są na raz. Gdy wyłączymy cache`owanie jest dokładnie odwrotnie. Kolejną ciekawostką jest postać cache`u. Jest on tworzony dla każdego obiektu ADSI (nie zapominajmy, iż DirectoryServices korzystają z tego interfejsu). Jest to tabela istniejąca pomiędzy obiektem ADSI a usługodawcą ADSI. Często jest to bardzo optymalne rozwiązanie skracające czas i zmniejszające obciążenie sieci. Wywołując metodę CommitChanges() dokonujemy zapisu danych z tabeli do katalogu. Dane w tabeli zostają.

Dodawanie właściwości, których obiekt nie posiada wygląda dokładnie tak samo, jak dodawanie wartości do istniejących właściwości. Jednakże, jak już wiele razy wspominałem, sprawdzane jest czy dana właściwość może być reprezentowana w danym obiekcie (w class schema) oraz sprawdzane jest, czy wartość jest poprawna. Jeżeli tylko występuje jakaś nieścisłość, zostajemy powiadomieni wyjątkiem COMException.

Dodawanie i usuwanie obiektów potomnych jest bardziej kłopotliwe. Dodawanie obiektów polega na odczytaniu kolekcji obiektów potomnych podłączonego obiektu. Następnie dodajemy nowy obiekt do kolekcji. W międzyczasie określamy objectClass, który ma implementować oraz jego nazwę. Następnie dodać możemy (i zwykle musimy) dodatkowe właściwości. Przykładowy kod wygląda następująco:

// zakładam istnienie dirEnt (typ DirectoryEntry)
DirectoryEntry dChild = dirEnt.Children.Add("ou=maxusers","organizationalUnit");
dChild.Properties["ou"].Add("maxusers");
dirEnt.CommitChanges();
dirEnt.Close();
dChild.CommitChanges();
dChild.Close();
(kod dostępny w examples.zip/03_ChildObjects2)

Warto zwrócić uwagę na ten nieco dziwny zapis. Dokonujemy zapisu zmian najpierw obiektu macierzystego. Następnie rozłączamy się i zwalniamy zasoby powiązane w tym obiektem. Wtedy możemy dokonać zapisu danych obiektu potomnego oraz zwolnić zasoby powiązane z nim. Tak naprawdę najważniejsze jest aby dokonać zapisu danych do katalogu. Samo zwalnianie zasobów nie jest konieczne do poprawnego zapisania nowego obiektu.

Usuwanie obiektów też należy do ciekawych czynności. Wiemy już, iż obiekty potomne są typu DirectoryEntries, czyli są kolekcją obiektów typu DirectoryEntry. Kolekcja DirectoryEntries udostępnia metodę służącą do odnalezienia obiektu o podanej jako string nazwie. Podać należy RDN obiektu do usunięcia względem obiektu macierzystego, czyli np. Find(„ou=users”). Oczywiście nie możemy usunąć obiektu, z którym jesteśmy aktualnie połączeni. Wydaje sie to całkiem logiczne, iż nie pozwala się nam „podciąć gałęzi, na której siedzimy”. Przykładowy fragment kodu to:

// zakładam istnienie dirEntry jako obiektu klasy DirectoryEntry
DirectoryEntries children = dirEnt.Children;
DirectoryEntry toRemove = children.Find("ou=maxusers");               
children.Remove(toRemove);
dirEnt.Close();
(kod dostępny w examples.zip/03_ChildObjects2)

Ciekawostką dotyczącą usuwania obiektów z Active Directory jest nietypowe działanie metody Find. Oczywiście poza zwracaniem znalezionego potomka potrafi ona wyrzucić znany nam dobrze wyjątek... COMException. Nie byłoby może w tym nic dziwnego skoro DirectoryServices korzystają z ADSI opartego na COM. Jednakże sam fakt wyrzucania wyjątku w przypadku nie odnalezienia szukanego obiektu jest zastanawiający. Można śmiało stwierdzić, iż zachowanie to nie pasuje do .NET Framework, które winno zwrócić, np. pustą referencję. Idąc tym tropem doszedłem do wniosku, iż „wyszukiwanie” polega na próbie połączenia i odczytania wszystkich właściwości obiektu. Co w przypadku braku takiego obiektu owocuje znanym już dobrze wyjątkiem(oczywiście COMException). Ten fragment .NET Framework sprawia wrażenie niedopracowanego.

WYSZUKIWANIE OBIEKTÓW

Active Directory, jak i inne usługi katalogowe zdecydowanie często wykorzystywane są do wyszukiwania przeróżnych danych. W końcu jest to jedna z ważniejszych ich funkcjonalnosci obok utrzymywania porządku, bezpieczeństwa i ułatwiania administracji. Oczywiście przechodzenie poprzez wszystkie obiekty i sprawdzanie, czy nie mają interesujących nas właściwości jest raczej mało efektywne i graniczy z absurdem. Tak więc usługa Active Directory udostępnia interfejs służący do wyszukiwania obiektów spełniających pewne, interesujące nas kryteria. Za wyszukiwanie danych w DirectoryServices odpowiada klasa DirectorySearcher. Inicjalizujemy obiekt tejże klasy za pomocą obiektu klasy DirecotryEntry. Tym samym określamy korzeń, od którego rozpoczynamy poszukiwania. Określić możemy wiele właściwości tej klasy, które służą do zawężania zakresu poszukiwań i uzyskiwania danych wartościowych dla szukającego. Kolejny fragment kodu przedstawia przykładową konfigurację przeszukiwania:

// zakładam istnienie dirEntry jako obiektu klasy DirectoryEntry
DirectorySearcher searcher = new DirectorySearcher(dirEntry);
searcher.Filter = "(&(objectClass=person)(&(name>=Adm)(name<=N)))";
searcher.ReferralChasing = true;
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertyNamesOnly = false;
searcher.PropertiesToLoad.Add("sn");
searcher.PropertiesToLoad.Add("cn");
searcher.PropertiesToLoad.Add("description");
searcher.PropertiesToLoad.Add("telephoneNumber");
SearchResultCollection results = searcher.FindAll();
foreach(SearchResult res in results)
{
Console.WriteLine(res.Path);
}
(kod dostępny w examples.zip/06_SearchExample)

Pierwsza linia powyższego kodu tworzy obiekt odpowiedzialny za przeszukiwanie katalogu. Następnie określamy Filter zwany także „zapytaniem LDAP” lub też fragmentem tegoż właśnie zapytania. Warto zwrócić uwagę na to, iż to zapytanie podane w przykładzie zwracać ma wszystkich użytkowników, których imię jest leksykograficzne „większe-równe” „Adm” i „mniejsze-równe” „N”. Tak samo ciekawa jest notacja prefixowa oraz możliwość użycia operatorów logicznych, wyrażeń matematycznych oraz znaków „wildcard”. Dalej za pomocą właściwości ReferralChasing określamy czy mamy podążać za odwołaniami do innych serwerów. Za pomocą SearchScope określamy, jak głęboko mamy „schodzić” w hierarchii obiektów podczas poszukiwań. W powyższym kodzie przeszukamy całe poddrzewo. Właściwość PropertyNamesOnly oznacza, iż nie pobieramy żadnych obiektów wraz z ich właściwościami a tylko same nazwy. Potrafi to znacznie przyspieszyć szukanie. Kolekcja PropertiesToLoad określa jakie właściwości mamy załadować do wyników wyszukiwania. Jeżeli wiemy, co dokładnie nas interesuje, możemy znacznie przyspieszyć czas wyszukiwania. Domyślnie, jeśli nie manipulujemy przy tej kolekcji, ładowane są wszystkie właściwości obiektu. Na samym końcu jest najciekawsza metoda: FindAll(). Zwraca ona zbiór wszystkich obiektów, które spełniają określone przez nas kryteria. Oczywiście, jeżeli nie znajdzie żadnego obiektu, to nie wyrzuca żadnego wyjątku (patrz proszę: ostatni paragraf „Edycja obiektów” – metoda Find(string name)). Istnieje także metoda, która zwraca pojedynczy, pierwszy wynik wyszukiwania: FindOne().

CÓŻ WIĘCEJ W „AD LDAP Explorer”?

Celowo umieściłem krótki opis tej aplikacji na samym końcu artykułu, gdyż wszystkie przykłady opisane przeze mnie do tej pory stanowią jednocześnie opis części mechanizmów zawartych w aplikacji „AD LDAP Explorer”. Aplikacja ta służy do przeglądania, edycji i wyszukiwania obiektów w hierarchicznych bazach danych Active Directory. Większość jej funkcjonalności dostępna jest też dla wielu serwerów zgodnych z LDAP. Dlaczego tak jest? Wprawdzie podaje się, iż AD korzysta z LDAP, to prawdą jest, iż Active Directory jest nadzbiorem funkcjonalności LDAP. Tak więc usługi te nie muszą być obustronnie kompatybilne, lecz bazują na tym samym protokole LDAP (w chwili obecnej LDAPv3). Korzystając z np. OpenLDAP nie odczytamy schematu usługi tak, jak w Active Directory. Odczyt jej odbywa się z „LDAP://hostaddress/RootDSE” poprzez odczytanie właściwości schemaNamingContext, która zawiera adres do obiektu określającego schemat. Poprzez odczytanie potomków tegoż obiektu uzyskujemy obiekty zawarte z schemacie usługi.

Głównym elementem „AD LDAP Explorer`a” jest klasa LDAPRunner, gdzie zawarta jest najważniejsza logika aplikacji.

Rys. 4 AD LDAP Explorer

W aplikacji zawarłem przykład wizualizacji wyników otrzymywanych z usługi katalogowej. Jest to drobiazg, lecz ma on duży wpływ na szybkość odnajdywania obiektów przez użytkownika. Odbywa się to poprzez sprawdzenie klas implementowanych przez obiekt podczas wyświetlania obiektów potomnych. Jeżeli obiekt implementuje klasę group to jego ikonka znana z MSN Messengera.

Aplikację i jej kod znajdziecie w pliku adexplorer.zip. Natomiast w pliku examples.zip zawarłem także (poza tymi wspomnianymi w artykule) inne proste, elementarne aplikacje.

SŁÓW KILKA NA ZAKOŃCZENIE

W niniejszym artykule zaprezentowałem, jak wykorzystać klasy z przestrzeni nazw System.DirectoryServices do uzyskania dostępu do danych zawartych w Active Directory. Najważniejsze z nich to DirectoryEntry oraz DirectorySearcher. Pierwsza z nich służy do uzyskiwania bezpośredniego dostępu do obiektów z bazie danych AD, edycji właściwości, dodawania oraz usuwania obiektów. Reprezentują one obiekt Active Directory po stronie klienta.  Natomiast druga służy do wyszukiwania obiektów według zadanych kryteriów. Bardzo ciekawą właściwością klasy DirectorySearcher jest Filter. Jest to łańcuch, który umożliwia pisanie zapytań dowolnie ograniczających i zawężających wyniki poszukiwań.

Po lekturze artykułu zastanawiać może zapewne, co stało się z ogromem różnych klas i interfejsów udostępnianych przez ADSI widzianych z poziomu COM, a niewidocznych w .NET. Niestety wiele z nich nie zostało udostępnionych, można je jednak nadal osiągnąć. Jednym ze sposobów uzyskania do nich dostepu jest metoda Invoke(string methodName, params object[] args), dzięki której możemy wykonywać metody na natywnym ADSI podając nazwę metody i tablicę obiektów, które są jej argumentami. Innym wyjściem może być dodanie do projektu referencji (z zakładki COM w Visual Studio) o nazwie Active DS Type Library. Dzięki temu możemy mieć surowy dostęp do wszystkich możliwości ADSI. Lecz to jest doskonały materiał na inny artykuł...  

Miejsca, które warto odwiedzić:

Załączniki:

Podobne artykuły

Komentarze 32

User 79341
User 79341
39 pkt.
Poczatkujacy
21-01-2010
oceń pozytywnie 0
temat niezwykle ciekawy, przydatny, i swietnie opisany jedynym zastrzezeniem jest niewystarczajaca dawka - domagam sie wiecej ;)
will0w
will0w
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Ciekawy temat, dość skomplikowany ale dobrze opisany. Jak dla mnie w artykule znajduje się za dużo teorii, a za mało opisanych przykładów, które lepiej by przedstawiały problem.
User 83081
User 83081
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
dopiero co zajrzałem na codeguru a tu bardzo fajny artykuł. temat rzadko spotykany dlatego +1pkt. wydaje mi się, iż jest to pierwsza publikacja tego typu w języku polskim. do tej pory w Polsce spotkać się można z administracyjnym podejściem do AD a tu... programowe :). dodatkowo przystępnie opisany dostęp do usług katalogowych AD i LDAP, wspomniane o rodowodzie API (COM ADSI). bardzo ciekawy materiał
User 82921
User 82921
1 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Rewelacja. Artykuł na wysokim poziomie, teoria i praktyka oraz ciekawostki! Zgadzam się z jedną z opinii, że mogło by być więcej przykładów... ale dla mnie i tak OK - przynajmniej żadna klikologia!!! Tak dalej!
jrozewski517
jrozewski517
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Autor kolejny raz wspiął się na wyżyny swoich możliwosci.
admin8523
admin8523
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Super wlasnie tego sukałem
User 79013
User 79013
171 pkt.
Junior
21-01-2010
oceń pozytywnie 0
AD potrafi dużo, dużo więcej - to tylko napowietrzna część tej góry lodowej. Brak szczegółówych przykładów to minusik, ach gdybym miał czas coś napisać ;-)
masta
masta
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Trafiłem tu z linka na www.windows2003.pl :) i jestem zadowolony, że poświęciłem czas na rejestrację. Zgadzam się z komentarzami! Traktuję ten artykuł jako przeznaczony dla osób raczej początkujących. Dlatego dobrze, że jest i LDAP i wstęp do usług katalogowych. JEst to tylko mały fragment AD... lecz o AD książki pisać można! Niewątpliwie od takich właśnie przykładzików zacząć można przygodę z programistycznym wykorzystaniem Active Directory - TAKI MAŁY KROK, OD KTÓREGO ROZPOCZYNA SIĘ CAŁA WĘDRÓWKA :) Za ten mały krok (nie tami mały!) "7"!!!
zooly
zooly
1812 pkt.
Guru
21-01-2010
oceń pozytywnie 0
Przystępny opis niewątpliwie szerokiego zakresu materiału. W sieci można znaleźć o tym niewiele materiałów (chodzi o AD z punktu widzenia programisty). Jeśli już jakieś są, to traktują tylko o przeglądaniu zasobów serwera. Dla wielu niewtajemniczonych ten artykuł będzie bardzo pomocny. Jeśli ktoś czuje niedosyt to zapraszam do napisania własnego artykułu o AD i LDAP. Brak czasu to dla mnie żadna wymówka.
sebastiancodeguru851
sebastiancodeguru851
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Świetny artykuł!!! Polecam! Za pomocą "google" i "windows2003.pl" można wiele rzeczy znaleźć!!
gronkowiec
gronkowiec
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
specjalnie rejestrowałem się dla tego artykułu i nie zawiodłem się. zgrabny, ciekawy... chciałbym nieco więcej informacji na ten temat, ale generalnie takowych brakuje na necie. taki materiał powinien być też na windows2003.pl...
kasprzol
kasprzol
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Bardzo dobry artykuł. W sumie nie można mu nic zarzucić. Oby więcej takich artykułów!
malecki
malecki
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
-> Ogólne wrażenie: bardzo dobre <- PLUSY: czytelny, idealny dla osób znających już .NET ale chcących conieco więcej się nauczyć o usługach katalogowych, przyjemnie się czyta, nie ma niepotrzebnych informacji, same konkrety, kilka słów o LDAP = dobry wstęp, całkiem dobre kawałki kodu MINUSY: drobne nieścisłości związane z nazewnictwem atrybutów a właściwości (http://www.windows2003.pl/news.aspx?id=1294&cat=D&m=c), jednak nie zmieniają istoty rzeczy, może za mało przykładów (albo się czepiam...), na rys.1 ikonki (diagram w Visio) zaczerpnięte z AD a nie LDAP... ale to celowo się już czepiam (nie ma to wpływu żadnego).
User 82713
User 82713
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Zgadzam się z moderatorem! Poza tym: ŚWIETNY artykuł. Bardzo, bardzo rzadka tematyka. Opis niczego sobie. Wreszcie można się wczytać w jasno napisany artykuł poruszający nie taką łatwą temetykę(raczej trudną). Zgadzam się z P. S.Turalskim, że to napowietrzna część AD, lecz... 10 STRON A4 ogranicza ;( A pisanie o sztuczkach Active Directory na portalu CG (które trafiłyby do może paru osób) mija się z celem. Dlatego najwyższa nota.
User 79653
User 79653
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Ciekawy, klarowny artykuł. Tematyka poruszana nie jest łatwa. Także jej znajomość pośród większości programistów jest znikoma, więc to podnosi jego walory. W zasadzie ukazane są najważniejsze podstawy dostępu do AD. Duży plus za słów kilka o LDAP, jeszcze większy plus za wspomnienie o ADSI. Przynajmniej wiadomo, że System.DirecotryServices nie wzięło się z „nieba”... Uwag brak. Jeżeli by były, to raczej byłyby czepianiem się na siłę...
User 79379
User 79379
9 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
świetny artykuł! bardzo wiele z niego wysniosłem, naprawde dobra robota - tak trzymać:)
m_niedzielski8571
m_niedzielski8571
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
o Active Dir wiedzialem niewiele. czytajac ten artykul dowiedziałem się bardzo dużo. dzieki
kawecki
kawecki
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
bardzo cenny materiał. pozdrawiam
mozejkopawel
mozejkopawel
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
doskonały by dowiedziec sie o uslugach katalogowych, o ich podstawach i ich ideii. przejrzyste jako wstep. bardzo ciekawe, ze mozna polaczyc .NET, programowanie w C# z Active Directory. to daje do myslenia, ze .NET jest(staje sie) zbiorem polaczonych technologii. Artykuł w niektorych miejscach moze jest zbyt trudny. ok, tematyka nie jest zbyt latwa. Coz... reszte powiedzieli inni. Pozro!
uzytkownik usuniety
uzytkownik usuniety
3556 pkt.
Guru
21-01-2010
oceń pozytywnie 0
Bardzo dobry artykuł, dużo się z niego dowiedziałem. oby tak dalej:-)
DRECH
DRECH
1 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
domena była plaska „płaska” :))... i jeszcze gdzieś była jakaś literówka, czy coś podobnego. Ale jakie to ma znaczenie - wiadomo o co chodzi. Artykół ogólnie świetny, ale... 1. ReferralChasing jest typu enum ReferralChasingOption (All, External, None, Subordinate). 2. Może się czepiam, ale wydaj mi się, że zapytanie do Filter warto było opisać trochę lepiej (dokumentacja jest chyba jaśniejsza).
enowak8762
enowak8762
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Artykuł dosyć ciekawy, przekazuje sporo wiedzy na temat usług katalogowych. Pytanie tylko do czego tak specjalizowane informacje można wykorzystać? Do samego przeglądania AD? Przydałoby się więcej praktycznych przykładów.
tokarski_798764
tokarski_798764
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Dosyć sprawnie napisany artykuł, w sumie nie można mu wiele zarzucić. Niestety nie pokazuje do czego tak naprawdę można wykorzystać dostęp do AD. Dla samego dostępu? Trochę to mało przekonujące. A do zarządzania AD dostępne są już odpowiednie narzędzia
dziku_19808759
dziku_19808759
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Cytuje: "Taki sobie ten artykuł..."
testa1435
testa1435
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Dobre rzemiosło
m_i_k_e
m_i_k_e
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Bardzo dobry artykul. Co prawda nie lubie dlugich, ale nie wszystko da sie opisac w paru zdaniach. Super.
User 79550
User 79550
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Po prostu perełka!! Kapitalne wprowadzenie, autor nie zagubił się i pomimo sporej objętości jasno prowadzi czytelnika do końca. Mało kodu? W dołączonych plikach jest go przecież całkiem sporo. Super!!!
iwonarygiel8679
iwonarygiel8679
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Za duzo teorii i za malo praktyki. Ktos kto nie zna teorii AD nie szuka przykladow kodu. I odwrotnie
:)
:)
3 pkt.
Nowicjusz
:)
21-01-2010
oceń pozytywnie 0
ciekawy dopracowany material - polecam
kokroc9106
kokroc9106
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Świetny artykuł - widać ogrom pracy włożony w jego przygotowanie. Może przydałoby się więcej zastosowań praktycznych. Ale i tak jest doskonale!
mikolajczyk.d
mikolajczyk.d
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Super! W załączniku jest katalog "OpenLDAP" i tam opisane jest kofiguracja ldap pod Windowsem. Niestety pod adresem nie ma już plików do zainstalowania :(
Czy ktoś mi pomoże? Szukałem na innych stronach ale bezskutecznie. Bardzo mi to jest potrzebne ponieważ piszę program C# który się łączy z bazą ldap a nie mam jak takiej bazy testowej stworzyć :(
[wally]
[wally]
21 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
jest czad!
pkt.

Zaloguj się lub Zarejestruj się aby wykonać tę czynność.