9 december 2012

C# LDAP läsa och söka

Att läsa och söka i en katalog.


De vanligaste operationerna en utvecklare utför mot en katalog är att hämta information till den eller det som har behov av det. Vissa förutsättningar måste vara givna innan du börjar. Du måste veta vilken adress Katalogen är placerad. Vidare om du måste använda krypterad förbindelse, s.k LDAPS vilken är en SSL krypterad kommunikation. Du behöver också i de flesta fall ett användarkonto (hädanefter kallad uid) och ett  lösenord (framåt kallad pw) även om anonym åtkomst kan tillåtas. Det brukar vara vanligt i Active Directory (hädanefter kallad AD) till en viss mån. Verksamhetskataloger brukar vara mer låsta.

Sökvägar, domäner, konton osv bör naturligtvis inte ligga hårt kodad utan i konfigurationsfiler, i databaser eller nu vilka rutiner man har. Dock kommer jag i alla exempel för att förenkla med hårdkodade i exempel

Struktur

Det finns nog lika många olika sätt att strukturera sina solutions och projekt som det finns utvecklare. Själv (och fler med mig) brukar ha vissa mappar i solutionsträdet där jag samlar klasser med likartade och specialiserade uppgifter. Hur många mappar och hur man delar upp det kan skilja mellan olika programmerare. Jag brukar dela upp mappstrukturen som bild nedan.


BLL = Business Logic Layer. Affärslogik.
DAL = Data Access Layer. Gränssnitt mot datakällor.
GEN = Generella. Ofta återkommande statiska klasser som jag använder.
MODEL = Modeller. Objekmodeller som fungerar som bärare av information. Också kallad "DTO" (Data transfer objects)
TEST = Här lägger jag testmetoder
UI = User Interface. I detta fall är det en console och då brukar jag lägga mainmetoden där.
Interface är en annan folder jag kan använda där jag separat placerar Interfaces i egna separat .cs filer. Det råder delade meningar om interfaces skall separeras eller deklareras i samma cs fil som basklasserna. Jag har dock valt det försnämnda.


Ansluta 

För att ö.h.t kunna arbeta mot en katalog krävs det först en anslutning vilket jag brukar ha några metoder för. Vanligtvis gör jag det när jag skapar objektet DirectoryEntry som jag sedan använder i olika sammanhang. 

I princip gör jag två olika anslutningar. Den ena där jag alltid ställer mig i början på katalogträdet och den andra där jag vill utgå från en viss plats i katalogen längre ned i trädet. Jag skapar klassen ADprovider i DAL mappen. Variablar som jag normalt läser in kodas här hårt.
===================================

using System.DirectoryServices;


Account.DAL

{

    internal class ADprovider 



     #region fields

            internal static string Domain = "MyDomain";
            internal static string DefaultOU = "MyOu";
            internal static string DefaultRootOU = "MyRoot";
            internal static string ServiceUser = "MyAccount" //Användarkonto med   read/change rättigheter i AD;
            internal static string ServicePassword = "MyPassword";

        #endregion



         #region private methods



        /// <summary>
        /// Skapa en säker anslutning till AD
        /// och returnera ett directoryentry
        /// </summary>
        /// <returns>DirectoryEntry</returns>

         private DirectoryEntry _GetDirectory()
        {

            DirectoryEntry de = new DirectoryEntry(
                    DefaultRootOU ,
                    ServiceUser,
                    ServicePassword,
                    AuthenticationTypes.Secure
                    );

            return de;

        }


       #endregion
}
===================================


Vad är ett DirectoryEntry?

Ett DirectoryEntry är en klass som kapslar in en node eller objekt från AD:et eller en annan katalog. Med hjälp av DirectoryEntry kan du söka, ändra och ta bort data. 


Söka upp en användare i AD

AD scheman skiljer mellan olika verksamheter och tillägg på över 100 attribut är inte ovanligt. Något som dock alltid finns är CN som betyder "Common Name" och alltid är sökbart och förkortas "cn". cn som attribut finns även i DirX. Ponera att vi vill söka upp en användare som heter "Elvira Persson" och således har Common Name satt till det. Dvs cn = Elvira Persson. Detta leder oss också till klassindelning. Varje objekt är en typ av en eller flera klasser. Användare (personer) i AD kan vara av klassen "person" eller "user". 

Klassindelningen är nödvändig eftersom objekt av andra typer än personer också har attributet cn. Och vi vill gärna smala ned sökningen genom att utesluta andra objekt. Andra objekt kan vara säkerhetsgrupper, datorer, servrar etc.

Något annat att veta är att Framework 3 (el möjligen 3.5) kom med klasserna i namespacet System.DirectoryServices.ActiveDirectory, vars assembly ligger i System.DirectoryServices (in System.DirectoryServices.dll, som väsentligen underlättar sökningar. Dessa klasser kapslar in mycket av den koden vi kommer att skriva nu. Dock fungerar dessa inte naturligt i Dirx och vi skall vilket fall börja med att själva använda oss den "gamla hederliga syntaxen" vilket också kan ge en viss inblick i vad MS kapslar in.

Metod sök upp en användare och läs ut dennes Displayname:

using System.DirectoryServices;

 /// <summary>
/// Hämta en användares
/// telefonnummer med CN som
/// sökparameter
/// </summary>
/// <returns>string</returns>
public string GetTelePhonenumber(string pCommonName)
{
     string retVal = string.Empty;


   using (DirectoryEntry de = _GetDirectory())
   {
      using (DirectorySearcher dsFind = new DirectorySearcher(de))
      {
          dsFind.Filter = "(&(objectClass=person)(cn=" + pCommonName+ "))";
          SearchResult rs = dsFind.FindOne();


          if (result != null)
          {

             retVal =  rs.Properties["telePhonenumber"][0].ToString() == null ? ""       :rs.Properties["telePhonenumber"].ToString(),
          }

      }

   }

      return retVal:
}


  •  Kontrollera alltid nullvärden när du kontrollerar/hämtar värdet på ett attribut. Till skillnad mot en databas där man får tillbaka null eller tom sträng så smäller det i Ldap-kataloger om inte attributet finns på personen. I vissa scheman läggs ö.h.t inte attributet till om det inte har tilldelats objeket.
  • Principen ovan fungerar på alla sökningar. Tänk på att det går bra mycket fortare att söka med SearchResult än med DirectoryEntries.
  • Använd allting "Using" i största möjliga mån. Jag har haft problem med minnesläckor i Ldaphantering. Using garanterar att objektet förstörs.



Inga kommentarer:

Skicka en kommentar