Создает новый профиль безопасности кластера для его последующей настройки и регистрации. Все свойства созданного профиля имеют значения по умолчанию для соответствующих типов.
Синтаксис
СоздатьПрофильБезопасности()Полное описание, параметры и ограничения
АдминистрированиеКластер.СоздатьПрофильБезопасности (AdministrationCluster.CreateSecurityProfile)
АдминистрированиеКластер (AdministrationCluster)
СоздатьПрофильБезопасности (CreateSecurityProfile)
Доступен, начиная с версии 8.3.14.
Синтаксис:
СоздатьПрофильБезопасности()
Возвращаемое значение:
Тип: АдминистрированиеПрофильБезопасности.
Описание:
Создает новый профиль безопасности кластера для его последующей настройки и регистрации. Все свойства созданного профиля имеют значения по умолчанию для соответствующих типов.
Доступность:
Тонкий клиент, сервер, толстый клиент, интеграция.
Использование в версии:
Доступен, начиная с версии 8.3.14.
Методическая информация
Практические примеры
Приложение: цикл своего разрешения без запуска команды
Копируем свойства настоящего собственного образца в новый отдельный профиль, подтверждаем регистрацию и обновление описания, затем отменяем только созданное разрешение и профиль.
Где и как запускать
Полный модуль формы. При самостоятельном осознанном запуске меняет только собственный временный неназначенный профиль на отдельном стенде. В 1С здесь не выполнялся.
Подготовка
Нужен отдельный собственный серверный стенд 1С 8.5.1.1343 без рабочих баз. Администратор должен заранее установить сервер, запустить совместимый ras и создать кластер с точным именем УчебныйКластер85. Код ничего не устанавливает и не регистрирует.
Запускайте обработку в собственной пустой учебной конфигурации с именем метаданных УчебнаяКонфигурацияСинтаксиса. Серверное выполнение должно находиться на той же машине, что собственный ras: код разрешает только 127.0.0.1. Это адрес сервера выполнения, не обязательно компьютера тонкого клиента.
ПортRAS возьмите из фактического запуска своего ras, не из порта ragent или рабочего процесса. Например, 1545 подходит только если именно этот порт настроен на вашем стенде. Используйте законные учётные данные своего агента и своего кластера; пустые допустимы только для намеренно настроенного учебного стенда без соответствующих администраторов.
В первый раз оставьте ИдентификаторКластера пустым: появится JSON только с кластерами УчебныйКластер85. Скопируйте настоящий UUID из результата, вновь введите очищенные пароли и повторите команду. Кластер выбирается одновременно по UUID и точному учебному имени; чужой кластер не принимается.
Выполняйте каждый урок отдельно. JSON формируется в памяти и показывается только на своей форме; код не сохраняет файлы, не пишет настройки кластера, не прерывает сеансы и не запускает команды ОС. Он выполняет сетевое обращение к своему локальному ras только если вы сами запустите его на подготовленном стенде.
Здесь подключение к ras и запуск в 1С не выполнялись. Проверены тексты, сигнатуры и привязки к локальной справке 8.5.1.1343. Пройдите контрольные действия сами только на своём учебном стенде.
Штатными средствами заранее зарегистрируйте в своём УчебныйКластер85 только собственную УчебнаяБаза85 с этой учебной конфигурацией. Код не создаёт базу, СУБД, пользователя, профиль или разрешение.
В управляемой форме обработки создайте ПортRAS — Число без дробной части; ИмяАгента, ПарольАгента, ИдентификаторКластера, ИмяАдминистратораКластера, ПарольАдминистратораКластера, ИдентификаторУчебнойБазы, ИмяАдминистратораБазы, ПарольАдминистратораБазы, JSONРезультат — Строка. У JSONРезультат длина 0.
Выведите реквизиты на форму. Для всех трёх полей паролей включите Режим пароля, не сохраняйте их в истории и настройках; JSONРезультат — многострочное поле просмотра. Создайте команду ПолучитьУчебныйСнимок и вставьте весь приведённый модуль формы.
Первый запуск с пустым UUID кластера возвращает только каталог УчебныйКластер85. Второй с настоящим UUID кластера и пустым UUID базы — только каталог УчебнаяБаза85. Третий — с обоими подтверждёнными UUID и законными учётными данными пользователя-администратора своей базы.
Учётные данные агента, администратора кластера и пользователя информационной базы — три разные пары. Не подставляйте имя кластера вместо логина. После каждого результата или ошибки все три пароля очищаются, для повторного запроса введите их заново.
Для текущих уроков жизненного цикла заранее штатными средствами своего стенда создайте и назначьте УчебнаяБаза85 обычный профиль УчебныйПрофиль85. Возможность работы с профилями должна быть доступна на вашем лицензированном стенде; код не обходит её ограничения.
Списки разрешений, роли и модули проверяются только как настройки. COM, внешние приложения, файлы, криптография и внешние веб-сервисы в примерах не запускаются. Снимок в памяти не проверяет фактический доступ или отказ.
Внимание: самостоятельный запуск этих уроков меняет административные записи своего учебного сервера. Не вставляйте модуль в рабочую конфигурацию, не меняйте loopback и учебные защитные имена. Здесь ни один пример в 1С не запускался.
Добавьте на форму РазрешитьУчебныеИзменения — Булево, начальное значение Ложь, элемент-флажок. Включать его можно только после сознательного подтверждения опыта на отдельном собственном стенде без рабочих баз.
Не назначайте временный УчебныйЦикл85_<UUID> ни одной базе, обычному или безопасному режиму. Не запускайте другие администрирующие команды параллельно. Проверка назначений не является атомарной блокировкой конкурирующего администратора.
Перед опытом сохраните административные настройки своего стенда штатными средствами и подготовьте возможность ручной проверки. Программа запоминает точное случайное имя и метку своего запуска; постоянный УчебныйПрофиль85 используется только как источник разрешений.
При штатном завершении удаляется только созданный этим запуском временный профиль. При любой ошибке JSON содержит этап и данные для ручного расследования; автоматического удаления по одному предположению об исходе RPC нет.
Заранее подготовьте в исходном учебном профиле ровно один настоящий образец типа РазрешенноеВнешнееПриложение с ключом Имя = УчебноеПриложение85. Пройдите подготовку и проверки урока черновика этого же типа; здесь используются его настоящие пути, CLSID, шаблон или SHA-1/base64.
После штатного цикла дополнительно ожидаются Истина у РазрешениеЗарегистрировано, ОписаниеРазрешенияОбновлено и РазрешениеОтсутствуетПослеУдаления. Это ожидаемые результаты будущего собственного теста, не измерения здесь.
&НаКлиенте
Процедура ПолучитьУчебныйСнимок(Команда)
Попытка
JSONРезультат = УчебныйСнимокНаСервере(ПортRAS, ИмяАгента, ПарольАгента,
ИдентификаторКластера, ИмяАдминистратораКластера, ПарольАдминистратораКластера,
ИдентификаторУчебнойБазы, ИмяАдминистратораБазы, ПарольАдминистратораБазы, РазрешитьУчебныеИзменения);
Исключение
JSONРезультат = "Снимок не получен. Проверьте собственный стенд, порт, UUID кластера и базы, учебные имена и права администраторов. Подробную серверную ошибку исследуйте в отладчике без публикации учётных данных.";
КонецПопытки;
ПарольАгента = "";
ПарольАдминистратораКластера = "";
ПарольАдминистратораБазы = "";
КонецПроцедуры
&НаСервереБезКонтекста
Функция УчебныйСнимокНаСервере(ПортRAS, ИмяАгента, ПарольАгента,
ИдентификаторКластера, ИмяАдминистратораКластера, ПарольАдминистратораКластера,
ИдентификаторУчебнойБазы, ИмяАдминистратораБазы, ПарольАдминистратораБазы, РазрешитьУчебныеИзменения)
Если ТипЗнч(РазрешитьУчебныеИзменения) <> Тип("Булево") Тогда
ВызватьИсключение "Подтверждение должно быть булевым";
КонецЕсли;
Если Не РазрешитьУчебныеИзменения Тогда
ВызватьИсключение "Разрешите только сознательный опыт на отдельном собственном стенде";
КонецЕсли;
Если ТипЗнч(ПортRAS) <> Тип("Число") Тогда
ВызватьИсключение "Порт ras должен быть числом";
КонецЕсли;
Если ПортRAS <> Цел(ПортRAS) Или ПортRAS < 1 Или ПортRAS > 65535 Тогда
ВызватьИсключение "Недопустимый порт собственного ras";
КонецЕсли;
ТекстовыеПараметры = Новый Массив;
ТекстовыеПараметры.Добавить(ИмяАгента);
ТекстовыеПараметры.Добавить(ПарольАгента);
ТекстовыеПараметры.Добавить(ИдентификаторКластера);
ТекстовыеПараметры.Добавить(ИмяАдминистратораКластера);
ТекстовыеПараметры.Добавить(ПарольАдминистратораКластера);
ТекстовыеПараметры.Добавить(ИдентификаторУчебнойБазы);
ТекстовыеПараметры.Добавить(ИмяАдминистратораБазы);
ТекстовыеПараметры.Добавить(ПарольАдминистратораБазы);
Для Каждого ТекстовыйПараметр Из ТекстовыеПараметры Цикл
Если ТипЗнч(ТекстовыйПараметр) <> Тип("Строка") Тогда
ВызватьИсключение "Учётные данные и UUID должны быть строками";
КонецЕсли;
КонецЦикла;
Агент = Новый АдминистрированиеСервера("127.0.0.1", ПортRAS);
Агент.ВыполнитьАутентификацию(ПарольАгента, ИмяАгента);
Кластеры = Агент.ПолучитьКластеры();
Если ПустаяСтрока(СокрЛП(ИдентификаторКластера)) Тогда
Каталог = Новый Массив;
Для Каждого Найденный Из Кластеры Цикл
Если Найденный.Имя = "УчебныйКластер85" Тогда
СтрокаКаталога = Новый Структура;
СтрокаКаталога.Вставить("UUID", Строка(Найденный.ИдентификаторКластера));
СтрокаКаталога.Вставить("Имя", Найденный.Имя);
Каталог.Добавить(СтрокаКаталога);
КонецЕсли;
КонецЦикла;
Возврат СериализоватьСвойСнимок(Новый Структура("УчебныеКластеры", Каталог));
КонецЕсли;
Кластер = Неопределено;
Совпадений = 0;
Для Каждого Найденный Из Кластеры Цикл
Если НРег(Строка(Найденный.ИдентификаторКластера)) = НРег(СокрЛП(ИдентификаторКластера))
И Найденный.Имя = "УчебныйКластер85" Тогда
Кластер = Найденный;
Совпадений = Совпадений + 1;
КонецЕсли;
КонецЦикла;
Если Совпадений <> 1 Тогда
ВызватьИсключение "Нужен один собственный учебный кластер с подтверждённым UUID";
КонецЕсли;
Кластер.ВыполнитьАутентификацию(ИмяАдминистратораКластера, ПарольАдминистратораКластера);
Снимок = Новый Структура;
Снимок.Вставить("UUIDКластера", Строка(Кластер.ИдентификаторКластера));
Снимок.Вставить("ИмяКластера", Кластер.Имя);
Базы = Кластер.ПолучитьИнформационныеБазы();
Если ПустаяСтрока(СокрЛП(ИдентификаторУчебнойБазы)) Тогда
КаталогБаз = Новый Массив;
Для Каждого КандидатБазы Из Базы Цикл
Если ТипЗнч(КандидатБазы) <> Тип("АдминистрированиеИнформационнаяБаза") Тогда
ВызватьИсключение "Ожидалось описание информационной базы";
КонецЕсли;
Если КандидатБазы.Имя = "УчебнаяБаза85" Тогда
ЗаписьКаталога = Новый Структура;
ЗаписьКаталога.Вставить("UUID", Строка(КандидатБазы.ИдентификаторИнформационнойБазы));
ЗаписьКаталога.Вставить("Имя", КандидатБазы.Имя);
КаталогБаз.Добавить(ЗаписьКаталога);
КонецЕсли;
КонецЦикла;
Снимок.Вставить("УчебныеБазы", КаталогБаз);
Возврат СериализоватьСвойСнимок(Снимок);
КонецЕсли;
База = Неопределено;
СовпаденийБазы = 0;
Для Каждого КандидатБазы Из Базы Цикл
Если ТипЗнч(КандидатБазы) <> Тип("АдминистрированиеИнформационнаяБаза") Тогда
ВызватьИсключение "Ожидалось описание информационной базы";
КонецЕсли;
Если КандидатБазы.Имя = "УчебнаяБаза85"
И НРег(Строка(КандидатБазы.ИдентификаторИнформационнойБазы)) = НРег(СокрЛП(ИдентификаторУчебнойБазы)) Тогда
База = КандидатБазы;
СовпаденийБазы = СовпаденийБазы + 1;
КонецЕсли;
КонецЦикла;
Если СовпаденийБазы <> 1 Тогда
ВызватьИсключение "Нужна одна собственная УчебнаяБаза85 с подтверждённым UUID";
КонецЕсли;
База.ВыполнитьАутентификацию(ИмяАдминистратораБазы, ПарольАдминистратораБазы);
Снимок.Вставить("UUIDБазы", Строка(База.ИдентификаторИнформационнойБазы));
Снимок.Вставить("ИмяБазы", База.Имя);
Если База.ПрофильБезопасности <> "УчебныйПрофиль85" Тогда
ВызватьИсключение "Для урока нужен заранее назначенный своей базе УчебныйПрофиль85";
КонецЕсли;
Профиль = Неопределено;
СовпаденийПрофиля = 0;
Для Каждого КандидатПрофиля Из Кластер.ПолучитьПрофилиБезопасности() Цикл
Если ТипЗнч(КандидатПрофиля) <> Тип("АдминистрированиеПрофильБезопасности") Тогда
ВызватьИсключение "Ожидалось описание профиля безопасности";
КонецЕсли;
Если КандидатПрофиля.Имя = "УчебныйПрофиль85" Тогда
Профиль = КандидатПрофиля;
СовпаденийПрофиля = СовпаденийПрофиля + 1;
КонецЕсли;
КонецЦикла;
Если СовпаденийПрофиля <> 1 Тогда
ВызватьИсключение "Нужен один собственный заранее зарегистрированный учебный профиль";
КонецЕсли;
Снимок.Вставить("ИмяПрофиля", Профиль.Имя);
Снимок.Вставить("ОписаниеПрофиляЗаполнено", Не ПустаяСтрока(Профиль.Описание));
Образец = Неопределено;
СовпаденийОбразца = 0;
Для Каждого ЗаписьОбразца Из Профиль.ПолучитьРазрешенныеВнешниеПриложения() Цикл
Если ТипЗнч(ЗаписьОбразца) <> Тип("РазрешенноеВнешнееПриложение") Тогда
ВызватьИсключение "Неверный тип исходного учебного разрешения";
КонецЕсли;
Если ЗаписьОбразца.Имя = "УчебноеПриложение85" Тогда
Образец = ЗаписьОбразца;
СовпаденийОбразца = СовпаденийОбразца + 1;
КонецЕсли;
КонецЦикла;
Если СовпаденийОбразца <> 1 Тогда
ВызватьИсключение "Заранее подготовьте ровно одно собственное учебное разрешение";
КонецЕсли;
Если ПустаяСтрока(Образец.СтрокаКоманды) Тогда
ВызватьИсключение "Нужен настоящий заранее подготовленный шаблон своей программы";
КонецЕсли;
ИдентификаторЗапуска = Строка(Новый УникальныйИдентификатор);
ИмяЦели = "УчебныйЦикл85_" + ИдентификаторЗапуска;
Метка = "syntax-guide85:cycle:" + ИдентификаторЗапуска;
Снимок.Вставить("ВременныйПрофиль", ИмяЦели);
Снимок.Вставить("МеткаТекущегоЗапуска", Метка);
Этап = "До создания временного профиля";
Попытка
Если ЧислоПрофилейЦикла(Кластер, ИмяЦели) <> 0 Тогда
ВызватьИсключение "Случайное имя уже занято: не перезаписываем существующий профиль";
КонецЕсли;
ПроверитьНеназначенность(Кластер, ИмяЦели);
Временный = Кластер.СоздатьПрофильБезопасности();
Если ТипЗнч(Временный) <> Тип("АдминистрированиеПрофильБезопасности") Тогда
ВызватьИсключение "Фабрика должна вернуть описание профиля";
КонецЕсли;
Временный.Имя = ИмяЦели;
Временный.Описание = Метка + "|profile:1";
Этап = "Регистрация временного профиля";
Временный.Записать();
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
Снимок.Вставить("ПрофильЗарегистрирован", СвойПрофиль.Описание = Метка + "|profile:1");
Этап = "Подготовка собственного разрешения во временном профиле";
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
Разрешение = СвойПрофиль.СоздатьРазрешенноеВнешнееПриложение();
Если ТипЗнч(Разрешение) <> Тип("РазрешенноеВнешнееПриложение") Тогда
ВызватьИсключение "Фабрика вернула неверный тип разрешения";
КонецЕсли;
КлючРазрешения = "УчебноеРазрешение85_" + ИдентификаторЗапуска;
Разрешение.Имя = КлючРазрешения;
Разрешение.Описание = Метка + "|leaf:1";
Разрешение.СтрокаКоманды = Образец.СтрокаКоманды;
ПроверитьНеназначенность(Кластер, ИмяЦели);
Этап = "Регистрация только собственного разрешения";
Разрешение.Записать();
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
Сохраненное = НайтиСвоюЗаписьЦикла(СвойПрофиль, КлючРазрешения, Метка);
Снимок.Вставить("РазрешениеЗарегистрировано", Сохраненное.Описание = Метка + "|leaf:1");
Этап = "Обновление описания только собственного разрешения";
Сохраненное.Описание = Метка + "|leaf:2";
ПроверитьНеназначенность(Кластер, ИмяЦели);
Сохраненное.Записать();
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
Удаляемое = НайтиСвоюЗаписьЦикла(СвойПрофиль, КлючРазрешения, Метка);
Снимок.Вставить("ОписаниеРазрешенияОбновлено", Удаляемое.Описание = Метка + "|leaf:2");
Этап = "Удаление только собственного разрешения";
ПроверитьНеназначенность(Кластер, ИмяЦели);
Удаляемое.Удалить();
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
ОсталосьЗаписей = 0;
Для Каждого ЗаписьОстатка Из СвойПрофиль.ПолучитьРазрешенныеВнешниеПриложения() Цикл
Если ТипЗнч(ЗаписьОстатка) <> Тип("РазрешенноеВнешнееПриложение") Тогда
ВызватьИсключение "Неверный тип после удаления разрешения";
КонецЕсли;
Если ЗаписьОстатка.Имя = КлючРазрешения Тогда
ОсталосьЗаписей = ОсталосьЗаписей + 1;
КонецЕсли;
КонецЦикла;
Снимок.Вставить("РазрешениеОтсутствуетПослеУдаления", ОсталосьЗаписей = 0);
Если ОсталосьЗаписей <> 0 Тогда
ВызватьИсключение "Удаление не подтверждено: не продолжаем каскадную очистку";
КонецЕсли;
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
Если СвойПрофиль.ПолучитьРазрешенныеВиртуальныеКаталоги().Количество() <> 0
Или СвойПрофиль.ПолучитьРазрешенныеCOMКлассы().Количество() <> 0
Или СвойПрофиль.ПолучитьРазрешенныеИнтернетРесурсы().Количество() <> 0
Или СвойПрофиль.ПолучитьРазрешенныеВнешниеМодули().Количество() <> 0
Или СвойПрофиль.ПолучитьРазрешенныеВнешниеКомпоненты().Количество() <> 0
Или СвойПрофиль.ПолучитьРазрешенныеВнешниеПриложения().Количество() <> 0 Тогда
ВызватьИсключение "В профиле остались или появились разрешения: каскадное удаление запрещено";
КонецЕсли;
Этап = "Удаление только собственного неназначенного профиля";
СвойПрофиль.Удалить();
ОсталосьПрофилей = ЧислоПрофилейЦикла(Кластер, ИмяЦели);
Снимок.Вставить("ПрофильОтсутствуетПослеУдаления", ОсталосьПрофилей = 0);
Если ОсталосьПрофилей <> 0 Тогда
ВызватьИсключение "Отмена регистрации собственного профиля не подтверждена";
КонецЕсли;
Снимок.Вставить("ЦиклЗавершен", Истина);
Исключение
Снимок.Вставить("ЦиклЗавершен", Ложь);
Снимок.Вставить("ЭтапОстановки", Этап);
Снимок.Вставить("Восстановление", "Не повторяйте запись или удаление вслепую. Штатно проверьте точные временное имя, метку и оба назначения; исход ошибки RPC может быть неопределённым. Автоматическая очистка при ошибке не выполняется.");
КонецПопытки;
Возврат СериализоватьСвойСнимок(Снимок);
КонецФункции
&НаСервереБезКонтекста
Функция СериализоватьСвойСнимок(Снимок)
Писатель = Новый ЗаписьJSON;
Писатель.УстановитьСтроку();
ЗаписатьJSON(Писатель, Снимок);
Возврат Писатель.Закрыть();
КонецФункции
&НаСервереБезКонтекста
Функция ЧислоПрофилейЦикла(Кластер, ИмяЦели)
Количество = 0;
Для Каждого ЗаписьПрофиля Из Кластер.ПолучитьПрофилиБезопасности() Цикл
Если ТипЗнч(ЗаписьПрофиля) <> Тип("АдминистрированиеПрофильБезопасности") Тогда
ВызватьИсключение "Ожидалось описание профиля";
КонецЕсли;
Если ЗаписьПрофиля.Имя = ИмяЦели Тогда
Количество = Количество + 1;
КонецЕсли;
КонецЦикла;
Возврат Количество;
КонецФункции
&НаСервереБезКонтекста
Процедура ПроверитьНеназначенность(Кластер, ИмяЦели)
Для Каждого ПроверяемаяБаза Из Кластер.ПолучитьИнформационныеБазы() Цикл
Если ТипЗнч(ПроверяемаяБаза) <> Тип("АдминистрированиеИнформационнаяБаза") Тогда
ВызватьИсключение "Ожидалось описание базы при проверке назначений";
КонецЕсли;
Если ПроверяемаяБаза.ПрофильБезопасности = ИмяЦели
Или ПроверяемаяБаза.ПрофильБезопасностиБезопасногоРежима = ИмяЦели Тогда
ВызватьИсключение "Временный профиль назначен базе: изменение и удаление запрещены";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка)
Префикс = "УчебныйЦикл85_";
Если Лев(ИмяЦели, СтрДлина(Префикс)) <> Префикс
Или Метка <> "syntax-guide85:cycle:" + Сред(ИмяЦели, СтрДлина(Префикс) + 1) Тогда
ВызватьИсключение "Не совпадают собственное имя и метка текущего запуска";
КонецЕсли;
Найденный = Неопределено;
Совпадений = 0;
Для Каждого ЗаписьПрофиля Из Кластер.ПолучитьПрофилиБезопасности() Цикл
Если ТипЗнч(ЗаписьПрофиля) <> Тип("АдминистрированиеПрофильБезопасности") Тогда
ВызватьИсключение "Ожидалось описание профиля";
КонецЕсли;
Если ЗаписьПрофиля.Имя = ИмяЦели Тогда
Найденный = ЗаписьПрофиля;
Совпадений = Совпадений + 1;
КонецЕсли;
КонецЦикла;
Если Совпадений <> 1 Тогда
ВызватьИсключение "Нужен один созданный текущим запуском профиль";
КонецЕсли;
Если Найденный.Описание <> Метка + "|profile:1"
И Найденный.Описание <> Метка + "|profile:2" Тогда
ВызватьИсключение "Метка владельца изменена: удаление или перезапись запрещены";
КонецЕсли;
ПроверитьНеназначенность(Кластер, ИмяЦели);
Возврат Найденный;
КонецФункции
&НаСервереБезКонтекста
Функция НайтиСвоюЗаписьЦикла(СвойПрофиль, КлючРазрешения, Метка)
Найденная = Неопределено;
Совпадений = 0;
Для Каждого ЗаписьЦикла Из СвойПрофиль.ПолучитьРазрешенныеВнешниеПриложения() Цикл
Если ТипЗнч(ЗаписьЦикла) <> Тип("РазрешенноеВнешнееПриложение") Тогда
ВызватьИсключение "Неверный тип собственного разрешения";
КонецЕсли;
Если ЗаписьЦикла.Имя = КлючРазрешения Тогда
Найденная = ЗаписьЦикла;
Совпадений = Совпадений + 1;
КонецЕсли;
КонецЦикла;
Если Совпадений <> 1 Тогда
ВызватьИсключение "Нужна одна запись с ключом текущего запуска";
КонецЕсли;
Если Найденная.Описание <> Метка + "|leaf:1"
И Найденная.Описание <> Метка + "|leaf:2" Тогда
ВызватьИсключение "Метка разрешения изменена: перезапись и удаление запрещены";
КонецЕсли;
Возврат Найденная;
КонецФункции
Разбор по шагам
До обращения к ras сервер проверяет тип и значение отдельного подтверждения изменений. Далее работают прежние проверки учебной конфигурации, loopback, порта, имён и UUID.
Случайный идентификатор текущего запуска создаёт новое имя УчебныйЦикл85_<UUID> и связанную метку владельца. Существующий профиль с таким именем не обновляется.
СоздатьПрофильБезопасности даёт новый объект с типовыми значениями по умолчанию. Имя и метка задаются только новому объекту; Записать регистрирует именно его.
После каждого важного изменения выполняется свежее административное чтение. Проверяются единственный точный ключ, метка собственного запуска и отсутствие назначения любой базе.
Обычное и безопасное назначение проверяются раздельно. Это запрет изменения используемого профиля, а не команда отключить назначение у базы.
При штатном завершении удаляется только собственный неназначенный временный профиль; перед этим все шесть списков разрешений должны быть пустыми. Удалить каскадно отменяет также оставшиеся разрешения, поэтому при неожиданном непустом списке действие запрещается.
При ошибке выполнение останавливается с этапом и точным временным ключом. Неопределённый результат RPC не исправляется повторной записью или слепым удалением.
Исходный образец ищется в УчебныйПрофиль85 по точному учебному ключу и типу до создания временного профиля. Его данные не заменяются выдуманными значениями.
Разрешение создаётся фабрикой на СвойПрофиль, то есть на новом подтверждённом временном профиле, а не на исходном. У него отдельный ключ и метка leaf:1.
Записать регистрирует новое разрешение; свежее чтение того же временного профиля проверяет его ключ и метку. Затем меняется только описание на leaf:2 и подтверждается повторное Записать.
Перед Удалить свежее чтение подтверждает отдельную запись текущего запуска. После удаления проверяется отсутствие её ключа; иначе каскадное удаление профиля не продолжается.
Все реальные ресурсные значения берутся из подготовленного собственного образца. COM ограничен localhost, виртуальный каталог — чтением без записи; программа, компонент, файл и веб-ресурс не запускаются.
Как проверить результат
Без включённого булева подтверждения изменений не должно быть подключения и регистрации. Все три пароля формы очищаются после успеха или ошибки.
При штатном ходе ПрофильЗарегистрирован, ПрофильОтсутствуетПослеУдаления и ЦиклЗавершен — Истина. Временное имя и метка содержат один и тот же UUID текущего запуска.
Сверьте исходную базу и УчебныйПрофиль85 штатными средствами: их назначения и существующие разрешения не изменены.
Если ЦиклЗавершен — Ложь, прочитайте ЭтапОстановки. По точному имени и метке вручную проверьте регистрацию, оба назначения и записи профиля; не повторяйте весь урок, ожидая автоматической очистки предыдущего запуска.
Проверки не означают, что пример был выполнен здесь. В 1С он не запускался; создаются только тексты и справочник.
Ожидаемый результат
Полный контролируемый учебный цикл с регистрацией, проверкой, отменой собственной регистрации и явной остановкой при неопределённом исходе.
На что обратить внимание
Самостоятельный запуск действительно меняет административные записи учебного сервера. Это не предыдущий урок черновика и не рекомендация экспериментировать на production.
Записать — не операция базы 1С в вашей транзакции; прежний снимок не доказывает атомарность с последующим RPC. На время опыта исключите конкурентное администрирование.
Имя и метка — контроль происхождения внутри собственного опыта, не механизм защиты от злоумышленного администратора. Любое несовпадение останавливает действия.
Нельзя назначать временный профиль базе ради проверки. Изменения действующего профиля по справке применяются после отсоединения последнего соединения; этот урок не заставляет рабочие сеансы переподключаться.
При сбое записи результат может быть неопределённым: объект мог зарегистрироваться, даже если клиент получил ошибку. Поэтому автоматической очистки в Исключение нет.
Удаление профиля удаляет все связанные с ним разрешения. Перед ним повторно проверяются точное имя, метка и отсутствие назначений; исходный профиль никогда не удаляется.
Статические проверки сверяют код, типы, сигнатуры и ограничители. Они не подтверждают регистрацию, доступ к ресурсу или отсутствие остатка на реальном сервере.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.
Внешняя компонента: цикл своего разрешения без загрузки компоненты
Копируем свойства настоящего собственного образца в новый отдельный профиль, подтверждаем регистрацию и обновление описания, затем отменяем только созданное разрешение и профиль.
Где и как запускать
Полный модуль формы. При самостоятельном осознанном запуске меняет только собственный временный неназначенный профиль на отдельном стенде. В 1С здесь не выполнялся.
Подготовка
Нужен отдельный собственный серверный стенд 1С 8.5.1.1343 без рабочих баз. Администратор должен заранее установить сервер, запустить совместимый ras и создать кластер с точным именем УчебныйКластер85. Код ничего не устанавливает и не регистрирует.
Запускайте обработку в собственной пустой учебной конфигурации с именем метаданных УчебнаяКонфигурацияСинтаксиса. Серверное выполнение должно находиться на той же машине, что собственный ras: код разрешает только 127.0.0.1. Это адрес сервера выполнения, не обязательно компьютера тонкого клиента.
ПортRAS возьмите из фактического запуска своего ras, не из порта ragent или рабочего процесса. Например, 1545 подходит только если именно этот порт настроен на вашем стенде. Используйте законные учётные данные своего агента и своего кластера; пустые допустимы только для намеренно настроенного учебного стенда без соответствующих администраторов.
В первый раз оставьте ИдентификаторКластера пустым: появится JSON только с кластерами УчебныйКластер85. Скопируйте настоящий UUID из результата, вновь введите очищенные пароли и повторите команду. Кластер выбирается одновременно по UUID и точному учебному имени; чужой кластер не принимается.
Выполняйте каждый урок отдельно. JSON формируется в памяти и показывается только на своей форме; код не сохраняет файлы, не пишет настройки кластера, не прерывает сеансы и не запускает команды ОС. Он выполняет сетевое обращение к своему локальному ras только если вы сами запустите его на подготовленном стенде.
Здесь подключение к ras и запуск в 1С не выполнялись. Проверены тексты, сигнатуры и привязки к локальной справке 8.5.1.1343. Пройдите контрольные действия сами только на своём учебном стенде.
Штатными средствами заранее зарегистрируйте в своём УчебныйКластер85 только собственную УчебнаяБаза85 с этой учебной конфигурацией. Код не создаёт базу, СУБД, пользователя, профиль или разрешение.
В управляемой форме обработки создайте ПортRAS — Число без дробной части; ИмяАгента, ПарольАгента, ИдентификаторКластера, ИмяАдминистратораКластера, ПарольАдминистратораКластера, ИдентификаторУчебнойБазы, ИмяАдминистратораБазы, ПарольАдминистратораБазы, JSONРезультат — Строка. У JSONРезультат длина 0.
Выведите реквизиты на форму. Для всех трёх полей паролей включите Режим пароля, не сохраняйте их в истории и настройках; JSONРезультат — многострочное поле просмотра. Создайте команду ПолучитьУчебныйСнимок и вставьте весь приведённый модуль формы.
Первый запуск с пустым UUID кластера возвращает только каталог УчебныйКластер85. Второй с настоящим UUID кластера и пустым UUID базы — только каталог УчебнаяБаза85. Третий — с обоими подтверждёнными UUID и законными учётными данными пользователя-администратора своей базы.
Учётные данные агента, администратора кластера и пользователя информационной базы — три разные пары. Не подставляйте имя кластера вместо логина. После каждого результата или ошибки все три пароля очищаются, для повторного запроса введите их заново.
Для текущих уроков жизненного цикла заранее штатными средствами своего стенда создайте и назначьте УчебнаяБаза85 обычный профиль УчебныйПрофиль85. Возможность работы с профилями должна быть доступна на вашем лицензированном стенде; код не обходит её ограничения.
Списки разрешений, роли и модули проверяются только как настройки. COM, внешние приложения, файлы, криптография и внешние веб-сервисы в примерах не запускаются. Снимок в памяти не проверяет фактический доступ или отказ.
Внимание: самостоятельный запуск этих уроков меняет административные записи своего учебного сервера. Не вставляйте модуль в рабочую конфигурацию, не меняйте loopback и учебные защитные имена. Здесь ни один пример в 1С не запускался.
Добавьте на форму РазрешитьУчебныеИзменения — Булево, начальное значение Ложь, элемент-флажок. Включать его можно только после сознательного подтверждения опыта на отдельном собственном стенде без рабочих баз.
Не назначайте временный УчебныйЦикл85_<UUID> ни одной базе, обычному или безопасному режиму. Не запускайте другие администрирующие команды параллельно. Проверка назначений не является атомарной блокировкой конкурирующего администратора.
Перед опытом сохраните административные настройки своего стенда штатными средствами и подготовьте возможность ручной проверки. Программа запоминает точное случайное имя и метку своего запуска; постоянный УчебныйПрофиль85 используется только как источник разрешений.
При штатном завершении удаляется только созданный этим запуском временный профиль. При любой ошибке JSON содержит этап и данные для ручного расследования; автоматического удаления по одному предположению об исходе RPC нет.
Заранее подготовьте в исходном учебном профиле ровно один настоящий образец типа РазрешеннаяВнешняяКомпонента с ключом Имя = УчебнаяКомпонента85. Пройдите подготовку и проверки урока черновика этого же типа; здесь используются его настоящие пути, CLSID, шаблон или SHA-1/base64.
После штатного цикла дополнительно ожидаются Истина у РазрешениеЗарегистрировано, ОписаниеРазрешенияОбновлено и РазрешениеОтсутствуетПослеУдаления. Это ожидаемые результаты будущего собственного теста, не измерения здесь.
&НаКлиенте
Процедура ПолучитьУчебныйСнимок(Команда)
Попытка
JSONРезультат = УчебныйСнимокНаСервере(ПортRAS, ИмяАгента, ПарольАгента,
ИдентификаторКластера, ИмяАдминистратораКластера, ПарольАдминистратораКластера,
ИдентификаторУчебнойБазы, ИмяАдминистратораБазы, ПарольАдминистратораБазы, РазрешитьУчебныеИзменения);
Исключение
JSONРезультат = "Снимок не получен. Проверьте собственный стенд, порт, UUID кластера и базы, учебные имена и права администраторов. Подробную серверную ошибку исследуйте в отладчике без публикации учётных данных.";
КонецПопытки;
ПарольАгента = "";
ПарольАдминистратораКластера = "";
ПарольАдминистратораБазы = "";
КонецПроцедуры
&НаСервереБезКонтекста
Функция УчебныйСнимокНаСервере(ПортRAS, ИмяАгента, ПарольАгента,
ИдентификаторКластера, ИмяАдминистратораКластера, ПарольАдминистратораКластера,
ИдентификаторУчебнойБазы, ИмяАдминистратораБазы, ПарольАдминистратораБазы, РазрешитьУчебныеИзменения)
Если ТипЗнч(РазрешитьУчебныеИзменения) <> Тип("Булево") Тогда
ВызватьИсключение "Подтверждение должно быть булевым";
КонецЕсли;
Если Не РазрешитьУчебныеИзменения Тогда
ВызватьИсключение "Разрешите только сознательный опыт на отдельном собственном стенде";
КонецЕсли;
Если ТипЗнч(ПортRAS) <> Тип("Число") Тогда
ВызватьИсключение "Порт ras должен быть числом";
КонецЕсли;
Если ПортRAS <> Цел(ПортRAS) Или ПортRAS < 1 Или ПортRAS > 65535 Тогда
ВызватьИсключение "Недопустимый порт собственного ras";
КонецЕсли;
ТекстовыеПараметры = Новый Массив;
ТекстовыеПараметры.Добавить(ИмяАгента);
ТекстовыеПараметры.Добавить(ПарольАгента);
ТекстовыеПараметры.Добавить(ИдентификаторКластера);
ТекстовыеПараметры.Добавить(ИмяАдминистратораКластера);
ТекстовыеПараметры.Добавить(ПарольАдминистратораКластера);
ТекстовыеПараметры.Добавить(ИдентификаторУчебнойБазы);
ТекстовыеПараметры.Добавить(ИмяАдминистратораБазы);
ТекстовыеПараметры.Добавить(ПарольАдминистратораБазы);
Для Каждого ТекстовыйПараметр Из ТекстовыеПараметры Цикл
Если ТипЗнч(ТекстовыйПараметр) <> Тип("Строка") Тогда
ВызватьИсключение "Учётные данные и UUID должны быть строками";
КонецЕсли;
КонецЦикла;
Агент = Новый АдминистрированиеСервера("127.0.0.1", ПортRAS);
Агент.ВыполнитьАутентификацию(ПарольАгента, ИмяАгента);
Кластеры = Агент.ПолучитьКластеры();
Если ПустаяСтрока(СокрЛП(ИдентификаторКластера)) Тогда
Каталог = Новый Массив;
Для Каждого Найденный Из Кластеры Цикл
Если Найденный.Имя = "УчебныйКластер85" Тогда
СтрокаКаталога = Новый Структура;
СтрокаКаталога.Вставить("UUID", Строка(Найденный.ИдентификаторКластера));
СтрокаКаталога.Вставить("Имя", Найденный.Имя);
Каталог.Добавить(СтрокаКаталога);
КонецЕсли;
КонецЦикла;
Возврат СериализоватьСвойСнимок(Новый Структура("УчебныеКластеры", Каталог));
КонецЕсли;
Кластер = Неопределено;
Совпадений = 0;
Для Каждого Найденный Из Кластеры Цикл
Если НРег(Строка(Найденный.ИдентификаторКластера)) = НРег(СокрЛП(ИдентификаторКластера))
И Найденный.Имя = "УчебныйКластер85" Тогда
Кластер = Найденный;
Совпадений = Совпадений + 1;
КонецЕсли;
КонецЦикла;
Если Совпадений <> 1 Тогда
ВызватьИсключение "Нужен один собственный учебный кластер с подтверждённым UUID";
КонецЕсли;
Кластер.ВыполнитьАутентификацию(ИмяАдминистратораКластера, ПарольАдминистратораКластера);
Снимок = Новый Структура;
Снимок.Вставить("UUIDКластера", Строка(Кластер.ИдентификаторКластера));
Снимок.Вставить("ИмяКластера", Кластер.Имя);
Базы = Кластер.ПолучитьИнформационныеБазы();
Если ПустаяСтрока(СокрЛП(ИдентификаторУчебнойБазы)) Тогда
КаталогБаз = Новый Массив;
Для Каждого КандидатБазы Из Базы Цикл
Если ТипЗнч(КандидатБазы) <> Тип("АдминистрированиеИнформационнаяБаза") Тогда
ВызватьИсключение "Ожидалось описание информационной базы";
КонецЕсли;
Если КандидатБазы.Имя = "УчебнаяБаза85" Тогда
ЗаписьКаталога = Новый Структура;
ЗаписьКаталога.Вставить("UUID", Строка(КандидатБазы.ИдентификаторИнформационнойБазы));
ЗаписьКаталога.Вставить("Имя", КандидатБазы.Имя);
КаталогБаз.Добавить(ЗаписьКаталога);
КонецЕсли;
КонецЦикла;
Снимок.Вставить("УчебныеБазы", КаталогБаз);
Возврат СериализоватьСвойСнимок(Снимок);
КонецЕсли;
База = Неопределено;
СовпаденийБазы = 0;
Для Каждого КандидатБазы Из Базы Цикл
Если ТипЗнч(КандидатБазы) <> Тип("АдминистрированиеИнформационнаяБаза") Тогда
ВызватьИсключение "Ожидалось описание информационной базы";
КонецЕсли;
Если КандидатБазы.Имя = "УчебнаяБаза85"
И НРег(Строка(КандидатБазы.ИдентификаторИнформационнойБазы)) = НРег(СокрЛП(ИдентификаторУчебнойБазы)) Тогда
База = КандидатБазы;
СовпаденийБазы = СовпаденийБазы + 1;
КонецЕсли;
КонецЦикла;
Если СовпаденийБазы <> 1 Тогда
ВызватьИсключение "Нужна одна собственная УчебнаяБаза85 с подтверждённым UUID";
КонецЕсли;
База.ВыполнитьАутентификацию(ИмяАдминистратораБазы, ПарольАдминистратораБазы);
Снимок.Вставить("UUIDБазы", Строка(База.ИдентификаторИнформационнойБазы));
Снимок.Вставить("ИмяБазы", База.Имя);
Если База.ПрофильБезопасности <> "УчебныйПрофиль85" Тогда
ВызватьИсключение "Для урока нужен заранее назначенный своей базе УчебныйПрофиль85";
КонецЕсли;
Профиль = Неопределено;
СовпаденийПрофиля = 0;
Для Каждого КандидатПрофиля Из Кластер.ПолучитьПрофилиБезопасности() Цикл
Если ТипЗнч(КандидатПрофиля) <> Тип("АдминистрированиеПрофильБезопасности") Тогда
ВызватьИсключение "Ожидалось описание профиля безопасности";
КонецЕсли;
Если КандидатПрофиля.Имя = "УчебныйПрофиль85" Тогда
Профиль = КандидатПрофиля;
СовпаденийПрофиля = СовпаденийПрофиля + 1;
КонецЕсли;
КонецЦикла;
Если СовпаденийПрофиля <> 1 Тогда
ВызватьИсключение "Нужен один собственный заранее зарегистрированный учебный профиль";
КонецЕсли;
Снимок.Вставить("ИмяПрофиля", Профиль.Имя);
Снимок.Вставить("ОписаниеПрофиляЗаполнено", Не ПустаяСтрока(Профиль.Описание));
Образец = Неопределено;
СовпаденийОбразца = 0;
Для Каждого ЗаписьОбразца Из Профиль.ПолучитьРазрешенныеВнешниеКомпоненты() Цикл
Если ТипЗнч(ЗаписьОбразца) <> Тип("РазрешеннаяВнешняяКомпонента") Тогда
ВызватьИсключение "Неверный тип исходного учебного разрешения";
КонецЕсли;
Если ЗаписьОбразца.Имя = "УчебнаяКомпонента85" Тогда
Образец = ЗаписьОбразца;
СовпаденийОбразца = СовпаденийОбразца + 1;
КонецЕсли;
КонецЦикла;
Если СовпаденийОбразца <> 1 Тогда
ВызватьИсключение "Заранее подготовьте ровно одно собственное учебное разрешение";
КонецЕсли;
Если СтрДлина(Образец.ХешСумма) <> 28 Тогда
ВызватьИсключение "Нужна настоящая каноническая SHA-1/base64 контрольная сумма своего файла";
КонецЕсли;
БайтыХеша = Base64Значение(Образец.ХешСумма);
Если ТипЗнч(БайтыХеша) <> Тип("ДвоичныеДанные") Или БайтыХеша.Размер() <> 20 Тогда
ВызватьИсключение "Контрольная сумма должна декодироваться в 20 байт SHA-1";
КонецЕсли;
ИдентификаторЗапуска = Строка(Новый УникальныйИдентификатор);
ИмяЦели = "УчебныйЦикл85_" + ИдентификаторЗапуска;
Метка = "syntax-guide85:cycle:" + ИдентификаторЗапуска;
Снимок.Вставить("ВременныйПрофиль", ИмяЦели);
Снимок.Вставить("МеткаТекущегоЗапуска", Метка);
Этап = "До создания временного профиля";
Попытка
Если ЧислоПрофилейЦикла(Кластер, ИмяЦели) <> 0 Тогда
ВызватьИсключение "Случайное имя уже занято: не перезаписываем существующий профиль";
КонецЕсли;
ПроверитьНеназначенность(Кластер, ИмяЦели);
Временный = Кластер.СоздатьПрофильБезопасности();
Если ТипЗнч(Временный) <> Тип("АдминистрированиеПрофильБезопасности") Тогда
ВызватьИсключение "Фабрика должна вернуть описание профиля";
КонецЕсли;
Временный.Имя = ИмяЦели;
Временный.Описание = Метка + "|profile:1";
Этап = "Регистрация временного профиля";
Временный.Записать();
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
Снимок.Вставить("ПрофильЗарегистрирован", СвойПрофиль.Описание = Метка + "|profile:1");
Этап = "Подготовка собственного разрешения во временном профиле";
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
Разрешение = СвойПрофиль.СоздатьРазрешеннуюВнешнююКомпоненту();
Если ТипЗнч(Разрешение) <> Тип("РазрешеннаяВнешняяКомпонента") Тогда
ВызватьИсключение "Фабрика вернула неверный тип разрешения";
КонецЕсли;
КлючРазрешения = "УчебноеРазрешение85_" + ИдентификаторЗапуска;
Разрешение.Имя = КлючРазрешения;
Разрешение.Описание = Метка + "|leaf:1";
Разрешение.ХешСумма = Образец.ХешСумма;
ПроверитьНеназначенность(Кластер, ИмяЦели);
Этап = "Регистрация только собственного разрешения";
Разрешение.Записать();
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
Сохраненное = НайтиСвоюЗаписьЦикла(СвойПрофиль, КлючРазрешения, Метка);
Снимок.Вставить("РазрешениеЗарегистрировано", Сохраненное.Описание = Метка + "|leaf:1");
Этап = "Обновление описания только собственного разрешения";
Сохраненное.Описание = Метка + "|leaf:2";
ПроверитьНеназначенность(Кластер, ИмяЦели);
Сохраненное.Записать();
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
Удаляемое = НайтиСвоюЗаписьЦикла(СвойПрофиль, КлючРазрешения, Метка);
Снимок.Вставить("ОписаниеРазрешенияОбновлено", Удаляемое.Описание = Метка + "|leaf:2");
Этап = "Удаление только собственного разрешения";
ПроверитьНеназначенность(Кластер, ИмяЦели);
Удаляемое.Удалить();
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
ОсталосьЗаписей = 0;
Для Каждого ЗаписьОстатка Из СвойПрофиль.ПолучитьРазрешенныеВнешниеКомпоненты() Цикл
Если ТипЗнч(ЗаписьОстатка) <> Тип("РазрешеннаяВнешняяКомпонента") Тогда
ВызватьИсключение "Неверный тип после удаления разрешения";
КонецЕсли;
Если ЗаписьОстатка.Имя = КлючРазрешения Тогда
ОсталосьЗаписей = ОсталосьЗаписей + 1;
КонецЕсли;
КонецЦикла;
Снимок.Вставить("РазрешениеОтсутствуетПослеУдаления", ОсталосьЗаписей = 0);
Если ОсталосьЗаписей <> 0 Тогда
ВызватьИсключение "Удаление не подтверждено: не продолжаем каскадную очистку";
КонецЕсли;
СвойПрофиль = ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка);
Если СвойПрофиль.ПолучитьРазрешенныеВиртуальныеКаталоги().Количество() <> 0
Или СвойПрофиль.ПолучитьРазрешенныеCOMКлассы().Количество() <> 0
Или СвойПрофиль.ПолучитьРазрешенныеИнтернетРесурсы().Количество() <> 0
Или СвойПрофиль.ПолучитьРазрешенныеВнешниеМодули().Количество() <> 0
Или СвойПрофиль.ПолучитьРазрешенныеВнешниеКомпоненты().Количество() <> 0
Или СвойПрофиль.ПолучитьРазрешенныеВнешниеПриложения().Количество() <> 0 Тогда
ВызватьИсключение "В профиле остались или появились разрешения: каскадное удаление запрещено";
КонецЕсли;
Этап = "Удаление только собственного неназначенного профиля";
СвойПрофиль.Удалить();
ОсталосьПрофилей = ЧислоПрофилейЦикла(Кластер, ИмяЦели);
Снимок.Вставить("ПрофильОтсутствуетПослеУдаления", ОсталосьПрофилей = 0);
Если ОсталосьПрофилей <> 0 Тогда
ВызватьИсключение "Отмена регистрации собственного профиля не подтверждена";
КонецЕсли;
Снимок.Вставить("ЦиклЗавершен", Истина);
Исключение
Снимок.Вставить("ЦиклЗавершен", Ложь);
Снимок.Вставить("ЭтапОстановки", Этап);
Снимок.Вставить("Восстановление", "Не повторяйте запись или удаление вслепую. Штатно проверьте точные временное имя, метку и оба назначения; исход ошибки RPC может быть неопределённым. Автоматическая очистка при ошибке не выполняется.");
КонецПопытки;
Возврат СериализоватьСвойСнимок(Снимок);
КонецФункции
&НаСервереБезКонтекста
Функция СериализоватьСвойСнимок(Снимок)
Писатель = Новый ЗаписьJSON;
Писатель.УстановитьСтроку();
ЗаписатьJSON(Писатель, Снимок);
Возврат Писатель.Закрыть();
КонецФункции
&НаСервереБезКонтекста
Функция ЧислоПрофилейЦикла(Кластер, ИмяЦели)
Количество = 0;
Для Каждого ЗаписьПрофиля Из Кластер.ПолучитьПрофилиБезопасности() Цикл
Если ТипЗнч(ЗаписьПрофиля) <> Тип("АдминистрированиеПрофильБезопасности") Тогда
ВызватьИсключение "Ожидалось описание профиля";
КонецЕсли;
Если ЗаписьПрофиля.Имя = ИмяЦели Тогда
Количество = Количество + 1;
КонецЕсли;
КонецЦикла;
Возврат Количество;
КонецФункции
&НаСервереБезКонтекста
Процедура ПроверитьНеназначенность(Кластер, ИмяЦели)
Для Каждого ПроверяемаяБаза Из Кластер.ПолучитьИнформационныеБазы() Цикл
Если ТипЗнч(ПроверяемаяБаза) <> Тип("АдминистрированиеИнформационнаяБаза") Тогда
ВызватьИсключение "Ожидалось описание базы при проверке назначений";
КонецЕсли;
Если ПроверяемаяБаза.ПрофильБезопасности = ИмяЦели
Или ПроверяемаяБаза.ПрофильБезопасностиБезопасногоРежима = ИмяЦели Тогда
ВызватьИсключение "Временный профиль назначен базе: изменение и удаление запрещены";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПодтвердитьСвойПрофильЦикла(Кластер, ИмяЦели, Метка)
Префикс = "УчебныйЦикл85_";
Если Лев(ИмяЦели, СтрДлина(Префикс)) <> Префикс
Или Метка <> "syntax-guide85:cycle:" + Сред(ИмяЦели, СтрДлина(Префикс) + 1) Тогда
ВызватьИсключение "Не совпадают собственное имя и метка текущего запуска";
КонецЕсли;
Найденный = Неопределено;
Совпадений = 0;
Для Каждого ЗаписьПрофиля Из Кластер.ПолучитьПрофилиБезопасности() Цикл
Если ТипЗнч(ЗаписьПрофиля) <> Тип("АдминистрированиеПрофильБезопасности") Тогда
ВызватьИсключение "Ожидалось описание профиля";
КонецЕсли;
Если ЗаписьПрофиля.Имя = ИмяЦели Тогда
Найденный = ЗаписьПрофиля;
Совпадений = Совпадений + 1;
КонецЕсли;
КонецЦикла;
Если Совпадений <> 1 Тогда
ВызватьИсключение "Нужен один созданный текущим запуском профиль";
КонецЕсли;
Если Найденный.Описание <> Метка + "|profile:1"
И Найденный.Описание <> Метка + "|profile:2" Тогда
ВызватьИсключение "Метка владельца изменена: удаление или перезапись запрещены";
КонецЕсли;
ПроверитьНеназначенность(Кластер, ИмяЦели);
Возврат Найденный;
КонецФункции
&НаСервереБезКонтекста
Функция НайтиСвоюЗаписьЦикла(СвойПрофиль, КлючРазрешения, Метка)
Найденная = Неопределено;
Совпадений = 0;
Для Каждого ЗаписьЦикла Из СвойПрофиль.ПолучитьРазрешенныеВнешниеКомпоненты() Цикл
Если ТипЗнч(ЗаписьЦикла) <> Тип("РазрешеннаяВнешняяКомпонента") Тогда
ВызватьИсключение "Неверный тип собственного разрешения";
КонецЕсли;
Если ЗаписьЦикла.Имя = КлючРазрешения Тогда
Найденная = ЗаписьЦикла;
Совпадений = Совпадений + 1;
КонецЕсли;
КонецЦикла;
Если Совпадений <> 1 Тогда
ВызватьИсключение "Нужна одна запись с ключом текущего запуска";
КонецЕсли;
Если Найденная.Описание <> Метка + "|leaf:1"
И Найденная.Описание <> Метка + "|leaf:2" Тогда
ВызватьИсключение "Метка разрешения изменена: перезапись и удаление запрещены";
КонецЕсли;
Возврат Найденная;
КонецФункции
Разбор по шагам
До обращения к ras сервер проверяет тип и значение отдельного подтверждения изменений. Далее работают прежние проверки учебной конфигурации, loopback, порта, имён и UUID.
Случайный идентификатор текущего запуска создаёт новое имя УчебныйЦикл85_<UUID> и связанную метку владельца. Существующий профиль с таким именем не обновляется.
СоздатьПрофильБезопасности даёт новый объект с типовыми значениями по умолчанию. Имя и метка задаются только новому объекту; Записать регистрирует именно его.
После каждого важного изменения выполняется свежее административное чтение. Проверяются единственный точный ключ, метка собственного запуска и отсутствие назначения любой базе.
Обычное и безопасное назначение проверяются раздельно. Это запрет изменения используемого профиля, а не команда отключить назначение у базы.
При штатном завершении удаляется только собственный неназначенный временный профиль; перед этим все шесть списков разрешений должны быть пустыми. Удалить каскадно отменяет также оставшиеся разрешения, поэтому при неожиданном непустом списке действие запрещается.
При ошибке выполнение останавливается с этапом и точным временным ключом. Неопределённый результат RPC не исправляется повторной записью или слепым удалением.
Исходный образец ищется в УчебныйПрофиль85 по точному учебному ключу и типу до создания временного профиля. Его данные не заменяются выдуманными значениями.
Разрешение создаётся фабрикой на СвойПрофиль, то есть на новом подтверждённом временном профиле, а не на исходном. У него отдельный ключ и метка leaf:1.
Записать регистрирует новое разрешение; свежее чтение того же временного профиля проверяет его ключ и метку. Затем меняется только описание на leaf:2 и подтверждается повторное Записать.
Перед Удалить свежее чтение подтверждает отдельную запись текущего запуска. После удаления проверяется отсутствие её ключа; иначе каскадное удаление профиля не продолжается.
Все реальные ресурсные значения берутся из подготовленного собственного образца. COM ограничен localhost, виртуальный каталог — чтением без записи; программа, компонент, файл и веб-ресурс не запускаются.
Как проверить результат
Без включённого булева подтверждения изменений не должно быть подключения и регистрации. Все три пароля формы очищаются после успеха или ошибки.
При штатном ходе ПрофильЗарегистрирован, ПрофильОтсутствуетПослеУдаления и ЦиклЗавершен — Истина. Временное имя и метка содержат один и тот же UUID текущего запуска.
Сверьте исходную базу и УчебныйПрофиль85 штатными средствами: их назначения и существующие разрешения не изменены.
Если ЦиклЗавершен — Ложь, прочитайте ЭтапОстановки. По точному имени и метке вручную проверьте регистрацию, оба назначения и записи профиля; не повторяйте весь урок, ожидая автоматической очистки предыдущего запуска.
Проверки не означают, что пример был выполнен здесь. В 1С он не запускался; создаются только тексты и справочник.
Ожидаемый результат
Полный контролируемый учебный цикл с регистрацией, проверкой, отменой собственной регистрации и явной остановкой при неопределённом исходе.
На что обратить внимание
Самостоятельный запуск действительно меняет административные записи учебного сервера. Это не предыдущий урок черновика и не рекомендация экспериментировать на production.
Записать — не операция базы 1С в вашей транзакции; прежний снимок не доказывает атомарность с последующим RPC. На время опыта исключите конкурентное администрирование.
Имя и метка — контроль происхождения внутри собственного опыта, не механизм защиты от злоумышленного администратора. Любое несовпадение останавливает действия.
Нельзя назначать временный профиль базе ради проверки. Изменения действующего профиля по справке применяются после отсоединения последнего соединения; этот урок не заставляет рабочие сеансы переподключаться.
При сбое записи результат может быть неопределённым: объект мог зарегистрироваться, даже если клиент получил ошибку. Поэтому автоматической очистки в Исключение нет.
Удаление профиля удаляет все связанные с ним разрешения. Перед ним повторно проверяются точное имя, метка и отсутствие назначений; исходный профиль никогда не удаляется.
Статические проверки сверяют код, типы, сигнатуры и ограничители. Они не подтверждают регистрацию, доступ к ресурсу или отсутствие остатка на реальном сервере.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.