Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Delphi. Получение информации из домена

Модерирует : ShIvADeSt

 Версия для печати • ПодписатьсяДобавить в закладки

Открыть новую тему     Написать ответ в эту тему

FreePaul



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Здравствуйте!
Необходимо с помощью Delphi 7 получить из домена информацию о пользователе: Имя, Фамилию, описание, комнату, Организацию, все OU.
При этом нам известно имя входа пользователя и программа, получающая эти сведения, запускается на компьютере пользователя, информацию о котором нужно собрать.
Возможно ли это? Или хотя бы что-то из перечисленного? И самое главное - как?

----------
Восход Солнца - это хорошо для начала...

Всего записей: 935 | Зарегистр. 07-08-2002 | Отправлено: 09:39 22-05-2015 | Исправлено: FreePaul, 05:44 28-05-2015
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Посмотрите в MSDN про ADSI
 
Насколько помню, и через ADO можно было выгребать объекты из Active Directory...

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 09:52 22-05-2015
MrZeRo



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
https://msdn.microsoft.com/en-us/library/ms806997.aspx#buildingadapps_using_good_adsi
 
Там есть примеры.

----------
... не это главное ...

Всего записей: 831 | Зарегистр. 30-01-2002 | Отправлено: 16:24 25-05-2015
asadaf



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
FreePaul, вот пример получения E-mail адреса пользователя из домена. Остальные атрибуты можно получить аналогично.

Код:
uses
  SysUtils, Variants, Dialogs, AdsTypes, ActiveDs_TLB, ComObj;
 
const
  ADUsrName = 'Имя пользователя';
  ADUsrPwd = 'Пароль';
  PDCName = 'Домен';
 
// Получение Email пользователя из AD
function GetUserEmail(const UserLogin: String; var ErrorStr: String): String;
var
  ADOConnection, ADOCmd, Res: Variant;
  sBase, sFilter, sAttributes: String;
  ADsUser: IADsUser;
begin
  Result := '';
  try
    ADOConnection := CreateOleObject('ADODB.Connection');
    ADOCmd := CreateOleObject('ADODB.Command');
    try
      ADOConnection.Provider := 'ADsDSOObject';
      ADOConnection.Properties('User ID') := ADUsrName;
      ADOConnection.Properties('Password') := ADUsrPwd;
      ADOConnection.Properties('Encrypt Password') := False;
      ADOConnection.Open('Active Directory Provider');
      ADOCmd.ActiveConnection := ADOConnection;
      ADOCmd.Properties('Page Size')     := 100;
      ADOCmd.Properties('Timeout')       := 30;
      ADOCmd.Properties('Cache Results') := False;
 
      sBase       := '<LDAP://' + PDCName + '>';
      sFilter     := '(&(objectCategory=person)(objectClass=user)(sAMAccountName=' + UserLogin + '))';
      sAttributes := 'ADsPath';
 
      ADOCmd.CommandText := sBase + ';' + sFilter + ';' + sAttributes + ';subtree';
      Res := AdoCmd.Execute;
 
      if not Res.EOF then
      begin
        OleCheck(ADsOpenObject(Res.Fields[0].Value, ADUsrName, ADUsrPwd,
          ADS_SECURE_AUTHENTICATION, IADsUser, ADsUser));
        Result := ADsUser.EmailAddress;
      end else
        raise Exception.Create('Учетная запись не найдена в AD');
    finally
      ADOCmd := Unassigned;
      ADOConnection.Close;
      ADOConnection := Unassigned;
    end;
  except
    on E: Exception do
      ErrorStr := E.Message;
  end;
end;

Всего записей: 138 | Зарегистр. 27-01-2007 | Отправлено: 08:05 27-05-2015 | Исправлено: asadaf, 08:06 27-05-2015
FreePaul



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
KDPoid
MrZeRo
Спасибо. Пробую разобраться.
 
asadaf
У меня Delphi ругается на отсутствие AdsTypes...
 
Кроме того, если я правильно понял - необходимо вводить имя пользователя и пароль. Имя пльзователя я еще могу получить с помощью Jedi, а вот с паролем - проблема. Программка должна запускаться на компьютерах пользователей и без их участия заполнять удаленную БД данными:
Пользователь (Username)
Компьютер (Computername)
IP-адрес
Ф.И.О. пользователя
Кабинет

В идеале бы еще - все группы, в которые он включен, заблокирован или нет...
 
***
 
И попутно еще вопрос:
испытываю различные костыли, возникла необходимость в получении имени домена вида
OU=ххх,OU=ххх,DC=ххх,DC=ххх,DC=ххх,DC=ru
При этом, так как хочу потом программу раздавть ("...безвоздмездно, то есть даром!" (с)), вложенность DC и OU может быть разной (соответственно, и DC=ru тоже может быть другой).
Возможно ли стандартными средствами получить эту строку?


----------
Восход Солнца - это хорошо для начала...

Всего записей: 935 | Зарегистр. 07-08-2002 | Отправлено: 04:23 28-05-2015 | Исправлено: FreePaul, 05:43 28-05-2015
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
FreePaul,
Давайте посмотрим на исходник...

Цитата:
 
      ADOConnection.Properties('User ID') := ADUsrName;  
      ADOConnection.Properties('Password') := ADUsrPwd;  
 

Это параметры подключения к AD. Логин и пароль того пользователя, который имеет право получать информацию. Например, администратор домена

Цитата:
   sFilter     := '(&(objectCategory=person)(objectClass=user)(sAMAccountName=' + UserLogin + '))';

UserLogin - Логин пользователя, который вам интересен. Его пароль - не нужен.
 

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 06:30 28-05-2015
asadaf



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
FreePaul
Имя пользователя и пароль (это технический пользователь), если программа запускается на ПК, который не в домене. Если программа запускается на ПК в домене, то имя пользователя и пароль не нужны.
Ф-я определения пользователя:

Код:
function GetCurrentUserName: AnsiString;
const
  cnMaxUserNameLen = 256;
var
  sUserName: String;
  dwUserNameLen: DWORD;
begin
  dwUserNameLen := cnMaxUserNameLen;
  SetLength(sUserName, cnMaxUserNameLen);
  GetUserName(PChar(sUserName), dwUserNameLen);
  SetLength(sUserName, dwUserNameLen - 1);
  Result := AnsiString(AnsiUpperCase(sUserName));
end;

 
Отключена учетка или нет можно определить с помощью:

Код:
IADsUser.AccountDisabled

 
Я писал на Delphi XE там есть AdsTypes. Оттуда нужна только ф-я ADsOpenObject

Код:
const
  ActiveDSDll         =   'activeds.dll';
function ADsOpenObject(lpszPathName:WideString;
                       lpszUserName:WideString;
                       lpszPassword:WideString;
                       dwReserved:DWORD;
                       const riid:TGUID;
                       out ppObject): HRESULT; stdcall;
var
  hMod : THandle;  
  FuncProc : function(lpszPathName: WideString; lpszUserName: WideString;
                       lpszPassword: WideString; dwReserved: DWORD;
                       const riid : TIID; out obj) : HRESULT; stdcall;
begin
  Result := ERROR_GEN_FAILURE;
  hMod := LoadLibrary(ActiveDsDll);
  if hMod > 0 then
  begin
    try
      @FuncProc := GetProcAddress(hMod, 'ADsOpenObject');
      if (@FuncProc <> nil) then
      begin
        Result := FuncProc(lpszPathName, lpszUserName, lpszPassword, dwReserved, riid, ppObject);
      end;
    finally
      FreeLibrary(hMod);
    end;
  end;
end;

 
KDPoid

Цитата:
Это параметры подключения к AD. Логин и пароль того пользователя, который имеет право получать информацию. Например, администратор домена

Любой пользователь домена имеет право читать все атрибуты. Администратор домена это слишком много прав, достаточно пользователь домена.
 

Всего записей: 138 | Зарегистр. 27-01-2007 | Отправлено: 07:59 28-05-2015 | Исправлено: asadaf, 08:21 28-05-2015
FreePaul



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
KDPoid
asadaf
Спасибо! Завтра на работе буду разбираться (дома нету AD ). Наверное, подзависну...

Всего записей: 935 | Зарегистр. 07-08-2002 | Отправлено: 13:56 28-05-2015
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
asadaf,

Цитата:
...Администратор домена это слишком много прав...
Изначально, там был смайл...

Цитата:
Имя пользователя и пароль (это технический пользователь), если программа запускается на ПК, который не в домене. Если программа запускается на ПК в домене, то имя пользователя и пароль не нужны.

Если машинка в домене, а юзер зашёл под локальной учёткой, а не доменной и запустил программульку...
Мы в коннекции логин-пароль доменного пользователя не указываем, текущие у нас - не доменные, разве нам домен отдаст данные о пользователях ?

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 15:11 28-05-2015 | Исправлено: KDPoid, 15:14 28-05-2015
FreePaul



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
asadaf

Код:
 const
  ActiveDSDll         =   'activeds.dll';
function ADsOpenObject(lpszPathName:WideString;
                       lpszUserName:WideString;
                       lpszPassword:WideString;
                       dwReserved:DWORD;
                       const riid:TGUID;
                       out ppObject): HRESULT; stdcall;
var
  hMod : THandle;  
  FuncProc : function(lpszPathName: WideString; lpszUserName: WideString;
                       lpszPassword: WideString; dwReserved: DWORD;
                       const riid : TIID; out obj) : HRESULT; stdcall;
begin
  Result := ERROR_GEN_FAILURE;
  hMod := LoadLibrary(ActiveDsDll);
  if hMod > 0 then
  begin
    try
      @FuncProc := GetProcAddress(hMod, 'ADsOpenObject');
      if (@FuncProc <> nil) then
      begin
        Result := FuncProc(lpszPathName, lpszUserName, lpszPassword, dwReserved, riid, ppObject);
      end;
    finally
      FreeLibrary(hMod);
    end;
  end;
end;
 

 
В таком случае ругается: "Unknown identifier: 'TIID'"
И опять же, в коде далее требуется пароль:

Код:
if not Res.EOF then
   begin
        OleCheck(ADsOpenObject(Res.Fields[0].Value, ADUsrName, ADUsrPwd,
          ADS_SECURE_AUTHENTICATION, IADsUser, ADsUser));
        Result := ADsUser.EmailAddress;  

а задача стоит - без участия пользователя собрать информацию...
 
Мдяяя, не все так просто...
 
Добавлено:
KDPoid, asadaf
Я пошел немного другим путем и просто положил на форму ADOConnection и ADOCommand. В ADOConnection создал Connection String с указанием в качестве поставщика данных "OLE DB Provider for Microsoft Directory Services" и на вкладке "Соединение" - использовать встроенную безопасность Windows NT
ИМХО, по такой настройке пользователь может получить сведения о себе после логина в домен. Если запускать программу в логон-скрипте, то это условие (после логина в домен) будет ведь выполнено?  
В таком случае я вызываю Jedi'вскую функцию GetLocalUserName и получаю имя залогиненного пользователя. Кроме того, я могу получить IP-адрес компьютера и его DNS-имя. А вот со всем остальным - засада... И пароль я не могу у него спросить, т.к. это будет нарушением безопасности (да и не должен он давать пароль любой запрашивающей его программе!). И жестко вбить в программу логин/пароль администратора тоже не могу, ведь это во-первых тоже будет нарушением безопасности (логин/пароль можно будет вытянуть из исполняемого файла), а во-вторых при передаче программы другому пользователю, в его сети логин/пароль администратора будет совсем другой.
 
Могу, кроме того, через ADOQuery выполнить такой запрос:

Код:
SELECT AdsPath, CN, SN, location
FROM 'LDAP://ou=ХХХ,ou=ХХХ,dc=YYY,dc=YYY,dc=YYY,dc=ru'
WHERE  
objectClass='user'  

При этом в CN я получу Ф.И.О. НО мне нужно каким-то образом получить строку с именем OU, к которому принадлежит учетная запись пользователя, запустившего программу.
 
Кстати, вопрос: почему при SELECT */SELECT ALL я не получаю ничего?
ORDER BY sn

Всего записей: 935 | Зарегистр. 07-08-2002 | Отправлено: 04:20 29-05-2015 | Исправлено: FreePaul, 05:09 29-05-2015
KDPoid



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
FreePaul,

Цитата:
 
В таком случае ругается: "Unknown identifier: 'TIID'"  
И опять же, в коде далее требуется пароль:  
 


Код:
 
unit ActiveX;
...
  PIID = PGUID;
  TIID = TGUID;
 

Ну и, раз пошла такая пьянка...  

Код:
 
unit System;
...
  PGUID = ^TGUID;
  TGUID = packed record
    D1: LongWord;
    D2: Word;
    D3: Word;
    D4: array[0..7] of Byte;
    class operator Equal(const Left, Right: TGUID): Boolean;
    class operator NotEqual(const Left, Right: TGUID): Boolean;
    class function Empty: TGUID; static;
  end;
 

 

Цитата:
 

Код:
 
if not Res.EOF then  
   begin  
        OleCheck(ADsOpenObject(Res.Fields[0].Value, ADUsrName, ADUsrPwd,  
          ADS_SECURE_AUTHENTICATION, IADsUser, ADsUser));  
        Result := ADsUser.EmailAddress;  
 

а задача стоит - без участия пользователя собрать информацию...  
 

Как мы писали, это пароль интересующегося, т.е. можно использовать какую-нибудь техническую, служебную учётную запись. Обычно, все  пользователи домена имеют доступ к информации друг друга. Создайте технологическую учётку и обращайтесь в домен от её имени.
 

Цитата:
 
Кстати, вопрос: почему при SELECT */SELECT ALL я не получаю ничего?  
ORDER BY sn
 

Насколько помню, дело в звёздочке. Ни каких "отдай мне всё" здесь не работает
Нужно перечислить поля.

Всего записей: 404 | Зарегистр. 08-08-2006 | Отправлено: 06:22 29-05-2015
asadaf



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
FreePaul

Цитата:
Я пошел немного другим путем и просто положил на форму ADOConnection и ADOCommand.
Можно и через ADO, только при этом размер exe увеличится при том же функционале. Если ты хочешь делать запрос, текущим пользователем AD, то используй вместо AdsOpenObject AdsGetObject:
Код:
function ADsGetObject(lpszPathName:WideString; const riid:TGUID;
                      out ppObject): HRESULT; stdcall;
var
  hMod : THandle;  
  FuncProc : function(lpszPathName : WideString; const riid : TIID; out obj) : HRESULT; stdcall;
begin
  Result := ERROR_GEN_FAILURE;
  hMod := LoadLibrary(ActiveDsDll);
  if hMod > 0 then
  begin
    try
      @FuncProc := GetProcAddress(hMod, 'ADsGetObject');
      if (@FuncProc <> nil) then
      begin
        Result := FuncProc(lpszPathName, riid, ppObject);
      end;
    finally
      FreeLibrary(hMod);
    end;
  end;
end;

Код:
if not Res.EOF then  
   begin  
        OleCheck(ADsGetObject(Res.Fields[0].Value, IADsUser, ADsUser));  
        Result := ADsUser.EmailAddress;
Тут не нужно указывать логин и пароль.

Цитата:
Кстати, вопрос: почему при SELECT */SELECT ALL я не получаю ничего?
ORDER BY sn
Запросы к LDAP это не совсем так, как SQL к обычным БД. Тут нужно указывать имена атрибутов обязательно, как сказал KDPoid. Плюс еще, если кол-во записей будет больше MaxValRange - получишь ошибку.
 
 

Всего записей: 138 | Зарегистр. 27-01-2007 | Отправлено: 08:17 29-05-2015 | Исправлено: asadaf, 08:28 29-05-2015
FreePaul



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Парни, спасибо! Теперь уже до вторника, т.к. до компьютера с доменом мне до этого времени не добраться... Буду пока так вникать...

Всего записей: 935 | Зарегистр. 07-08-2002 | Отправлено: 11:47 29-05-2015
FreePaul



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Спасибо огромное всем! Вроде получилось!!!
Если кому интересно:
Посмотреть...

----------
Восход Солнца - это хорошо для начала...

Всего записей: 935 | Зарегистр. 07-08-2002 | Отправлено: 05:53 17-06-2015 | Исправлено: FreePaul, 05:55 17-06-2015
asadaf



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
FreePaul
Получение всех этих атрибутов можно было оформить одной функцией, которая возвращает список.

Всего записей: 138 | Зарегистр. 27-01-2007 | Отправлено: 10:14 17-06-2015
FreePaul



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
asadaf
Ну, я самоучка. Вообще я по образованию - бухгалтер. )) Понимаю, что что-то не так, но как та собака - сказать не могу... ))

Всего записей: 935 | Зарегистр. 07-08-2002 | Отправлено: 14:11 17-06-2015
FreePaul



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Здравствуйте!
Пишу обратно в эту же тему, т.к. вопрос вновь по использованию Delphi и получению информации из AD.
Имею:  
Delphi 10.1, ADOConnection + ADOQuery. Запрос:

Код:
SELECT  
cn ,ou , whenCreated ,whenChanged ,Name ,distinguishedName ,ADsPath ,
sAMAccountName ,userPrincipalName, mail ,otherMailbox,
proxyAddresses ,dNSHostName ,operatingSystem ,operatingSystemVersion ,operatingSystemServicePack,
logonCount, Department, physicalDeliveryOfficeName, description, title, userAccountControl, pwdLastSet,
accountExpires
 
FROM 'LDAP://XXX'
 
WHERE objectClass='user' and objectClass<>'computer'  
 
order by name ASC

Все это "добро" через стандартный же DataSource выводится в DBGridEh. Однако, при запуске приложения получаю ошибку вида:

Цитата:
Project <XXX> raised exception class EVariantTypeCastError with message 'Could not convert variant of type (Dispatch) into type (OleStr)'.

 
Я понимаю, что в БД ActiveDirectory часть данных хранятся, мягко говоря, не совсем в том виде, в котором мне хотелось бы их видеть. Но, к сожалению, к SQL-запросу, получающему эти данные, невозможно добавить процедуры преобразования.
Все, что я смог нагуглить - это решения примерно 2013 года с использованием к примеру IADsLargeInteger. Если я правильно понял, в D10.1 выпилен IADsLargeInteger.
 
Как можно получить удобочитаемые и понимаемые стандартными (и EhLib'овскими) компонентами сведения?
В частности, интересуют description, accountExpires

Всего записей: 935 | Зарегистр. 07-08-2002 | Отправлено: 05:14 30-01-2017 | Исправлено: FreePaul, 05:19 30-01-2017
Открыть новую тему     Написать ответ в эту тему

Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Delphi. Получение информации из домена


Реклама на форуме Ru.Board.

Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
Modified by Ru.B0ard
© Ru.B0ard 2000-2024

BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

Рейтинг.ru