Мне часто приходится сталкиваться с обработкой информации из Active Directory. Так как данная система много где распространена, я решил поделиться своим опытом работы с ней.
Началось всё с того, что я раздавал доступ в MS Sharepoint. В заявках от сотрудников, в лучшем случае, приходили учетные записи, в худшем могли написать что-то типа “Мне и моему начальнику”. Это поначалу напрягало, и я, чувствуя себя заправским админом, посылал такие заявки обратно нерадивым юзерам, чтобы они всё переделали. Это превращалось в ворох пропитанных гневом писем и звонков. Я даже стал задумываться, не случайно ли совпадение сокращения от Active Directory – AD с русским словом “Ад”. В итоге, осознав, что надо менять мир к лучшему, я решил детально разобраться, что вообще хранится в Active Directory и как это можно использовать, для автоматической раздачи доступа и других полезных вещей.
В компании информация о сотрудниках хранится в 2-х местах:
Уникальность поддерживается в Oracle, а доступ даётся через AD, т.е. на одного сотрудника может приходиться несколько учетных записей. Возникла необходимость однозначно определять сотрудника по его учетной записи.
Решение этой задачи было найдено и растиражировано во множество утилит и программных продуктов, активно используемых внутри компании. Одной из наиболее используемых утилит стала программа поиска информации по сотруднику. Она ищет сотрудника или сотрудников по различным критериям и выдаёт наиболее полную информацию о них, совмещая данные из Active Directory и Oracle. Особой популярностью пользуются фотографии сотрудников, которые хранятся в базе данных.
Так же стоит отметить интеграцию Active Directory не только с Oracle но и с MS Sharepoint. Благодаря найденному решению появилось приложение способное быстро дать доступ группе пользователей из Active Directory на страницы портала Sharepoint, а так же удалить из него пользователей, которые по различным причинам, ушли из неё.
Задача была решена 2-мя способами:
При использовании C# следует учесть следующее (библиотека System.DirectoryServices.dll):
Так же есть свойство DirectorySearcher.SizeLimit, которое устанавливает максимальное количество записей в возвращаемом результате. По умолчанию оно равно 0, что означает – взять это значение с сервера. На сервере обычно стоит значение 1000. Можно поиграть со свойством SizeLimit и посмотреть, как меняется результат работы функции (ссылка).
По ссылке выше есть пример кода, который использует yiled, что с точки зрения работы .NET более правильно, но в примере ниже я его не использовал, для наглядности алгоритма.
Умение работать с Active Directory и обращаться к нему напрямую из БД Oracle существенно упростило работу программистам отдела, где я работаю. Изначально я, ради эксперимента, выкачал содержимое Active Directory в таблицу базы данных. Потом, к своему удивлению, я обнаружил ряд хранимых процедур, которые работали с этой таблицей. Выяснилось, что разработчики обращались к ней, поленившись разобраться в пакете DBMS_LDAP. Этот прецедент и подтолкнул меня к желанию рассказать и привести примеры того как можно работать с Active Directory.
Началось всё с того, что я раздавал доступ в MS Sharepoint. В заявках от сотрудников, в лучшем случае, приходили учетные записи, в худшем могли написать что-то типа “Мне и моему начальнику”. Это поначалу напрягало, и я, чувствуя себя заправским админом, посылал такие заявки обратно нерадивым юзерам, чтобы они всё переделали. Это превращалось в ворох пропитанных гневом писем и звонков. Я даже стал задумываться, не случайно ли совпадение сокращения от Active Directory – AD с русским словом “Ад”. В итоге, осознав, что надо менять мир к лучшему, я решил детально разобраться, что вообще хранится в Active Directory и как это можно использовать, для автоматической раздачи доступа и других полезных вещей.
В компании информация о сотрудниках хранится в 2-х местах:
- Active Directory
- БД Oracle
Уникальность поддерживается в Oracle, а доступ даётся через AD, т.е. на одного сотрудника может приходиться несколько учетных записей. Возникла необходимость однозначно определять сотрудника по его учетной записи.
Решение этой задачи было найдено и растиражировано во множество утилит и программных продуктов, активно используемых внутри компании. Одной из наиболее используемых утилит стала программа поиска информации по сотруднику. Она ищет сотрудника или сотрудников по различным критериям и выдаёт наиболее полную информацию о них, совмещая данные из Active Directory и Oracle. Особой популярностью пользуются фотографии сотрудников, которые хранятся в базе данных.
Так же стоит отметить интеграцию Active Directory не только с Oracle но и с MS Sharepoint. Благодаря найденному решению появилось приложение способное быстро дать доступ группе пользователей из Active Directory на страницы портала Sharepoint, а так же удалить из него пользователей, которые по различным причинам, ушли из неё.
Задача была решена 2-мя способами:
- Для получения информации по одному сотруднику — DBMS_LDAP в Oracle
- Для того чтобы выкачать все доступные записи и посмотреть, что вообще есть в Active Directory использовали код на C#
При использовании C# следует учесть следующее (библиотека System.DirectoryServices.dll):
- Свойство DirectorySearcher.PageSize должно быть отлично от 0, если хотите чтобы функция FindAll() вернула все записи.
- Обязательно надо вызвать Dispose() для экземпляра DirectorySearcher
Так же есть свойство DirectorySearcher.SizeLimit, которое устанавливает максимальное количество записей в возвращаемом результате. По умолчанию оно равно 0, что означает – взять это значение с сервера. На сервере обычно стоит значение 1000. Можно поиграть со свойством SizeLimit и посмотреть, как меняется результат работы функции (ссылка).
По ссылке выше есть пример кода, который использует yiled, что с точки зрения работы .NET более правильно, но в примере ниже я его не использовал, для наглядности алгоритма.
Примеры кода:
- DBMS_LDAP Oracle
function GetDataByUser(userAccount VARCHAR2) return VARCHAR2 is l_ldap_host VARCHAR2(256) := 'host'; l_ldap_port VARCHAR2(256) := 'port'; l_ldap_user VARCHAR2(256) := 'user'; l_ldap_passwd VARCHAR2(256) := 'password'; l_ldap_base VARCHAR2(256) := 'ldap_path'; l_retval PLS_INTEGER; l_session DBMS_LDAP.session; l_attrs DBMS_LDAP.string_collection; l_message DBMS_LDAP.message; l_entry DBMS_LDAP.message; l_attr_name VARCHAR2(256); l_ber_element DBMS_LDAP.ber_element; l_vals DBMS_LDAP.string_collection; ret VARCHAR2(256); begin DBMS_LDAP.USE_EXCEPTION := TRUE; l_session := DBMS_LDAP.init(hostname => l_ldap_host,portnum => l_ldap_port); l_retval := DBMS_LDAP.simple_bind_s(ld => l_session,dn => l_ldap_user,passwd => l_ldap_passwd); l_attrs(1) := 'postalcode'; l_retval := DBMS_LDAP.search_s(ld => l_session,base => l_ldap_base,scope => DBMS_LDAP.SCOPE_SUBTREE,filter => '(&(objectClass=user)(cn=' ||userAccount || ')(mail=*))',attrs => l_attrs,attronly => 0,res => l_message); IF DBMS_LDAP.count_entries(ld => l_session, msg => l_message) > 0 THEN l_entry := DBMS_LDAP.first_entry(ld => l_session,msg => l_message); l_attr_name := DBMS_LDAP.first_attribute(ld => l_session, ldapentry => l_entry, ber_elem => l_ber_element); l_vals := DBMS_LDAP.get_values (ld => l_session, ldapentry => l_entry, attr => l_attr_name); ret := l_vals(0); END IF; l_retval := DBMS_LDAP.unbind_s(ld => l_session); return ret; end GetDataByUser;
- С#
static void Main(string[] args) { var listDict = ActiveDirectoryTraversal(); var d = listDict[0]; } private static List<Dictionary<string, object>> ActiveDirectoryTraversal() { List<Dictionary<string, object>> ret = null; var dep = new DirectoryEntry(); dep.AuthenticationType = AuthenticationTypes.FastBind; dep.Path = "LDAP://yourpath"; using(DirectorySearcher ds = new DirectorySearcher(dep)) { ds.Filter = "(&(objectClass=user))"; //ds.SizeLimit = 5; ds.PageSize = 100; using (SearchResultCollection results = ds.FindAll()) { var e = results.Count; if (results != null && results.Count > 0) { ret = SaveData(results); } } } dep.Close(); return ret; } private static List<Dictionary<string, object>> SaveData(SearchResultCollection results) { var ret = new List<Dictionary<string, object>>(); for (int i = 0; i < results.Count; i++) { var res = results[i]; var dict = new Dictionary<string, object>(); foreach (var e in res.Properties.PropertyNames) { if (!dict.ContainsKey(e.ToString())) dict.Add(e.ToString(), res.Properties[e.ToString()][0]); } ret.Add(dict); } return ret; }
Заключение:
Умение работать с Active Directory и обращаться к нему напрямую из БД Oracle существенно упростило работу программистам отдела, где я работаю. Изначально я, ради эксперимента, выкачал содержимое Active Directory в таблицу базы данных. Потом, к своему удивлению, я обнаружил ряд хранимых процедур, которые работали с этой таблицей. Выяснилось, что разработчики обращались к ней, поленившись разобраться в пакете DBMS_LDAP. Этот прецедент и подтолкнул меня к желанию рассказать и привести примеры того как можно работать с Active Directory.