Как запросить ActiveDirectory из собственного кода Win32 (т.е. не .NET) - PullRequest
0 голосов
/ 19 декабря 2011

Если бы я хотел получить информацию о пользователе из Active Directory в .NET, я мог бы использовать класс DirectorySearcher.

Например, чтобы найти адрес электронной почты пользователя, которого я бы назвал:

public String GetUserEmailAddress(String accountName)
{
    DirectorySearcher searcher = new DirectorySearcher();
    searcher.Filter = String.Format("(&(objectCategory=user)(sAMAccountName={0}))", accountName);
    searcher.PropertiesToLoad.Add("mail");

    SearchResult searchResult = searcher.FindOne();

    return searchResult.Properties["mail"][0];
}

Каков собственный способ запроса Active Directory?

Примечание :

  • доменное имя не указано
  • имя сервера не указано

Мы даже можем расширить нашу функцию, чтобы разрешить запрашивать любую универсальную произвольную информацию:

public Object GetUserAttribute(String accountName, String propertyName)
{
    DirectorySearcher searcher = new DirectorySearcher();
    searcher.Filter = String.Format("(&(objectCategory=user)(sAMAccountName={0}))", accountName);
    searcher.PropertiesToLoad.Add(propertyName);

    SearchResult searchResult = searcher.FindOne();

    return searchResult.Properties[propertyName][0];
}

AD содержит все виды информации, которую вы можете передать как propertyName. Например:

  • displayName (Отображаемое имя): отображаемое имя для объекта. Обычно это сочетание имени пользователя, отчества и фамилии пользователя. (например, Ян А. Бойд )
  • mail (адреса электронной почты): список адресов электронной почты для контакта. (например, ianboyd@stackoverflow.com)
  • cn (Common-Name): имя, представляющее объект. Используется для поиска.
  • name (RDN): Относительное отличительное имя объекта. (например, Ян Бойд )
  • sn (Фамилия): Этот атрибут содержит фамилию или фамилию пользователя.
  • givenName (Имя-имя): Содержит имя (имя) пользователя.
  • sAMAccountName (SAM-Account-Name): имя для входа, используемое для поддержки клиентов и серверов, работающих под управлением более старых версий операционной системы, таких как Windows NT 4.0, Windows 95, Windows 98 и LAN Manager. Этот атрибут должен содержать не более 20 символов для поддержки старых клиентов.
  • objectGUID (Object-Guid): уникальный идентификатор объекта. (например, {3BF66482-3561-49a8-84A6-771C70532F25} )
  • employeeID (идентификатор сотрудника): идентификатор сотрудника. /// "description" (Description): содержит описание для отображения объекта. Это значение рассматривается системой как однозначное.

Ответы [ 3 ]

1 голос
/ 20 декабря 2011

Первым шагом будет ознакомление с серией статей Учебник по ADSI в Windows IT Pro. Он дает довольно хороший обзор основ ADSI и интерфейсов IADs и того, как их использовать (я полагаю, из VBScript).

Вторым шагом в Delphi будет импорт библиотеки типов Active_Ds - при этом должен быть создан файл ActiveDs_TLB.pas, содержащий основные типы, интерфейсы, методы для работы с Active Directory из родного языка с использованием ADSI.

Чтобы получить доступ к собственным функциям, вам нужно использовать так называемый импорт функций для каждой функции, которую вы хотите - здесь код только для одной - ADsGetObject:

type
  TADsGetObject = function(aPathName: PWideChar; const aRIID: TGUID; out aObject): HResult; safecall;

var
  ADsGetObject : TADsGetObject = nil;

initialization
  hActiveDS := LoadLibrary(PChar('ActiveDS.dll')); // don't localize

  if (hActiveDS = 0) then
    raise Exception.Create(rc_CannotLoadActiveDS);

  LoadProcAddress(hActiveDS, 'ADsGetObject', @ADsG

etObject);

Как только вы создали эти функции из внешней библиотеки, вы можете вызывать их - что-то вроде этого:

var
  hr : HRESULT;
  oIADs : IADs;
  wsTemp : WideString;

begin
   wsTemp := 'LDAP://cn=IanBoyd,cn=Users,dc=YourCompany,dc=com';

   // try to bind to the ADSI object using the "sanitized" path
   hr := ADsGetObject(PWideChar(wsTemp), IID_IADs, oIADs);

   if Succeeded(hr) then begin
      // successful - now retrieve all properties into property cache
      try
        oIADs.GetInfo;
      except
         on EOleSysError do begin
           Exit;
         end;
      end;

      // get the object's GUID
      wsTemp := oIADs.GUID;

      // do more stuff here.....

Далее, также посмотрите мою страницу ADSI Delphi Tips & Tricks - поэтому информация устарела, хотя (как ссылка на коллекционный компакт-диск The Delphi Magazine - кажется, больше не доступна) .

Поиск ADSI с нативным кодом довольно сложен - определенно выходит за рамки такой публикации. Я написал довольно обширную статью об этом - включая пример кода - который можно получить по запросу от меня (отправьте мне электронное письмо на мой адрес в моем профиле).

1 голос
/ 20 декабря 2011

удаленный ответ marc_s оказался самым полезным;но вот ответ на вопрос в псевдокоде:

public GetUserEmailAddress(String accountName): String;
{
   //Get the distinguished name of the current domain 
   String dn = GetDefaultDistinguishedName(); //e.g. "dc=stackoverflow,dc=com"

   //Construct the ldap table name  (e.g. "LDAP://dc=stackoverflow,dc=com")
   String ldapTableName := "LDAP://"+dc;

   //ADO connection string
   String connectionString := "Provider=ADsDSOObject;Mode=Read;Bind Flags=0;ADSI Flag=-2147483648";

   //The sql query to execute
   String sql := 
         "SELECT mail"+CRLF+
         "FROM "+QuotedStr(ldapTableName)+CRLF+
         "WHERE objectClass = "+QuotedStr("user")+CRLF+
         "AND sAMAccountName = "+QuotedStr(userName);

   ADOConnection conn := new ADOConnection(connectionString);
   try
      Recordset rs := conn.Execute(sql);
      try
         if (rs.Eof)
            return "";

         return rs["mail"].Value;
      finally
          rs.Free;
      end;
   finally 
      conn.Free;
   end;
}

Настоящий секрет заключается в том, чтобы говорить с «доменом», а не с каким-либо конкретным сервером:

//get the distinguished name of the current domain
public GetDefaultDistinguishedName(): string;
{
   String path := "LDAP://rootDSE";

   IADs ads;
   ADsGetObject(PWideChar(path), IADs, out ads);

   //e.g. on the "stackoverflow.com" domain, returns "DC=stackoverflow,DC=com"
   return (String)ads.Get("defaultNamingContext"); 
}

Примечание : любой код публикуется в открытом доступе.Указание авторства не требуется.

0 голосов
/ 20 декабря 2011

Нативное программирование - это LDAP, вы можете использовать его в .NET с System.DirectoryServices.Protocols (S.DS.P) .


Отредактировано

Если вас интересует, как запрашивать активный каталог из собственного кода, вы можете взглянуть на API-интерфейс привязки LDAP, как описано в документе RFC 1823, «Поддержите его, см. Стратегия MS для облегченного протокола доступа к каталогам». (LDAP) . Инструкции по использованию и справочные материалы по API Microsoft вы найдете в Облегченный протокол доступа к каталогам .

Здесь вы найдете способ найти Active Directory в сети, не предоставляя никакой информации, кроме правильного DNS-сервера. Вы можете использовать DNS-имя домена в функции ldap_open, так что вам не нужно знать адрес сервера домена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...