Всем доброго времени суток.
Возникла необходимость работы с AD из 1с в частности создавать пользователей, группы безопасности и организационные единицы.
Нижеприведенный код распологается во общем модуле.
Для работы используется LDAP провайдер ADSI
Пример содержимого передаваемых и возвращаемых переменных:
- Организационная единица: "OU=TestOU,DC=domain,DC=internal"
- Группа безопасности: "CN=TestGroup,OU=TestOU,DC=domain,DC=internal"
- Пользователь: "CN=TestUser,OU=TestOU,DC=domain,DC=internal"
SID пользователя и группы возвращается в виде COMSafeArray. Я его преобразовывавю в читаемый вид. Он мне нужен для установки прав на каталоги и файлы.
Все функции возвращают результат выполнения Ложь/Истина. В случае возникновения ошибки описание возвращается в переменную ОписаниеОшибки.
Надо не забывать, что пользователь, от имени которого запускается 1с (или пользователь сервера приложения если процедуры будут запускаться на сервере) должен обладать соответствующими правами для работы с AD
Привожу на суд общественности результаты:
1) Cоздание организационной единицы
Функция СоздатьОрганизационнуюЕдиницу(
ИмяОрганизационнойЕдиницы,
ОрганизационнаяЕдиницаВладелец,
Описание,
ГруппаДелегат = "",
ПолноеИмяОрганизационнойЕдиницы = "", //возращается путь до созданой OU
ОписаниеОшибки = ""
) Экспорт
фРезультат = Истина;
Попытка
ОрганизационнаяЕдиницаВладелецОбъект = ПолучитьCOMОбъект("LDAP://" + ОрганизационнаяЕдиницаВладелец);
ОрганизационнаяЕдиница = ОрганизационнаяЕдиницаВладелецОбъект.Create("OrganizationalUnit", "OU=" + ИмяОрганизационнойЕдиницы);
ОрганизационнаяЕдиница.description = Описание;
Если Не ПустаяСтрока(ГруппаДелегат) Тогда
ОрганизационнаяЕдиница.managedBy = ГруппаДелегат;
КонецЕсли;
ОрганизационнаяЕдиница.SetInfo();
Исключение
фРезультат = Ложь;
ОписаниеОшибки = ОписаниеОшибки();
КонецПопытки;
Если фРезультат Тогда
ПолноеИмяОрганизационнойЕдиницы = ОрганизационнаяЕдиница.distinguishedName;
КонецЕсли;
Возврат фРезультат;
КонецФункции
2) Создание группы безопасности
Функция СоздатьГруппуБезопасности(
ИмяГруппыБезопасности,
ОрганизационнаяЕдиницаВладелец,
Описание,
ПолноеИмяГруппыБезопасности = "",
SID = "",
ОписаниеОшибки = ""
) Экспорт
фРезультат = Истина;
//ADS_GROUP_TYPE_GLOBAL_GROUP = 2;
//ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP = 4;
//ADS_GROUP_TYPE_LOCAL_GROUP = 4;
//ADS_GROUP_TYPE_UNIVERSAL_GROUP = 8;
//ADS_GROUP_TYPE_SECURITY_ENABLED = -2147483648;
Попытка
ОрганизационнаяЕдиницаВладелецОбъект = ПолучитьCOMОбъект("LDAP://" + ОрганизационнаяЕдиницаВладелец);
ГруппаБезопасности = ОрганизационнаяЕдиницаВладелецОбъект.Create("Group", "CN=" + ИмяГруппыБезопасности);
ГруппаБезопасности.sAMAccountName = ИмяГруппыБезопасности;
ГруппаБезопасности.displayName = ИмяГруппыБезопасности;
ГруппаБезопасности.description = Описание;
ГруппаБезопасности.groupType = -2147483646;//ADS_GROUP_TYPE_GLOBAL_GROUP + ADS_GROUP_TYPE_SECURITY_ENABLED; //глобальная группа
ГруппаБезопасности.SetInfo();
Исключение
фРезультат = Ложь;
ОписаниеОшибки = ОписаниеОшибки();
КонецПопытки;
Если фРезультат Тогда
SID = ПреобразоватьSID(ГруппаБезопасности.objectSid);
ПолноеИмяГруппыБезопасности = ГруппаБезопасности.distinguishedName;
КонецЕсли;
Возврат фРезультат;
КонецФункции
Функция СоздатьПользователя(
Логин,
ПарольПользователя,
ОрганизационнаяЕдиница,
АдресЭлектроннойПочты,
МенятьПарольПриВходе = Истина,
Описание,
ПутьПользователяAD = "",
SID = "",
ОписаниеОшибки = ""
) Экспорт
фРезультат = Истина;
Попытка
ОрганизационнаяЕдиницаОбъект = ПолучитьCOMОбъект("LDAP://" + ОрганизационнаяЕдиница);
ПользовательAD = ОрганизационнаяЕдиницаОбъект.Create("user", "CN=" + Логин);
ПользовательAD.sAMAccountName = Логин;
ПользовательAD.description = Описание;
ПользовательAD.userPrincipalName = Логин + "@" + Константы.НаименованиеДомена.Получить();
Если Не ПустаяСтрока(АдресЭлектроннойПочты) Тогда
ПользовательAD.mail = АдресЭлектроннойПочты;
КонецЕсли;
Если МенятьПарольПриВходе Тогда
ПользовательAD.pwdLastSet = 0;
Иначе
ПользовательAD.pwdLastSet = -1;
КонецЕсли;
ПользовательAD.SetInfo();
ПользовательAD.SetPassword(ПарольПользователя);
Исключение
фРезультат = Ложь;
ОписаниеОшибки = ОписаниеОшибки();
КонецПопытки;
Если фРезультат Тогда
SID = ПреобразоватьSID(ПользовательAD.objectSid);
ПутьПользователяAD = ПользовательAD.distinguishedName;
КонецЕсли;
Если фРезультат Тогда
ПользовательAD.AccountDisabled = Ложь;
ПользовательAD.SetInfo();
КонецЕсли;
Возврат фРезультат;
КонецФункции
В константе НаименованиеДомена находится название домена типа "domain.internal".
4) Добавление пользователя в группу
Функция ДобавитьПользователяВГруппу(
ПолноеИмяГруппыБезопасности,
ПутьПользователяAD,
ОписаниеОшибки = ""
) Экспорт
фРезультат = Истина;
Попытка
ГруппаБезопасности = ПолучитьCOMОбъект("LDAP://" + ПолноеИмяГруппыБезопасности);
ГруппаБезопасности.Add("LDAP://" + ПутьПользователяAD);
ГруппаБезопасности.SetInfo();
Исключение
фРезультат = Ложь;
ОписаниеОшибки = ОписаниеОшибки();
КонецПопытки;
Возврат фРезультат;
КонецФункции
5) Удаление пользователя из группы
Функция УдалитьПользователяИзГруппы(
ПолноеИмяГруппыБезопасности,
ПутьПользователяAD,
ОписаниеОшибки = ""
) Экспорт
фРезультат = Истина;
Попытка
ГруппаБезопасности = ПолучитьCOMОбъект("LDAP://" + ПолноеИмяГруппыБезопасности);
ГруппаБезопасности.Remove("LDAP://" + ПутьПользователяAD);
ГруппаБезопасности.SetInfo();
Исключение
фРезультат = Ложь;
ОписаниеОшибки = ОписаниеОшибки();
КонецПопытки;
Возврат фРезультат;
КонецФункции
6) Переобразование SID из массива в читаемый вид типа "S-1-5-21-3784850290-2022084444-2521399107-4676"
Функция ПреобразоватьSID(objectSid)
SID = "S-";
МассивSID = Новый Массив;
Для Каждого ЭлементSID Из objectSid Цикл
МассивSID.Добавить(ЭлементSID);
КонецЦикла;
//SID_REVISION
SID = SID + Строка(МассивSID[0]) + "-";
КоличествоДашей = МассивSID[1];
SECURITY_NT_AUTHORITY = 0;
Для Инд = 0 По 5 Цикл
SECURITY_NT_AUTHORITY = SECURITY_NT_AUTHORITY + МассивSID[2 + Инд] * Pow(2, (5 - Инд) * 8);
КонецЦикла;
SID = SID + Строка(SECURITY_NT_AUTHORITY);
Для Инд = 0 По КоличествоДашей - 1 Цикл
SID = SID + "-";
Даш = 0;
Для ИндДаш = 0 По 3 Цикл
Даш = Даш + МассивSID[8 + 4 * Инд + ИндДаш] * Pow(2, (ИндДаш) * 8);
КонецЦикла;
SID = SID + Строка(Даш);
КонецЦикла;
Возврат SID;
КонецФункции
7) Ну и бонусом привожу процедуру установки прав на каталог. Права ставятся с наследованием на нижестоящие объекты. Для установки используется утилита операционки (в моём случае win 2012 в Asure). При вызове (в толстом клиенте) у 1С теряется фокус. К сожалению как установить права другим способом (например WMI) я не нашел. Планирую копать в сторону PowerShell.
Функция УстановитьПраваНаКаталог(
ПутьККаталогу,
SIDГруппы,
Описание = "") Экспорт
фРезультат = Истина;
КодВозврата = Неопределено;
Попытка
ЗапуститьПриложение("icacls " + ПутьККаталогу + " /grant *" + SIDГруппы + ":(CI)(OI)F", , Истина, КодВозврата)
Исключение
Описание = ОписаниеОшибки();
фРезультат = Ложь;
КонецПопытки;
Если фРезультат Тогда
Если КодВозврата <> 0 Тогда
фРезультат = Ложь;
Описание = "Код возврата: " + Строка(КодВозврата);
КонецЕсли;
КонецЕсли;
Возврат фРезультат;
КонецФункции
Список использованных ссылок:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa772203%28v=vs.85%29.aspx
http://www.script-coding.com/Python/LDAP.html
http://blogs.msdn.com/b/oldnewthing/archive/2004/03/15/89753.aspx
http://technet.microsoft.com/ru-ru/library/cc753525%28v=ws.10%29.aspx
Незаменимой вешью оказалась утилита Марка Руссиновича