Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Базовые технологии платформы .NET.docx
Скачиваний:
15
Добавлен:
02.11.2018
Размер:
626.37 Кб
Скачать

2.31. Процессы и домены

Любому запущенному приложению в операционной системе соответствует некий процесс. Процесс образует границы приложения, выделяя для приложения изолированное адресное пространство и поддерживая один или несколько потоков выполнения. Для работы с процессами в платформе .NET имеется класс System.Diagnostics.Process. Используя свойства этого класса можно получить информацию о текущем процессе, а также всех процессах системы.

Process current = Process.GetCurrentProcess();

foreach(Process p in Process.GetProcesses())

{

Console.WriteLine("{0} {1} {2}",

p.Id, p.ProcessName, p.StartTime);

}

Класс Process позволяет управлять процессами (при наличии соответствующих привилегий). В следующем примере запускается приложение «Блокнот», которое завершается через 5 секунд.

Process p = Process.Start("notepad.exe");

Thread.Sleep(5000);

p.Kill();

Платформа .NET вводит дополнительный уровень изоляции кода, называемый доменом приложения. Домены существуют внутри процессов и содержат загруженные сборки. Любой процесс запускает при старте домен по умолчанию, однако домены могут создаваться и уничтожаться в ходе работы в рамках процесса. Домены обеспечивают приемлемый уровень изоляции кода, но их создание менее затратно, чем создание отдельных процессов. Кроме того, домен можно уничтожить, не нарушая целостность работы всего процесса.

Домены приложений инкапсулированы в объектах класса System.AppDomain. Статическое свойство CurrentDomain позволяет получить информацию о текущем домене, а статические методы наподобие CreateDomain() ‑ создать новый домен в рамках текущего процесса. После создания домена в него можно программно загрузить сборки, используя экземплярный метод. Выгрузить отдельные сборки из домена нельзя. Можно только выгрузить весь домен:

AppDomain newDomain = AppDomain.CreateDomain("nd");

newDomain.Load("assemblyName");

AppDomain.Unload(newDomain);

Домены содержат методы для создания экземпляров объектов требуемых типов (например, CreateInstance()). Однако доступ к созданным экземплярам нетривиален – фактически, это межпрограммное взаимодействия, для которого существую специальные технологии.

2.32. Безопасность

В параграфе обсуждаются следующие аспекты безопасности в .NET: разрешения на доступ, изолированные хранилища, криптография.

Разрешения на доступ

Рассмотрим вопросы, связанные с разрешением на доступ к ресурсам. Начнем с анализа терминологии. Под пользователем (user) будем понимать физическое лицо или систему. Личность (identity) – это информация о пользователе, связанная с системой безопасности. Принципал (principal) – личность, рассматриваемая с точки зрения определенной задачи обеспечения безопасности.

В платформе .NET определён интерфейс IIdentity, используемый классами описания личности:

public interface IIdentity

{

string AuthenticationType { get; }

bool IsAuthenticated { get; }

string Name { get; }

}

Свойство Name – это имя пользователя. Свойство IsAuthenticated используется для различения аутентифицированных и анонимных пользователей. Свойство AuthenticationType позволит выяснить тип аутентификации.

Для описания принципалов существуют два основных класса: WindowsPrincipal и GenericPrincipal. Первый класс представляет принципала с точки зрения операционной системы, а второй класс – это база для реализации собственных принципалов. Оба класса реализуют интерфейс IPrincipal:

public interface IPrincipal

{

IIdentity Identity { get; }

bool IsInRole(string role);

}

Операционная система содержит встроенные механизмы обеспечения безопасности доступа к ресурсам (файлам, каталогам, процессам). При запуске любого процесса система помещает в контекст потока выполнения специальный маркер безопасности, описывающий личность пользователя, выполнившего запуск. Маркер безопасности копируется во все потоки, порождённые процессом. Если код потока выполняет доступ к защищенному ресурсу, система извлекает маркер безопасности и проверяет права пользователя на доступ.

Механизмы безопасности .NET строятся поверх соответствующих механизмов операционной системы. Как и операционная система, CLR позволяет связать с потоком выполнения определенного пользователя. Принципал этого пользователя будет доступен через свойство Thread.CurrentPrincipal. Однако значение этого свойства не обязательно совпадает с принципалом операционной системы. Например, в консольном приложении Thread.CurrentPrincipal по умолчанию вообще не задан, хотя, безусловно, маркер безопасности и соответствующий принципал ОС в нём присутствует. В следующем примере кода демонстрируется анализ данных личности и принципала. Чтобы связать маркер безопасности операционной системы с принципалом CLR, используется специальный приём.

// получаем данные о пользователе Windows

WindowsIdentity winUser = WindowsIdentity.GetCurrent();

Console.WriteLine(winUser.Name);

Console.WriteLine(winUser.IsGuest);

// изменяем политику безопасности по умолчанию,

// чтобы связать пользователя Windows и Thread.CurrentPrincipal

AppDomain.CurrentDomain.SetPrincipalPolicy(

PrincipalPolicy.WindowsPrincipal);

// получаем даннные из Thread.CurrentPrincipal

IPrincipal pr = Thread.CurrentPrincipal;

Console.WriteLine(pr.Identity.Name);

Обладая информацией о пользователе, можно решать, есть ли у этого пользователя право производить заданные действия. При этом удобным оказывается механизм ролей, связывающий пользователя с определённой группой (или группами)1.

// выполняем приведение типов, чтобы использовать

// перегруженный вариант IsInRole()

var pr = (WindowsPrincipal) Thread.CurrentPrincipal;

Console.WriteLine(pr.IsInRole(WindowsBuiltInRole.Administrator) ?

"Действия разрешены" : "Действия запрещены");

В примере вместо работы со строковым именем роли использовалось перечисление WindowsBuiltInRole, описывающее стандартные роли Windows.

В платформе .NET можно контролировать не только доступ к внешним ресурсам, но и использовать ограничения на доступ к коду. Соответствующая подсистема носит название Code Access Security (CAS). Права доступа к коду описываются разрешениями, представленными как объекты классов, производных от CodeAccessPermission. Наиболее важным методом разрешения является метод Demand(). Он проверяет стек вызова на наличие прав выполнения кода и в случае их отсутствия генерирует исключение SecurityException. Пусть, например, создаётся метод, обрабатывающий с файлы, и необходимо убедится, что у кода, вызывающего этот метод, есть права на работу с файлами. В этом случае следует воспользоваться классом FileIOPermission и разместить в начале метода такой код:

new FileIOPermission(PermissionState.None).Demand();

Так как подобный код зачастую располагаются в начале тела метода, для всех Permission–классов существуют одноименные атрибуты, применяемые к методам и позволяющие настроить разрешения декларативно1.

[FileIOPermission(SecurityAction.Demand)]

private void ActionWithFiles() { . . . }

Объекты разрешения могут комбинироваться в наборы, с которыми можно работать, как с множествами.

Каким образом вызывающий код получает некие разрешения? Все разрешения, которые имеет код, образуют политику безопасности. Политика безопасности для сборки определяет средой выполнения по имени сборки, месту, откуда загружена сборка, и прочим параметрам. При необходимости политика безопасности может быть задана как часть конфигурации сборки.