TimVin

Возникла необходимость работы с 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;
    КонецЕсли;
    Возврат фРезультат;
КонецФункции

3) Создание пользователя

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