Интернет-журнал "Домашняя лаборатория", 2007 №6 - Усманов
Шрифт:
Интервал:
Закладка:
Для нашей задачи контроля доступа к методу в зависимости от параметров можно использовать следующие методы данного интерфейса:
• IsSecurity Enabled возвращает как выходной параметр логическое значение: TRUE, если основанная на ролях система безопасности задействована, и FALSE в противном случае.
• Если система безопасности задействована, то метод IsCalleIinRole используется для проверки принадлежности клиента, вызвавшего метод, заданной роли. Входной параметр задает строку с ролью, выходной возвращает истину или ложь в зависимости от принадлежности клиента специфицированной роли. В зависимости от этого значения можно продолжить выполнение основной логики метода, либо прервать его выполнение с соответствующим кодом ошибки.
Вообще, интерфейс ISecurityCallContext позволяет получить следующую информацию об исполняемом вызове:
• Длина цепи вызовов
Как уже отмечалось ранее, в СОМ каждый вызов получает уникальный идентификатор, и все последующие вызовы, сделанные ради выполнения данного вызова, получают тот же идентификатор. Это позволяет отслеживать цепочки вызовов.
• Минимальный уровень аутентификации, использующийся в данной цепи вызовов
• Идентификационная информация для всех клиентов, сделавших включенные в данную цепь вызовы:
♦ SID
♦ Имя
♦ Сервис аутентификации (например, Kerberos)
♦ Уровни аутентификации и имперсонализации
• Идентификационные данные клиента, сделавшего первый вызов в цепи
• Идентификационные данные клиента, сделавшего последний вызов в цепи
Теперь рассмотрим, как на стороне сервера решается вопрос имперсонализации клиента и делегирование его прав при удаленном вызове.
С помощью функции CoGetCallContext можно получить также указатель на интерфейс IServerSecurity. Именно этот интерфейс предоставляет метод без параметров ImpersonateClient, который при вызове в потоке, выполняющем вызов клиента, имперсонирует этого клиента, приписывая потоку маркер доступа с аутентификационными данными этого клиента. Вызов другого метода без параметров этого же интерфейса — RevertToSeif позволяет вернуть потоку исходный маркер доступа.
Как уже отмечалось ранее, если уровень аутентификации клиента был установлен не ниже чем в Impersonate, то после имперсонализации клиента сервер получает доступ (на время выполнения этого метода или до вызова RevertToSelf) ко всем локальным ресурсам от имени клиента пользуясь всеми его правами. Однако, если уровень имперсонализации установлен в Delegate, можно было бы ожидать, что данный поток получает право делать от лица клиента и удаленные вызовы. Однако, это не так. Ради совместимости с предыдущими версиями (СОМ под Windows NT), делегирование будет иметь место только после дополнительной настройки. Именно, после имперсонализации клиента С поток сервера S должен выполнить cloakig, т. е. скрыть свою сущность от вызываемого сервера Q под маской имперсонированного клиента С. Один из способов состоит в задании специального флага для прокси, который поток сервера S получил, выполнив вызов сервера Q. Для этого можно получить текущие установки уровня безопасности для данного прокси используя IClientSecurity::GetBlanket, добавить один из следующих флагов:
• EOAC_STATIC_CLOAKING
• EOAC_DYNAMIC_CLOAKING
и задать новые установки для прокси с помощью IClientSecurity::SetBlanket.
Упомянутые выше флаги имеют следующий смысл. При задании первого флага все последующие вызовы через этот прокси будут делаться от лица того клиента, который был имперсонирован до вызова SetBlanket. Если был использован второй флаг, то прокси делает все проходящие через него вызовы от лица клиента, данные которого записаны в текущий маркер доступа процесса. Это означает, что, например, чередуя вызовы
IServerSecurity::ImpersonateClient и IServerSecurity::RevertToSeif, текущий поток будет делать удаленные вызовы то от имени клиента С, то от имени сервера S.
Асинхронные компоненты (Queued Components)
Вначале несколько слов о терминологии. Термин Queued Components сложно перевести на русский язык, сохраняя стоящий за ним (в рамках СОМ+) смысл. Дословный перевод "организованные в очередь компоненты", который иногда используется в русскоязычной литературе, заставляет предполагать, что имеется в виду некоторая очередь различных компонентов, тогда как все совершенно иначе — имеется очередь вызовов к одному компоненту. В данном курсе выбран термин "асинхронные компоненты", который должен подчеркивать возможность коммуникации клиента и сервера, функционирующих в различные, непересекающиеся интервалы времени.
Здесь же необходимо отметить, что в СОМ+ появилась новая возможность объявить некоторый интерфейс как асинхронный. Асинхронные интерфейсы и асинхронные компоненты (Queued Components) — это разные технологии. Использование асинхронного интерфейса позволяет клиенту сделать вызов некоторого метода асинхронного интерфейса сервера и сразу же заняться чем-нибудь еще (при использовании обычного синхронного интерфейса клиент блокируется до получения ответа от сервера). Но при этом и клиент и сервер должны функционировать одновременно. В случае вызова, направленного асинхронному компоненту, клиент также не блокируется, как и при вызове асинхронного интерфейса. И, кроме того, клиент может делать вызов сервера в тот момент, когда сервер еще не запущен.
Теперь перейдем к более подробному рассмотрению именно технологии асинхронных компонент.
До сих пор мы рассматривали только синхронную коммуникацию клиента и сервера — клиент делает вызов и ждет ответа сервера. Только после получения ответа от сервера продолжается выполнение клиента. Иначе такая коммуникация называется коммуникацией в режиме реального времени.
В случае вызова асинхронного компонента
• Клиент может не дожидаться ответа сервера и продолжать свою работу.
• Вызовы от клиента к серверу могут накапливаться на стороне клиента и отправляться серверу все за один раз.
• Клиент может вызывать метод сервера даже в тот момент, когда сервер еще не запущен.
Рассмотрим ситуации, когда предпочтительно использовать асинхронные компоненты:
• В рамках бизнес-логики данного приложения в одних случаях коммуникация клиент/сервер должна выполняться в режиме реального времени, а в других допустима асинхронная коммуникация.
Чаще всего в литературе приводится следующий пример. Клерк принимает заказы от клиентов по телефону. Коммуникация клерка и приложения, обеспечивающего прием заказа, должна выполняться в режиме реального времени. Например, может оказаться, что нужного товара нет на складе, и клерк может попытаться уговорить клиента купить другой товар. Однако, коммуникация приложения, принявшего заказ, и приложения, обеспечивающего доставку товара покупателю, может выполняться не в режиме реального времени, а, например, ночью, когда спадет поток заказов по телефону.
• Возникает проблема масштабируемости приложения
Предположим, что в рамках рассмотренного в предыдущем пункте примера, для оформления каждого нового заказа серверное приложения формирует объект, представляющий покупателя, в который и заносятся такие данные как имя покупателя, название товара, его стоимость, форма оплаты, адрес покупателя и т. п. В течении всего времени оформления заказа для некоторого покупателя соответствующий ему объект живет на сервере и связывает определенные ресурсы (например, соединения с базами данных). При большом числе одновременно оформляемых заказов, ресурсы, необходимые для поддержания всех представляющих покупателей объектов, могут оказаться недоступными.
Масштабируемое решение связано с использованием асинхронных компонент. Во время оформления заказа данные о заказе накапливаются в клиентском приложении и только потом, все вместе, направляются в только что созданный объект, представляющий покупателя, который обрабатывает все пришедшие запросы и удаляется из памяти.
• Клиентское приложение работает на устройстве, не подключенном к сети
Клерк из рассматриваемого примера может