Настройка разрешений на использование внешних ресурсов / Модуль объекта

файл
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2024, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область ОписаниеПеременных

// Массив из УникальныйИдентификатор - идентификаторы запросов на использование внешних
// ресурсов, для применения которых инициализирован объект.
//
Перем ИдентификаторыЗапросов;

// План выполнения операций администрирования при применении запросов на использование внешних ресурсов.
Перем ОперацииАдминистрирования; // см. ОперацииАдминистрирования

// Текущий план применения запросов на использование внешних ресурсов.
Перем ПланПримененияЗапросов; // см. ПланПримененияЗапросов

// Исходный срез разрешений (в разрезе владельцев разрешений).
Перем ИсходныйСрезРазрешенийВРазрезеВладельцев; // см. РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.НовыйСрезРазрешенийВРазрезеВладельцев

// Исходный срез разрешений (без учета владельцев разрешений).
Перем ИсходныйСрезРазрешенийБезУчетаВладельцев; // см. РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.НовыйСрезРазрешений

// Срез разрешений в результате применения запросов (в разрезе владельцев разрешений).
Перем РезультатПримененияЗапросовВРазрезеВладельцев; // см. РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.НовыйСрезРазрешенийВРазрезеВладельцев

// Срез разрешений в результате применения запросов (в разрезе владельцев разрешений).
Перем РезультатПримененияЗапросовБезУчетаВладельцев; // см. РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.НовыйСрезРазрешений

// Дельта между исходным и результирующим срезами разрешений (в разрезе владельцев разрешений).
Перем ДельтаВРазрезеВладельцев; // см. ДельтаВРазрезеВладельцев

// Дельта между исходным и результирующим срезами разрешений (без учета владельцев разрешений).
Перем ДельтаБезУчетаВладельцев; // см. ДельтаБезУчетаВладельцев

// Флаг выполнения очистки информации о предоставленных разрешениях перед применением разрешений.
Перем ОчисткаРазрешенийПередПрименением; // Булево

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

// Добавляет идентификатор запроса в перечень обрабатываемых. После успешного применения будет выполнена очистка
// запросов, идентификаторы которых были добавлены.
//
// Параметры:
//  ИдентификаторЗапроса - УникальныйИдентификатор - идентификатор запроса на использование
//    внешних ресурсов.
//
Процедура ДобавитьИдентификаторЗапроса(Знач ИдентификаторЗапроса) Экспорт
	
	ИдентификаторыЗапросов.Добавить(ИдентификаторЗапроса);
	
КонецПроцедуры

// Добавляет в план применения запросов операцию администрирования профилей безопасности.
//
// Параметры:
//  ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//  ИдентификаторПрограммногоМодуля - УникальныйИдентификатор,
//  Операция - ПеречислениеСсылка.ОперацииАдминистрированияПрофилейБезопасности,
//  Имя - Строка - имя профиля безопасности.
//
Процедура ДобавитьОперациюАдминистрирования(Знач ТипПрограммногоМодуля, Знач ИдентификаторПрограммногоМодуля, Знач Операция, Знач Имя) Экспорт
	
	Отбор = Новый Структура();
	Отбор.Вставить("ТипПрограммногоМодуля", ТипПрограммногоМодуля);
	Отбор.Вставить("ИдентификаторПрограммногоМодуля", ИдентификаторПрограммногоМодуля);
	Отбор.Вставить("Операция", Операция);
	
	Строки = ОперацииАдминистрирования.НайтиСтроки(Отбор);
	
	Если Строки.Количество() = 0 Тогда
		
		Строка = ОперацииАдминистрирования.Добавить();
		ЗаполнитьЗначенияСвойств(Строка, Отбор);
		Строка.Имя = Имя;
		
	КонецЕсли;
	
КонецПроцедуры

// Добавляет свойства запроса разрешений на использование внешних ресурсов в план применения запросов.
//
// Параметры:
//  ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//  ИдентификаторПрограммногоМодуля - УникальныйИдентификатор,
//  ТипВладельца - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//  ИдентификаторВладельца - УникальныйИдентификатор,
//  РежимЗамещения - Булево,
//  ДобавляемыеРазрешения - Массив из ОбъектXDTO, Неопределено,
//  УдаляемыеРазрешения - Массив из ОбъектXDTO, Неопределено.
//
Процедура ДобавитьЗапросРазрешенийНаИспользованиеВнешнихРесурсов(
		Знач ТипПрограммногоМодуля, Знач ИдентификаторПрограммногоМодуля,
		Знач ТипВладельца, Знач ИдентификаторВладельца,
		Знач РежимЗамещения,
		Знач ДобавляемыеРазрешения = Неопределено,
		Знач УдаляемыеРазрешения = Неопределено) Экспорт
	
	Отбор = Новый Структура();
	Отбор.Вставить("ТипПрограммногоМодуля", ТипПрограммногоМодуля);
	Отбор.Вставить("ИдентификаторПрограммногоМодуля", ИдентификаторПрограммногоМодуля);
	
	Строка = Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
		ОперацииАдминистрирования, Отбор, Ложь);
	
	Если Строка = Неопределено Тогда
		
		Если ТипПрограммногоМодуля = Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка() Тогда
			
			Имя = Константы.ПрофильБезопасностиИнформационнойБазы.Получить();
			
		Иначе
			
			Имя = РегистрыСведений.РежимыПодключенияВнешнихМодулей.РежимПодключенияВнешнегоМодуля(
				РаботаВБезопасномРежимеСлужебный.СсылкаИзРегистраРазрешений(
					ТипПрограммногоМодуля, ИдентификаторПрограммногоМодуля));
			
		КонецЕсли;
		
		ДобавитьОперациюАдминистрирования(
			ТипПрограммногоМодуля,
			ИдентификаторПрограммногоМодуля,
			Перечисления.ОперацииАдминистрированияПрофилейБезопасности.Обновление,
			Имя);
		
	Иначе
		
		Имя = Строка.Имя;
		
	КонецЕсли;
	
	Если РежимЗамещения Тогда
		
		Отбор = Новый Структура();
		Отбор.Вставить("ТипПрограммногоМодуля", ТипПрограммногоМодуля);
		Отбор.Вставить("ИдентификаторПрограммногоМодуля", ИдентификаторПрограммногоМодуля);
		Отбор.Вставить("ТипВладельца", ТипВладельца);
		Отбор.Вставить("ИдентификаторВладельца", ИдентификаторВладельца);
		
		Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
			ПланПримененияЗапросов.Замещаемые, Отбор);
		
	КонецЕсли;
	
	Если ДобавляемыеРазрешения <> Неопределено Тогда
		
		Для Каждого ДобавляемоеРазрешение Из ДобавляемыеРазрешения Цикл
			
			Отбор = Новый Структура();
			Отбор.Вставить("ТипПрограммногоМодуля", ТипПрограммногоМодуля);
			Отбор.Вставить("ИдентификаторПрограммногоМодуля", ИдентификаторПрограммногоМодуля);
			Отбор.Вставить("ТипВладельца", ТипВладельца);
			Отбор.Вставить("ИдентификаторВладельца", ИдентификаторВладельца);
			Отбор.Вставить("Тип", ДобавляемоеРазрешение.Тип().Имя);
			
			Строка = Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
				ПланПримененияЗапросов.Добавляемые, Отбор);
			
			КлючРазрешения = РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения(ДобавляемоеРазрешение);
			ДополнениеРазрешения = РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.ДополнениеРазрешения(ДобавляемоеРазрешение);
			
			Строка.Разрешения.Вставить(КлючРазрешения, ОбщегоНазначения.ОбъектXDTOВСтрокуXML(ДобавляемоеРазрешение));
			
			Если ЗначениеЗаполнено(ДополнениеРазрешения) Тогда
				Строка.ДополненияРазрешений.Вставить(КлючРазрешения, ОбщегоНазначения.ЗначениеВСтрокуXML(ДополнениеРазрешения));
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЕсли;
	
	Если УдаляемыеРазрешения <> Неопределено Тогда
		
		Для Каждого УдаляемоеРазрешение Из УдаляемыеРазрешения Цикл
			
			Отбор = Новый Структура();
			Отбор.Вставить("ТипПрограммногоМодуля", ТипПрограммногоМодуля);
			Отбор.Вставить("ИдентификаторПрограммногоМодуля", ИдентификаторПрограммногоМодуля);
			Отбор.Вставить("ТипВладельца", ТипВладельца);
			Отбор.Вставить("ИдентификаторВладельца", ИдентификаторВладельца);
			Отбор.Вставить("Тип", УдаляемоеРазрешение.Тип().Имя);
			
			Строка = Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
				ПланПримененияЗапросов.Удаляемые, Отбор);
			
			КлючРазрешения = РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения(УдаляемоеРазрешение);
			ДополнениеРазрешения = РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.ДополнениеРазрешения(УдаляемоеРазрешение);
			
			Строка.Разрешения.Вставить(КлючРазрешения, ОбщегоНазначения.ОбъектXDTOВСтрокуXML(УдаляемоеРазрешение));
			
			Если ЗначениеЗаполнено(ДополнениеРазрешения) Тогда
				Строка.ДополненияРазрешений.Вставить(КлючРазрешения, ОбщегоНазначения.ЗначениеВСтрокуXML(ДополнениеРазрешения));
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЕсли;
	
КонецПроцедуры

// Добавляет в план применения запросов очистку информации о разрешениях из регистров.
// Используется в механизме восстановления профилей.
//
Процедура ДобавитьОчисткуРазрешенийПередПрименением() Экспорт
	
	ОчисткаРазрешенийПередПрименением = Истина;
	
КонецПроцедуры

// Рассчитывает результат применения запросов на использование внешних ресурсов.
//
Процедура РассчитатьПрименениеЗапросов() Экспорт
	
	ВнешняяТранзакция = ТранзакцияАктивна();
	Если Не ВнешняяТранзакция Тогда
		НачатьТранзакцию(); // АПК:326 для НачатьТранзакцию отсутствует парный ЗафиксироватьТранзакцию, т.к. действие отменяется.
	КонецЕсли;
	
	Попытка
		Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.ЗаблокироватьРегистрыПредоставленныхРазрешений();
		
		ИсходныйСрезРазрешенийВРазрезеВладельцев = РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.СрезРазрешений();
		РассчитатьРезультатПримененияЗапросовВРазрезеВладельцев();
		РассчитатьДельтуВРазрезеВладельцев();
		
		ИсходныйСрезРазрешенийБезУчетаВладельцев = РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.СрезРазрешений(Ложь, Истина);
		РассчитатьРезультатПримененияЗапросовБезУчетаВладельцев();
		РассчитатьДельтуБезУчетаВладельцев();
		
		Если Не ВнешняяТранзакция Тогда
			ОтменитьТранзакцию();
		КонецЕсли;
	Исключение
		Если Не ВнешняяТранзакция Тогда
			ОтменитьТранзакцию();
		КонецЕсли;
		ВызватьИсключение;
	КонецПопытки;
	
	Если ТребуетсяПрименениеРазрешенийВКластереСерверов() Тогда
		ЗаблокироватьДанныеДляРедактирования(Семафор());
	КонецЕсли;
	
КонецПроцедуры

// Проверяет необходимость применения разрешений в кластере серверов.
//
// Возвращаемое значение:
//   Булево
//
Функция ТребуетсяПрименениеРазрешенийВКластереСерверов() Экспорт
	
	Если ДельтаБезУчетаВладельцев.Добавляемые.Количество() > 0 Тогда
		Возврат Истина;
	КонецЕсли;
	
	Если ДельтаБезУчетаВладельцев.Удаляемые.Количество() > 0 Тогда
		Возврат Истина;
	КонецЕсли;
	
	Для Каждого ОперацияАдминистрирования Из ОперацииАдминистрирования Цикл
		Если ОперацияАдминистрирования.Операция = Перечисления.ОперацииАдминистрированияПрофилейБезопасности.Удаление Тогда
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

// Проверяет необходимости записи разрешений в регистры.
//
// Возвращаемое значение:
//   Булево
//
Функция ТребуетсяЗаписьРазрешенийВРегистр() Экспорт
	
	Если ДельтаВРазрезеВладельцев.Добавляемые.Количество() > 0 Тогда
		Возврат Истина;
	КонецЕсли;
	
	Если ДельтаВРазрезеВладельцев.Удаляемые.Количество() > 0 Тогда
		Возврат Истина;
	КонецЕсли;
	
	Для Каждого ОперацияАдминистрирования Из ОперацииАдминистрирования Цикл
		Если ОперацияАдминистрирования.Операция = Перечисления.ОперацииАдминистрированияПрофилейБезопасности.Удаление Тогда
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

// Возвращает представление запросов разрешений на использование внешних ресурсов.
//
// Параметры:
//  КакТребуемые - Булево - представление формируется как список разрешений, а не как список операций
//    при изменении разрешений.
//
// Возвращаемое значение:
//   ТабличныйДокумент
//
Функция Представление(Знач КакТребуемые = Ложь) Экспорт
	
	Возврат Отчеты.ИспользуемыеВнешниеРесурсы.ПредставлениеЗапросовРазрешенийНаИспользованиеВнешнихРесурсов(
		ОперацииАдминистрирования,
		ДельтаБезУчетаВладельцев.Добавляемые,
		ДельтаБезУчетаВладельцев.Удаляемые,
		КакТребуемые);
	
КонецФункции

// Возвращает сценарий применения запросов разрешений на использование внешних ресурсов.
//
// Возвращаемое значение:
//   Массив из Структура:
//                        * Операция - ПеречислениеСсылка.ОперацииАдминистрированияПрофилейБезопасности,
//                        * Профиль - Строка - имя профиля безопасности,
//                        * Разрешения - см. АдминистрированиеКластера.СвойстваПрофиляБезопасности
//
Функция СценарийПрименения() Экспорт
	
	Результат = Новый Массив();
	
	Для Каждого Описание Из ОперацииАдминистрирования Цикл
		
		ЭлементРезультата = Новый Структура("Операция,Профиль,Разрешения");
		ЭлементРезультата.Операция = Описание.Операция;
		ЭлементРезультата.Профиль = Описание.Имя;
		ЭлементРезультата.Разрешения = ПрофильВНотацииИнтерфейсаАдминистрированияКластера(ЭлементРезультата.Профиль, Описание.ТипПрограммногоМодуля, Описание.ИдентификаторПрограммногоМодуля);
		
		ЭтоПрофильКонфигурации = (Описание.ТипПрограммногоМодуля = Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка());
		
		Если ЭтоПрофильКонфигурации Тогда
			
			ПриоритетДополнительнойОперации = Ложь;
			
			Если Описание.Операция = Перечисления.ОперацииАдминистрированияПрофилейБезопасности.Создание Тогда
				ДополнительнаяОперация = Перечисления.ОперацииАдминистрированияПрофилейБезопасности.Назначение;
			КонецЕсли;
			
			Если Описание.Операция = Перечисления.ОперацииАдминистрированияПрофилейБезопасности.Удаление Тогда
				ДополнительнаяОперация = Перечисления.ОперацииАдминистрированияПрофилейБезопасности.УдалениеНазначения;
				ПриоритетДополнительнойОперации = Истина;
			КонецЕсли;
			
			ДополнительныйЭлемент = Новый Структура("Операция,Профиль,Разрешения", ДополнительнаяОперация, Описание.Имя);
			
		КонецЕсли;
		
		Если ЭтоПрофильКонфигурации И ПриоритетДополнительнойОперации Тогда
			
			Результат.Добавить(ДополнительныйЭлемент);
			
		КонецЕсли;
		
		Результат.Добавить(ЭлементРезультата);
		
		Если ЭтоПрофильКонфигурации И Не ПриоритетДополнительнойОперации Тогда
			
			Результат.Добавить(ДополнительныйЭлемент);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Сериализует внутреннее состояние объекта.
//
// Возвращаемое значение:
//   Строка.
//
Функция ЗаписатьСостояниеВСтрокуXML() Экспорт
	
	Состояние = Новый Структура();
	
	Состояние.Вставить("ИсходныйСрезРазрешенийВРазрезеВладельцев", ИсходныйСрезРазрешенийВРазрезеВладельцев);
	Состояние.Вставить("РезультатПримененияЗапросовВРазрезеВладельцев", РезультатПримененияЗапросовВРазрезеВладельцев);
	Состояние.Вставить("ДельтаВРазрезеВладельцев", ДельтаВРазрезеВладельцев);
	Состояние.Вставить("ИсходныйСрезРазрешенийБезУчетаВладельцев", ИсходныйСрезРазрешенийБезУчетаВладельцев);
	Состояние.Вставить("РезультатПримененияЗапросовБезУчетаВладельцев", РезультатПримененияЗапросовБезУчетаВладельцев);
	Состояние.Вставить("ДельтаБезУчетаВладельцев", ДельтаБезУчетаВладельцев);
	Состояние.Вставить("ОперацииАдминистрирования", ОперацииАдминистрирования);
	Состояние.Вставить("ИдентификаторыЗапросов", ИдентификаторыЗапросов);
	Состояние.Вставить("ОчисткаРазрешенийПередПрименением", ОчисткаРазрешенийПередПрименением);
	
	Возврат ОбщегоНазначения.ЗначениеВСтрокуXML(Состояние);
	
КонецФункции

// Десериализует внутреннее состояние объекта.
//
// Параметры:
//  СтрокаXML - Строка - результат, возвращенный функцией ЗаписатьСостояниеВСтрокуXML().
//
Процедура ПрочитатьСостояниеИзСтрокиXML(Знач СтрокаXML) Экспорт
	
	Состояние = ОбщегоНазначения.ЗначениеИзСтрокиXML(СтрокаXML);
	
	ИсходныйСрезРазрешенийВРазрезеВладельцев = Состояние.ИсходныйСрезРазрешенийВРазрезеВладельцев;
	РезультатПримененияЗапросовВРазрезеВладельцев = Состояние.РезультатПримененияЗапросовВРазрезеВладельцев;
	ДельтаВРазрезеВладельцев = Состояние.ДельтаВРазрезеВладельцев;
	ИсходныйСрезРазрешенийБезУчетаВладельцев = Состояние.ИсходныйСрезРазрешенийБезУчетаВладельцев;
	РезультатПримененияЗапросовБезУчетаВладельцев = Состояние.РезультатПримененияЗапросовБезУчетаВладельцев;
	ДельтаБезУчетаВладельцев = Состояние.ДельтаБезУчетаВладельцев;
	ОперацииАдминистрирования = Состояние.ОперацииАдминистрирования;
	ИдентификаторыЗапросов = Состояние.ИдентификаторыЗапросов;
	ОчисткаРазрешенийПередПрименением = Состояние.ОчисткаРазрешенийПередПрименением;
	
КонецПроцедуры

// Фиксирует в ИБ факт применения запросов на использование внешних ресурсов.
//
Процедура ЗавершитьПрименениеЗапросовНаИспользованиеВнешнихРесурсов() Экспорт
	
	НачатьТранзакцию();
	Попытка
		
		Если ТребуетсяЗаписьРазрешенийВРегистр() Тогда
			
			Если ОчисткаРазрешенийПередПрименением Тогда
				
				Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.ОчиститьПредоставленныеРазрешения(, Ложь);
				
			КонецЕсли;
			
			Для Каждого Удаляемые Из ДельтаВРазрезеВладельцев.Удаляемые Цикл
				
				Для Каждого КлючИЗначение Из Удаляемые.Разрешения Цикл
					
					РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.УдалитьРазрешение(
						Удаляемые.ТипПрограммногоМодуля,
						Удаляемые.ИдентификаторПрограммногоМодуля,
						Удаляемые.ТипВладельца,
						Удаляемые.ИдентификаторВладельца,
						КлючИЗначение.Ключ,
						ОбщегоНазначения.ОбъектXDTOИзСтрокиXML(КлючИЗначение.Значение));
					
				КонецЦикла;
				
			КонецЦикла;
			
			Для Каждого Добавляемые Из ДельтаВРазрезеВладельцев.Добавляемые Цикл
				
				Для Каждого КлючИЗначение Из Добавляемые.Разрешения Цикл
					
					Дополнение = Добавляемые.ДополненияРазрешений.Получить(КлючИЗначение.Ключ);
					Если Дополнение <> Неопределено Тогда
						Дополнение = ОбщегоНазначения.ЗначениеИзСтрокиXML(Дополнение);
					КонецЕсли;
					
					РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.ДобавитьРазрешение(
						Добавляемые.ТипПрограммногоМодуля,
						Добавляемые.ИдентификаторПрограммногоМодуля,
						Добавляемые.ТипВладельца,
						Добавляемые.ИдентификаторВладельца,
						КлючИЗначение.Ключ,
						ОбщегоНазначения.ОбъектXDTOИзСтрокиXML(КлючИЗначение.Значение),
						Дополнение);
					
				КонецЦикла;
				
			КонецЦикла;
			
			Для Каждого Описание Из ОперацииАдминистрирования Цикл
				
				ЭтоПрофильКонфигурации = (Описание.ТипПрограммногоМодуля = Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка());
				
				Если Описание.Операция = Перечисления.ОперацииАдминистрированияПрофилейБезопасности.Создание Тогда
					
					Если ЭтоПрофильКонфигурации Тогда
						
						Константы.ПрофильБезопасностиИнформационнойБазы.Установить(Описание.Имя);
						
					Иначе
						
						Менеджер = РегистрыСведений.РежимыПодключенияВнешнихМодулей.СоздатьМенеджерЗаписи();
						Менеджер.ТипПрограммногоМодуля = Описание.ТипПрограммногоМодуля;
						Менеджер.ИдентификаторПрограммногоМодуля = Описание.ИдентификаторПрограммногоМодуля;
						Менеджер.БезопасныйРежим = Описание.Имя;
						Менеджер.Записать();
						
					КонецЕсли;
					
				КонецЕсли;
				
				Если Описание.Операция = Перечисления.ОперацииАдминистрированияПрофилейБезопасности.Удаление Тогда
					
					Если ЭтоПрофильКонфигурации Тогда
						
						Константы.ПрофильБезопасностиИнформационнойБазы.Установить("");
						Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.ОчиститьПредоставленныеРазрешения();
						
					Иначе
						
						ПрограммныйМодуль = РаботаВБезопасномРежимеСлужебный.СсылкаИзРегистраРазрешений(
							Описание.ТипПрограммногоМодуля, Описание.ИдентификаторПрограммногоМодуля);
						Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.ОчиститьПредоставленныеРазрешения(
							ПрограммныйМодуль, Истина);
						
					КонецЕсли;
					
				КонецЕсли;
				
			КонецЦикла;
			
		КонецЕсли;
		
		РегистрыСведений.ЗапросыРазрешенийНаИспользованиеВнешнихРесурсов.УдалитьЗапросы(ИдентификаторыЗапросов);
		РегистрыСведений.ЗапросыРазрешенийНаИспользованиеВнешнихРесурсов.ОчиститьНеактуальныеЗапросы();
		
		РазблокироватьДанныеДляРедактирования(Семафор());
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Рассчитывает результат применения запросов в разрезе владельцев.
//
Процедура РассчитатьРезультатПримененияЗапросовВРазрезеВладельцев()
	
	РезультатПримененияЗапросовВРазрезеВладельцев = Новый ТаблицаЗначений();
	
	Для Каждого ИсходнаяКолонка Из ИсходныйСрезРазрешенийВРазрезеВладельцев.Колонки Цикл
		РезультатПримененияЗапросовВРазрезеВладельцев.Колонки.Добавить(ИсходнаяКолонка.Имя, ИсходнаяКолонка.ТипЗначения);
	КонецЦикла;
	
	Для Каждого ИсходнаяСтрока Из ИсходныйСрезРазрешенийВРазрезеВладельцев Цикл
		НоваяСтрока = РезультатПримененияЗапросовВРазрезеВладельцев.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, ИсходнаяСтрока);
	КонецЦикла;
	
	// Применяем план
	
	// Замещение
	Для Каждого СтрокаТаблицыЗамещения Из ПланПримененияЗапросов.Замещаемые Цикл
		
		Отбор = Новый Структура();
		Отбор.Вставить("ТипПрограммногоМодуля", СтрокаТаблицыЗамещения.ТипПрограммногоМодуля);
		Отбор.Вставить("ИдентификаторПрограммногоМодуля", СтрокаТаблицыЗамещения.ИдентификаторПрограммногоМодуля);
		Отбор.Вставить("ТипВладельца", СтрокаТаблицыЗамещения.ТипВладельца);
		Отбор.Вставить("ИдентификаторВладельца", СтрокаТаблицыЗамещения.ИдентификаторВладельца);
		
		Строки = РезультатПримененияЗапросовВРазрезеВладельцев.НайтиСтроки(Отбор);
		
		Для Каждого Строка Из Строки Цикл
			РезультатПримененияЗапросовВРазрезеВладельцев.Удалить(Строка);
		КонецЦикла;
		
	КонецЦикла;
	
	// Добавление разрешений
	Для Каждого СтрокаДобавленных Из ПланПримененияЗапросов.Добавляемые Цикл
		
		Отбор = Новый Структура();
		Отбор.Вставить("ТипПрограммногоМодуля", СтрокаДобавленных.ТипПрограммногоМодуля);
		Отбор.Вставить("ИдентификаторПрограммногоМодуля", СтрокаДобавленных.ИдентификаторПрограммногоМодуля);
		Отбор.Вставить("ТипВладельца", СтрокаДобавленных.ТипВладельца);
		Отбор.Вставить("ИдентификаторВладельца", СтрокаДобавленных.ИдентификаторВладельца);
		Отбор.Вставить("Тип", СтрокаДобавленных.Тип);
		
		Строка = Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
			РезультатПримененияЗапросовВРазрезеВладельцев, Отбор);
		
		Для Каждого КлючИЗначение Из СтрокаДобавленных.Разрешения Цикл
			
			Строка.Разрешения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение);
			
			Если СтрокаДобавленных.ДополненияРазрешений.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда
				Строка.ДополненияРазрешений.Вставить(КлючИЗначение.Ключ, СтрокаДобавленных.ДополненияРазрешений.Получить(КлючИЗначение.Ключ));
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
	// Удаление разрешений
	Для Каждого СтрокаУдаляемых Из ПланПримененияЗапросов.Удаляемые Цикл
		
		Отбор = Новый Структура();
		Отбор.Вставить("ТипПрограммногоМодуля", СтрокаУдаляемых.ТипПрограммногоМодуля);
		Отбор.Вставить("ИдентификаторПрограммногоМодуля", СтрокаУдаляемых.ИдентификаторПрограммногоМодуля);
		Отбор.Вставить("ТипВладельца", СтрокаУдаляемых.ТипВладельца);
		Отбор.Вставить("ИдентификаторВладельца", СтрокаУдаляемых.ИдентификаторВладельца);
		Отбор.Вставить("Тип", СтрокаУдаляемых.Тип);
		
		Строка = Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
			РезультатПримененияЗапросовВРазрезеВладельцев, Отбор);
		
		Для Каждого КлючИЗначение Из СтрокаУдаляемых.Разрешения Цикл
			
			Строка.Разрешения.Удалить(КлючИЗначение.Ключ);
			
			Если СтрокаУдаляемых.ДополненияРазрешений.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда
				
				Строка.ДополненияРазрешений.Вставить(КлючИЗначение.Ключ, СтрокаУдаляемых.ДополненияРазрешений.Получить(КлючИЗначение.Ключ));
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

// Рассчитывает результат применения запросов без учета владельцев.
//
Процедура РассчитатьРезультатПримененияЗапросовБезУчетаВладельцев()
	
	РезультатПримененияЗапросовБезУчетаВладельцев = Новый ТаблицаЗначений();
	
	Для Каждого ИсходнаяКолонка Из ИсходныйСрезРазрешенийБезУчетаВладельцев.Колонки Цикл
		РезультатПримененияЗапросовБезУчетаВладельцев.Колонки.Добавить(ИсходнаяКолонка.Имя, ИсходнаяКолонка.ТипЗначения);
	КонецЦикла;
	
	Для Каждого СтрокаРезультата Из РезультатПримененияЗапросовВРазрезеВладельцев Цикл
		
		Отбор = Новый Структура();
		Отбор.Вставить("ТипПрограммногоМодуля", СтрокаРезультата.ТипПрограммногоМодуля);
		Отбор.Вставить("ИдентификаторПрограммногоМодуля", СтрокаРезультата.ИдентификаторПрограммногоМодуля);
		Отбор.Вставить("Тип", СтрокаРезультата.Тип);
		
		Строка = Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
			РезультатПримененияЗапросовБезУчетаВладельцев, Отбор);
		
		Для Каждого КлючИЗначение Из СтрокаРезультата.Разрешения Цикл
			
			ИсходноеРазрешение = ОбщегоНазначения.ОбъектXDTOИзСтрокиXML(КлючИЗначение.Значение);
			// Описания не должны влиять на хеш-суммы для варианта без учета владельцев.
			ОписаниеРазрешения = ИсходноеРазрешение.Description;
			ИсходноеРазрешение.Description = ""; 
			КлючРазрешения = РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения(ИсходноеРазрешение);
			
			Разрешение = Строка.Разрешения.Получить(КлючРазрешения);
			Если Разрешение = Неопределено Тогда
				
				Если СтрокаРезультата.Тип = "FileSystemAccess" Тогда
					
					// Для разрешений на использование каталога файловой системы дополнительно ищем
					// вложенные или объемлющие разрешения.
					
					Если ИсходноеРазрешение.AllowedRead Тогда
						
						Если ИсходноеРазрешение.AllowedWrite Тогда
							
							// Выполним поиск разрешения на использование того же каталога, но только для чтения.
							КопияРазрешения = ОбщегоНазначения.ОбъектXDTOИзСтрокиXML(ОбщегоНазначения.ОбъектXDTOВСтрокуXML(ИсходноеРазрешение));
							КопияРазрешения.AllowedWrite = Ложь;
							КлючКопии = РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения(КопияРазрешения);
							
							// Удалим вложенное разрешение, после добавления текущего оно будет не нужно.
							ВложенноеРазрешение = Строка.Разрешения.Получить(КлючКопии);
							Если ВложенноеРазрешение <> Неопределено Тогда
								Строка.Разрешения.Удалить(КлючКопии);
							КонецЕсли;
							
						Иначе
							
							// Выполним поиск разрешения на использование того же каталога, но в т.ч. и для записи.
							КопияРазрешения = ОбщегоНазначения.ОбъектXDTOИзСтрокиXML(ОбщегоНазначения.ОбъектXDTOВСтрокуXML(ИсходноеРазрешение));
							КопияРазрешения.AllowedWrite = Истина;
							КлючКопии = РегистрыСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения(КопияРазрешения);
							
							// Обрабатывать это разрешение не требуется, каталог будет разрешен за счет объемлющего.
							ОбъемлющееРазрешение = Строка.Разрешения.Получить(КлючКопии);
							Если ОбъемлющееРазрешение <> Неопределено Тогда
								Продолжить;
							КонецЕсли;
							
						КонецЕсли;
						
					КонецЕсли;
					
				КонецЕсли;
				
				ИсходноеРазрешение.Description = ОписаниеРазрешения; 
				Строка.Разрешения.Вставить(КлючРазрешения, ОбщегоНазначения.ОбъектXDTOВСтрокуXML(ИсходноеРазрешение));
				
				Дополнение = СтрокаРезультата.ДополненияРазрешений.Получить(КлючИЗначение.Ключ);
				Если Дополнение <> Неопределено Тогда
					Строка.ДополненияРазрешений.Вставить(КлючРазрешения, Дополнение);
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

// Возвращаемое значение:
//  Структура:
//   * Добавляемые - ТаблицаЗначений - описание добавляемых разрешений, колонки:
//    ** ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//    ** ИдентификаторПрограммногоМодуля - УникальныйИдентификатор,
//    ** ТипВладельца - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//    ** ИдентификаторВладельца - УникальныйИдентификатор,
//    ** Тип - Строка - имя XDTO-типа, описывающего разрешения,
//    ** Разрешения - Соответствие из КлючИЗначение:
//      *** Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//      *** Значение - ОбъектXDTO - XDTO-описание разрешения,
//    ** ДополненияРазрешений - Соответствие из КлючИЗначение - описание дополнений разрешений:
//      *** Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//      *** Значение - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.ДополнениеРазрешения
//   * Удаляемые - ТаблицаЗначений - описание удаляемых разрешений, колонки:
//    ** ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//    ** ИдентификаторПрограммногоМодуля - УникальныйИдентификатор,
//    ** ТипВладельца - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//    ** ИдентификаторВладельца - УникальныйИдентификатор,
//    ** Тип - Строка - имя XDTO-типа, описывающего разрешения,
//    ** Разрешения - Соответствие из КлючИЗначение:
//      *** Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//      *** Значение - ОбъектXDTO - XDTO-описание разрешения,
//    ** ДополненияРазрешений - Соответствие из КлючИЗначение:
//      *** Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//      *** Значение - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.ДополнениеРазрешения
//
Функция ДельтаВРазрезеВладельцев()
		
	Результат = Новый Структура();
	
	Результат.Вставить("Добавляемые", Новый ТаблицаЗначений);
	Результат.Добавляемые.Колонки.Добавить("ТипПрограммногоМодуля", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	Результат.Добавляемые.Колонки.Добавить("ИдентификаторПрограммногоМодуля", Новый ОписаниеТипов("УникальныйИдентификатор"));
	Результат.Добавляемые.Колонки.Добавить("ТипВладельца", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	Результат.Добавляемые.Колонки.Добавить("ИдентификаторВладельца", Новый ОписаниеТипов("УникальныйИдентификатор"));
	Результат.Добавляемые.Колонки.Добавить("Тип", Новый ОписаниеТипов("Строка"));
	Результат.Добавляемые.Колонки.Добавить("Разрешения", Новый ОписаниеТипов("Соответствие"));
	Результат.Добавляемые.Колонки.Добавить("ДополненияРазрешений", Новый ОписаниеТипов("Соответствие"));
	
	Результат.Вставить("Удаляемые", Новый ТаблицаЗначений);
	Результат.Удаляемые.Колонки.Добавить("ТипПрограммногоМодуля", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	Результат.Удаляемые.Колонки.Добавить("ИдентификаторПрограммногоМодуля", Новый ОписаниеТипов("УникальныйИдентификатор"));
	Результат.Удаляемые.Колонки.Добавить("ТипВладельца", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	Результат.Удаляемые.Колонки.Добавить("ИдентификаторВладельца", Новый ОписаниеТипов("УникальныйИдентификатор"));
	Результат.Удаляемые.Колонки.Добавить("Тип", Новый ОписаниеТипов("Строка"));
	Результат.Удаляемые.Колонки.Добавить("Разрешения", Новый ОписаниеТипов("Соответствие"));
	Результат.Удаляемые.Колонки.Добавить("ДополненияРазрешений", Новый ОписаниеТипов("Соответствие"));
	
	Возврат Результат;
	
КонецФункции

// Рассчитывает дельту двух срезов разрешений в разрезе владельцев разрешений.
//
Процедура РассчитатьДельтуВРазрезеВладельцев()
	
	ДельтаВРазрезеВладельцев = ДельтаВРазрезеВладельцев();
	
	// Сравниваем исходные разрешения с результирующими.
	
	Для Каждого Строка Из ИсходныйСрезРазрешенийВРазрезеВладельцев Цикл
		
		Отбор = Новый Структура();
		Отбор.Вставить("ТипПрограммногоМодуля", Строка.ТипПрограммногоМодуля);
		Отбор.Вставить("ИдентификаторПрограммногоМодуля", Строка.ИдентификаторПрограммногоМодуля);
		Отбор.Вставить("ТипВладельца", Строка.ТипВладельца);
		Отбор.Вставить("ИдентификаторВладельца", Строка.ИдентификаторВладельца);
		Отбор.Вставить("Тип", Строка.Тип);
		
		Строки = РезультатПримененияЗапросовВРазрезеВладельцев.НайтиСтроки(Отбор);
		Если Строки.Количество() > 0 Тогда
			СтрокаРезультата = Строки.Получить(0);
		Иначе
			СтрокаРезультата = Неопределено;
		КонецЕсли;
		
		Для Каждого КлючИЗначение Из Строка.Разрешения Цикл
			
			Если СтрокаРезультата = Неопределено Или СтрокаРезультата.Разрешения.Получить(КлючИЗначение.Ключ) = Неопределено Тогда
				
				// Разрешение было в исходных, но отсутствует в результирующих - это удаляемое разрешение.
				
				СтрокаУдаляемых = Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
					ДельтаВРазрезеВладельцев.Удаляемые, Отбор);
				
				Если СтрокаУдаляемых.Разрешения.Получить(КлючИЗначение.Ключ) = Неопределено Тогда
					
					СтрокаУдаляемых.Разрешения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение);
					
					Если Строка.ДополненияРазрешений.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда
						СтрокаУдаляемых.ДополненияРазрешений.Вставить(КлючИЗначение.Ключ, Строка.ДополненияРазрешений.Получить(КлючИЗначение.Ключ));
					КонецЕсли;
					
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
	// Сравниваем результирующие разрешения с исходными.
	
	Для Каждого Строка Из РезультатПримененияЗапросовВРазрезеВладельцев Цикл
		
		Отбор = Новый Структура();
		Отбор.Вставить("ТипПрограммногоМодуля", Строка.ТипПрограммногоМодуля);
		Отбор.Вставить("ИдентификаторПрограммногоМодуля", Строка.ИдентификаторПрограммногоМодуля);
		Отбор.Вставить("ТипВладельца", Строка.ТипВладельца);
		Отбор.Вставить("ИдентификаторВладельца", Строка.ИдентификаторВладельца);
		Отбор.Вставить("Тип", Строка.Тип);
		
		Строки = ИсходныйСрезРазрешенийВРазрезеВладельцев.НайтиСтроки(Отбор);
		Если Строки.Количество() > 0 Тогда
			ИсходнаяСтрока = Строки.Получить(0);
		Иначе
			ИсходнаяСтрока = Неопределено;
		КонецЕсли;
		
		Для Каждого КлючИЗначение Из Строка.Разрешения Цикл
			
			Если ИсходнаяСтрока = Неопределено ИЛИ ИсходнаяСтрока.Разрешения.Получить(КлючИЗначение.Ключ) = Неопределено Тогда
				
				// Разрешение есть в результирующих, но отсутствует в исходных - это добавляемое разрешение.
				
				СтрокаДобавляемых = Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
					ДельтаВРазрезеВладельцев.Добавляемые, Отбор);
				
				Если СтрокаДобавляемых.Разрешения.Получить(КлючИЗначение.Ключ) = Неопределено Тогда
					
					СтрокаДобавляемых.Разрешения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение);
					
					Если Строка.ДополненияРазрешений.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда
						СтрокаДобавляемых.ДополненияРазрешений.Вставить(КлючИЗначение.Ключ, Строка.ДополненияРазрешений.Получить(КлючИЗначение.Ключ));
					КонецЕсли;
					
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

// Возвращаемое значение:
//  Структура:
//   * Добавляемые - ТаблицаЗначений - описание добавляемых разрешений, колонки:
//    ** ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//    ** ИдентификаторПрограммногоМодуля - УникальныйИдентификатор,
//    ** Тип - Строка - имя XDTO-типа, описывающего разрешения,
//    ** Разрешения - Соответствие из КлючИЗначение:
//      *** Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//      *** Значение - ОбъектXDTO - XDTO-описание разрешения,
//    ** ДополненияРазрешений - Соответствие из КлючИЗначение:
//      *** Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//      *** Значение - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.ДополнениеРазрешения
//   * Удаляемые - ТаблицаЗначений - описание удаляемых разрешений, колонки:
//    ** ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//    ** ИдентификаторПрограммногоМодуля - УникальныйИдентификатор,
//    ** Тип - Строка - имя XDTO-типа, описывающего разрешения,
//    ** Разрешения - Соответствие из КлючИЗначение:
//      *** Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//      *** Значение - ОбъектXDTO - XDTO-описание разрешения,
//    ** ДополненияРазрешений - Соответствие из КлючИЗначение:
//      *** Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//      *** Значение - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.ДополнениеРазрешения
//
Функция ДельтаБезУчетаВладельцев()
	
	Результат = Новый Структура();
	
	Результат.Вставить("Добавляемые", Новый ТаблицаЗначений);
	Результат.Добавляемые.Колонки.Добавить("ТипПрограммногоМодуля", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	Результат.Добавляемые.Колонки.Добавить("ИдентификаторПрограммногоМодуля", Новый ОписаниеТипов("УникальныйИдентификатор"));
	Результат.Добавляемые.Колонки.Добавить("Тип", Новый ОписаниеТипов("Строка"));
	Результат.Добавляемые.Колонки.Добавить("Разрешения", Новый ОписаниеТипов("Соответствие"));
	Результат.Добавляемые.Колонки.Добавить("ДополненияРазрешений", Новый ОписаниеТипов("Соответствие"));
	
	Результат.Вставить("Удаляемые", Новый ТаблицаЗначений);
	Результат.Удаляемые.Колонки.Добавить("ТипПрограммногоМодуля", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	Результат.Удаляемые.Колонки.Добавить("ИдентификаторПрограммногоМодуля", Новый ОписаниеТипов("УникальныйИдентификатор"));
	Результат.Удаляемые.Колонки.Добавить("Тип", Новый ОписаниеТипов("Строка"));
	Результат.Удаляемые.Колонки.Добавить("Разрешения", Новый ОписаниеТипов("Соответствие"));
	Результат.Удаляемые.Колонки.Добавить("ДополненияРазрешений", Новый ОписаниеТипов("Соответствие"));
	
	Возврат Результат;
	
КонецФункции 

// Рассчитывает дельту двух срезов разрешений без учета владельцев разрешений.
//
Процедура РассчитатьДельтуБезУчетаВладельцев()
	
	ДельтаБезУчетаВладельцев = ДельтаБезУчетаВладельцев();
	
	// Сравниваем исходные разрешения с результирующими.
	
	Для Каждого Строка Из ИсходныйСрезРазрешенийБезУчетаВладельцев Цикл
		
		Отбор = Новый Структура();
		Отбор.Вставить("ТипПрограммногоМодуля", Строка.ТипПрограммногоМодуля);
		Отбор.Вставить("ИдентификаторПрограммногоМодуля", Строка.ИдентификаторПрограммногоМодуля);
		Отбор.Вставить("Тип", Строка.Тип);
		
		Строки = РезультатПримененияЗапросовБезУчетаВладельцев.НайтиСтроки(Отбор);
		Если Строки.Количество() > 0 Тогда
			СтрокаРезультата = Строки.Получить(0);
		Иначе
			СтрокаРезультата = Неопределено;
		КонецЕсли;
		
		Для Каждого КлючИЗначение Из Строка.Разрешения Цикл
			
			Если СтрокаРезультата = Неопределено ИЛИ СтрокаРезультата.Разрешения.Получить(КлючИЗначение.Ключ) = Неопределено Тогда
				
				// Разрешение было в исходных, но отсутствует в результирующих - это удаляемое разрешение.
				
				СтрокаУдаляемых = Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
					ДельтаБезУчетаВладельцев.Удаляемые, Отбор);
				
				Если СтрокаУдаляемых.Разрешения.Получить(КлючИЗначение.Ключ) = Неопределено Тогда
					
					СтрокаУдаляемых.Разрешения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение);
					
					Если Строка.ДополненияРазрешений.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда
						СтрокаУдаляемых.ДополненияРазрешений.Вставить(КлючИЗначение.Ключ, Строка.ДополненияРазрешений.Получить(КлючИЗначение.Ключ));
					КонецЕсли;
					
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
	// Сравниваем результирующие разрешения с исходными.
	
	Для Каждого Строка Из РезультатПримененияЗапросовБезУчетаВладельцев Цикл
		
		Отбор = Новый Структура();
		Отбор.Вставить("ТипПрограммногоМодуля", Строка.ТипПрограммногоМодуля);
		Отбор.Вставить("ИдентификаторПрограммногоМодуля", Строка.ИдентификаторПрограммногоМодуля);
		Отбор.Вставить("Тип", Строка.Тип);
		
		Строки = ИсходныйСрезРазрешенийБезУчетаВладельцев.НайтиСтроки(Отбор);
		Если Строки.Количество() > 0 Тогда
			ИсходнаяСтрока = Строки.Получить(0);
		Иначе
			ИсходнаяСтрока = Неопределено;
		КонецЕсли;
		
		Для Каждого КлючИЗначение Из Строка.Разрешения Цикл
			
			Если ИсходнаяСтрока = Неопределено ИЛИ ИсходнаяСтрока.Разрешения.Получить(КлючИЗначение.Ключ) = Неопределено Тогда
				
				// Разрешение есть в результирующих, но отсутствует в исходных - это добавляемое разрешение.
				
				СтрокаДобавляемых = Обработки.НастройкаРазрешенийНаИспользованиеВнешнихРесурсов.СтрокаТаблицыРазрешений(
					ДельтаБезУчетаВладельцев.Добавляемые, Отбор);
				
				Если СтрокаДобавляемых.Разрешения.Получить(КлючИЗначение.Ключ) = Неопределено Тогда
					
					СтрокаДобавляемых.Разрешения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение);
					
					Если Строка.ДополненияРазрешений.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда
						СтрокаДобавляемых.ДополненияРазрешений.Вставить(КлючИЗначение.Ключ, Строка.ДополненияРазрешений.Получить(КлючИЗначение.Ключ));
					КонецЕсли;
					
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

// Формирует описание профиля безопасности в нотации программного интерфейса администрирования
// кластера серверов.
//
// Параметры:
//  ИмяПрофиля - Строка - имя профиля безопасности,
//  ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//  ИдентификаторПрограммногоМодуля - УникальныйИдентификатор.
//
// Возвращаемое значение:
//   см. АдминистрированиеКластера.СвойстваПрофиляБезопасности
//
Функция ПрофильВНотацииИнтерфейсаАдминистрированияКластера(Знач ИмяПрофиля, Знач ТипПрограммногоМодуля, Знач ИдентификаторПрограммногоМодуля)
	
	Профиль = АдминистрированиеКластера.СвойстваПрофиляБезопасности();
	Профиль.Имя = ИмяПрофиля;
	Профиль.Описание = НовоеОписаниеПрофиляБезопасности(ТипПрограммногоМодуля, ИдентификаторПрограммногоМодуля);
	Профиль.ПрофильБезопасногоРежима = Истина;
	
	Профиль.ПолныйДоступКФайловойСистеме = Ложь;
	Профиль.ПолныйДоступКCOMОбъектам = Ложь;
	Профиль.ПолныйДоступКВнешнимКомпонентам = Ложь;
	Профиль.ПолныйДоступКВнешнимМодулям = Ложь;
	Профиль.ПолныйДоступКПриложениямОперационнойСистемы = Ложь;
	Профиль.ПолныйДоступКИнтернетРесурсам = Ложь;
	
	Профиль.ПолныйДоступКПривилегированномуРежиму = Ложь;
	
	Отбор = Новый Структура();
	Отбор.Вставить("ТипПрограммногоМодуля", ТипПрограммногоМодуля);
	Отбор.Вставить("ИдентификаторПрограммногоМодуля", ИдентификаторПрограммногоМодуля);
	
	Строки = РезультатПримененияЗапросовБезУчетаВладельцев.НайтиСтроки(Отбор);
	
	Для Каждого Строка Из Строки Цикл
		
		Для Каждого КлючИЗначение Из Строка.Разрешения Цикл
			
			Разрешение = ОбщегоНазначения.ОбъектXDTOИзСтрокиXML(КлючИЗначение.Значение);
			
			Если Строка.Тип = "FileSystemAccess" Тогда
				
				Если СтандартныеВиртуальныеКаталоги().Получить(Разрешение.Path) <> Неопределено Тогда
					
					ВиртуальныйКаталог = АдминистрированиеКластера.СвойстваВиртуальногоКаталога();
					ВиртуальныйКаталог.ЛогическийURL = Разрешение.Path;
					ВиртуальныйКаталог.ФизическийURL = СтандартныеВиртуальныеКаталоги().Получить(Разрешение.Path);
					ВиртуальныйКаталог.ЧтениеДанных = Разрешение.AllowedRead;
					ВиртуальныйКаталог.ЗаписьДанных = Разрешение.AllowedWrite;
					ВиртуальныйКаталог.Описание = Разрешение.Description;
					Профиль.ВиртуальныеКаталоги.Добавить(ВиртуальныйКаталог);
					
				Иначе
					
					ВиртуальныйКаталог = АдминистрированиеКластера.СвойстваВиртуальногоКаталога();
					ВиртуальныйКаталог.ЛогическийURL = Разрешение.Path;
					ВиртуальныйКаталог.ФизическийURL = ЭкранироватьСимволПроцент(Разрешение.Path);
					ВиртуальныйКаталог.ЧтениеДанных = Разрешение.AllowedRead;
					ВиртуальныйКаталог.ЗаписьДанных = Разрешение.AllowedWrite;
					ВиртуальныйКаталог.Описание = Разрешение.Description;
					Профиль.ВиртуальныеКаталоги.Добавить(ВиртуальныйКаталог);
					
				КонецЕсли;
				
			ИначеЕсли Строка.Тип = "CreateComObject" Тогда
				
				COMКласс = АдминистрированиеКластера.СвойстваCOMКласса();
				COMКласс.Имя = Разрешение.ProgId;
				COMКласс.CLSID = Разрешение.CLSID;
				COMКласс.Компьютер = Разрешение.ComputerName;
				COMКласс.Описание = Разрешение.Description;
				Профиль.COMКлассы.Добавить(COMКласс);
				
			ИначеЕсли Строка.Тип = "AttachAddin" Тогда
				
				Дополнение = ОбщегоНазначения.ЗначениеИзСтрокиXML(Строка.ДополненияРазрешений.Получить(КлючИЗначение.Ключ));
				Для Каждого КлючИЗначениеДополнения Из Дополнение Цикл
					
					ВнешнийКомпонент = АдминистрированиеКластера.СвойстваВнешнейКомпоненты();
					ВнешнийКомпонент.Имя = Разрешение.TemplateName + "\" + КлючИЗначениеДополнения.Ключ;
					ВнешнийКомпонент.ХешСумма = КлючИЗначениеДополнения.Значение;
					ВнешнийКомпонент.Описание = Разрешение.Description;
					Профиль.ВнешниеКомпоненты.Добавить(ВнешнийКомпонент);
					
				КонецЦикла;
				
			ИначеЕсли Строка.Тип = "ExternalModule" Тогда
				
				ВнешнийМодуль = АдминистрированиеКластера.СвойстваВнешнегоМодуля();
				ВнешнийМодуль.Имя = Разрешение.Name;
				ВнешнийМодуль.ХешСумма = Разрешение.Hash;
				ВнешнийМодуль.Описание = Разрешение.Description;
				Профиль.ВнешниеМодули.Добавить(ВнешнийМодуль);
				
			ИначеЕсли Строка.Тип = "RunApplication" Тогда
				
				ПриложениеОС = АдминистрированиеКластера.СвойстваПриложенияОС();
				ПриложениеОС.Имя = Разрешение.CommandMask;
				ПриложениеОС.ШаблонСтрокиЗапуска = Разрешение.CommandMask;
				ПриложениеОС.Описание = Разрешение.Description;
				Профиль.ПриложенияОС.Добавить(ПриложениеОС);
				
			ИначеЕсли Строка.Тип = "InternetResourceAccess" Тогда
				
				ИнтернетРесурс = АдминистрированиеКластера.СвойстваИнтернетРесурса();
				ИнтернетРесурс.Имя = НРег(Разрешение.Protocol) + "://" + НРег(Разрешение.Host) + ":" + Разрешение.Port;
				ИнтернетРесурс.Протокол = Разрешение.Protocol;
				ИнтернетРесурс.Адрес = Разрешение.Host;
				ИнтернетРесурс.Порт = Разрешение.Port;
				ИнтернетРесурс.Описание = Разрешение.Description;
				Профиль.ИнтернетРесурсы.Добавить(ИнтернетРесурс);
				
			ИначеЕсли Строка.Тип = "ExternalModulePrivilegedModeAllowed" Тогда
				
				Профиль.ПолныйДоступКПривилегированномуРежиму = Истина;
				
			КонецЕсли;
			
			
		КонецЦикла;
		
	КонецЦикла;
	
	Возврат Профиль;
	
КонецФункции

// Формирует описание профиля безопасности для информационной базы или внешнего модуля.
//
// Параметры:
//  ВнешнийМодуль - ЛюбаяСсылка - ссылка на элемент справочника, использующийся в
//    качестве внешнего модуля.
//
// Возвращаемое значение: 
//   Строка - описание профиля безопасности.
//
Функция НовоеОписаниеПрофиляБезопасности(Знач ТипПрограммногоМодуля, Знач ИдентификаторПрограммногоМодуля)
	
	Шаблон = НСтр("ru = '[ИБ %1] %2 ""%3""'");
	
	ИмяИБ = "";
	СтрокаСоединения = СтрокаСоединенияИнформационнойБазы();
	Подстроки = СтрРазделить(СтрокаСоединения, ";");
	Для Каждого Подстрока Из Подстроки Цикл
		Если СтрНачинаетсяС(Подстрока, "Ref") Тогда
			ИмяИБ = СтрЗаменить(Прав(Подстрока, СтрДлина(Подстрока) - 4), """", "");
		КонецЕсли;
	КонецЦикла;
	Если ПустаяСтрока(ИмяИБ) Тогда
		ВызватьИсключение НСтр("ru = 'Строка соединения информационной базы должна содержать информационной базы'");
	КонецЕсли;
	
	Если ТипПрограммногоМодуля = Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка() Тогда
		Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, ИмяИБ,
			НСтр("ru = 'Профиль безопасности для информационной базы'"), СтрокаСоединенияИнформационнойБазы());
	Иначе
		ПрограммныйМодуль = РаботаВБезопасномРежимеСлужебный.СсылкаИзРегистраРазрешений(ТипПрограммногоМодуля, ИдентификаторПрограммногоМодуля);
		Словарь = РаботаВБезопасномРежимеСлужебный.МенеджерВнешнегоМодуля(ПрограммныйМодуль).СловарьКонтейнераВнешнегоМодуля();
		НаименованиеМодуля = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ПрограммныйМодуль, "Наименование");
		Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, ИмяИБ, Словарь.Именительный, НаименованиеМодуля);
	КонецЕсли;
	
КонецФункции

// Возвращает физические пути стандартных виртуальных каталогов.
//
// Возвращаемое значение:
//   Соответствие из КлючИЗначение:
//                         * Ключ - Строка - псевдоним виртуального каталога,
//                         * Значение - Строка - физический путь.
//
Функция СтандартныеВиртуальныеКаталоги()
	
	Результат = Новый Соответствие();
	
	Результат.Вставить("/temp", "%t/%r/%s/%p");
	Результат.Вставить("/bin", "%e");
	
	Возврат Результат;
	
КонецФункции

// Экранирует символ процент в физическом пути виртуального каталога.
//
// Параметры:
//  ИсходнаяСтрока - Строка - исходный физический путь виртуального каталога.
//
// Возвращаемое значение:
//   Строка
//
Функция ЭкранироватьСимволПроцент(Знач ИсходнаяСтрока)
	
	Возврат СтрЗаменить(ИсходнаяСтрока, "%", "%%");
	
КонецФункции

// Возвращает семафор применения запросов на использование внешних ресурсов.
//
// Возвращаемое значение:
//   РегистрСведенийКлючЗаписи.ЗапросыРазрешенийНаИспользованиеВнешнихРесурсов.
//
Функция Семафор()
	
	Ключ = Новый Структура();
	Ключ.Вставить("ИдентификаторЗапроса", Новый УникальныйИдентификатор("8e02fbd3-3f9f-4c3c-964d-7c602ad4eb38"));
	
	Возврат РегистрыСведений.ЗапросыРазрешенийНаИспользованиеВнешнихРесурсов.СоздатьКлючЗаписи(Ключ);
	
КонецФункции

// Возвращаемое значение:
//   ТаблицаЗначений:
//   * ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных
//   * ИдентификаторПрограммногоМодуля - УникальныйИдентификатор
//   * Операция - ПеречислениеСсылка.ОперацииАдминистрированияПрофилейБезопасности
//   * Имя - Строка - имя профиля безопасности
//
Функция ОперацииАдминистрирования()
	
	ОперацииАдминистрирования = Новый ТаблицаЗначений;
	ОперацииАдминистрирования.Колонки.Добавить("ТипПрограммногоМодуля", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	ОперацииАдминистрирования.Колонки.Добавить("ИдентификаторПрограммногоМодуля", Новый ОписаниеТипов("УникальныйИдентификатор"));
	ОперацииАдминистрирования.Колонки.Добавить("Операция", Новый ОписаниеТипов("ПеречислениеСсылка.ОперацииАдминистрированияПрофилейБезопасности"));
	ОперацииАдминистрирования.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка"));
	
	Возврат ОперацииАдминистрирования;
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * Замещаемые - ТаблицаЗначений - операции замещения существующих разрешений на использование внешних ресурсов:
//      ** ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//      ** ИдентификаторПрограммногоМодуля - УникальныйИдентификатор,
//      ** ТипВладельца - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//      ** ИдентификаторВладельца - УникальныйИдентификатор,
//   * Добавляемые - ТаблицаЗначений - операции добавления разрешений на использование внешних ресурсов:
//      ** ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//      ** ИдентификаторПрограммногоМодуля - УникальныйИдентификатор,
//      ** ТипВладельца - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//      ** ИдентификаторВладельца - УникальныйИдентификатор,
//      ** Тип - Строка - имя XDTO-типа, описывающего разрешения,
//      ** Разрешения - Соответствие из КлючИЗначение - описание добавляемых разрешений:
//         *** Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//         *** Значение - ОбъектXDTO - XDTO-описание добавляемого разрешения,
//      ** ДополненияРазрешений - Соответствие из КлючИЗначение - описание дополнений добавляемых разрешений:
//         *** Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//         *** Значение - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.ДополнениеРазрешения
//   * Удаляемые - ТаблицаЗначений - операции удаления разрешений на использование внешних ресурсов:
//      * ТипПрограммногоМодуля - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//      * ИдентификаторПрограммногоМодуля - УникальныйИдентификатор,
//      * ТипВладельца - СправочникСсылка.ИдентификаторыОбъектовМетаданных,
//      * ИдентификаторВладельца - УникальныйИдентификатор,
//      * Тип - Строка - имя XDTO-типа, описывающего разрешения,
//      * Разрешения - Соответствие из КлючИЗначение - описание удаляемых разрешений:
//         * Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//         * Значение - ОбъектXDTO - XDTO-описание удаляемого разрешения,
//      * ДополненияРазрешений - Соответствие из КлючИЗначение - описание дополнений удаляемых разрешений:
//         * Ключ - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.КлючРазрешения
//         * Значение - см. РегистрСведений.РазрешенияНаИспользованиеВнешнихРесурсов.ДополнениеРазрешения
//
Функция ПланПримененияЗапросов()
	
	ПланПримененияЗапросов = Новый Структура();

	ПланПримененияЗапросов.Вставить("Замещаемые", Новый ТаблицаЗначений);
	ПланПримененияЗапросов.Замещаемые.Колонки.Добавить("ТипПрограммногоМодуля", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	ПланПримененияЗапросов.Замещаемые.Колонки.Добавить("ИдентификаторПрограммногоМодуля", Новый ОписаниеТипов("УникальныйИдентификатор"));
	ПланПримененияЗапросов.Замещаемые.Колонки.Добавить("ТипВладельца", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	ПланПримененияЗапросов.Замещаемые.Колонки.Добавить("ИдентификаторВладельца", Новый ОписаниеТипов("УникальныйИдентификатор"));
	
	ПланПримененияЗапросов.Вставить("Добавляемые", Новый ТаблицаЗначений);
	ПланПримененияЗапросов.Добавляемые.Колонки.Добавить("ТипПрограммногоМодуля", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	ПланПримененияЗапросов.Добавляемые.Колонки.Добавить("ИдентификаторПрограммногоМодуля", Новый ОписаниеТипов("УникальныйИдентификатор"));
	ПланПримененияЗапросов.Добавляемые.Колонки.Добавить("ТипВладельца", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	ПланПримененияЗапросов.Добавляемые.Колонки.Добавить("ИдентификаторВладельца", Новый ОписаниеТипов("УникальныйИдентификатор"));
	ПланПримененияЗапросов.Добавляемые.Колонки.Добавить("Тип", Новый ОписаниеТипов("Строка"));
	ПланПримененияЗапросов.Добавляемые.Колонки.Добавить("Разрешения", Новый ОписаниеТипов("Соответствие"));
	ПланПримененияЗапросов.Добавляемые.Колонки.Добавить("ДополненияРазрешений", Новый ОписаниеТипов("Соответствие"));
	
	ПланПримененияЗапросов.Вставить("Удаляемые", Новый ТаблицаЗначений);
	ПланПримененияЗапросов.Удаляемые.Колонки.Добавить("ТипПрограммногоМодуля", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	ПланПримененияЗапросов.Удаляемые.Колонки.Добавить("ИдентификаторПрограммногоМодуля", Новый ОписаниеТипов("УникальныйИдентификатор"));
	ПланПримененияЗапросов.Удаляемые.Колонки.Добавить("ТипВладельца", Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	ПланПримененияЗапросов.Удаляемые.Колонки.Добавить("ИдентификаторВладельца", Новый ОписаниеТипов("УникальныйИдентификатор"));
	ПланПримененияЗапросов.Удаляемые.Колонки.Добавить("Тип", Новый ОписаниеТипов("Строка"));
	ПланПримененияЗапросов.Удаляемые.Колонки.Добавить("Разрешения", Новый ОписаниеТипов("Соответствие"));
	ПланПримененияЗапросов.Удаляемые.Колонки.Добавить("ДополненияРазрешений", Новый ОписаниеТипов("Соответствие"));
	
	Возврат ПланПримененияЗапросов;
	
КонецФункции

#КонецОбласти

#Область Инициализация

ИдентификаторыЗапросов = Новый Массив();

ПланПримененияЗапросов = ПланПримененияЗапросов();

ОперацииАдминистрирования = ОперацииАдминистрирования();

ОчисткаРазрешенийПередПрименением = Ложь;

#КонецОбласти

#Иначе
ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли

Связанные материалы