Возникла необходимость работы с 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 Тогда фРезультат = Ложь; Описание = "Код возврата: " + Строка(КодВозврата); КонецЕсли; КонецЕсли; Возврат фРезультат; КонецФункции