В прошлый раз мы получили PermissionSet . Теперь разберемся, как его использовать.
Во-первых, PermissionSet наследует ICollection, каждый из элементов которой, как минимум, имплементирует IPermission. Об этом интерфейсе и пойдет речь ниже. Сам PermissionSet определяет т.наз. "операции множеств" (set operations), но не над отдельными элементами из своей коллекции, а над самими PermissionSets, позволяя об'единять и разбивать их на новые коллекции. Таким образом, каждая коллекция PermissionSet состоит из элементов, поддерживающих IPermission и имеет методы - Union(), Intersect(), IsSubsetOf() -, позволяющие строить новые множества. Прежде, чем мы займемся IPermission, обратим внимание на то, это среди поддерживаемых в System.Collections namespace, нет похожей на ISet, и поэтому можно считать, что определение подобных операций для множеств, представляется логичным компромиссом для архитектуры CLR 1.1.
Ввиду отсутствия ISet, тот же design применяется и к IPermission, позволяя об'единять и пересекать их между собой. В этом посте речь не идет о collections design в CLR, но я бы хотел подчеркнуть, что имплементация этих методов is type-specific, т.е. сам имплементор решает, с кем ему пересекаться и об'единяться. Например, будет ошибкой послать FileIOPermission в WebPermission.Intersect().
Помимо методов для множественных операций, IPermission имеет метод Demand(), ради которого, собственно, он и задумывался. Самое простое использование Demand() состоит в следующем : ваш код желает требовать от callers соответствующих permissions. Это желание можно выразить так:
a). Построим те permissions, кот. потом будем требовать
FileIOPermissionAccess readAccess = FileIOPermissionAccess.Read;
IPermission p = new FileIOPermission(readAccess, @"c:okey");
b). Затребуем от всех callers выше по стеку иметь такой же permission из их PermissionsSets или где там они их будут брать.
p.Demand();
The Demand() method triggers a stack walk in which the permissions of every method are inspected. The CLR calculates the permissions of each method by running the evidence from the method's assembly through the security policy - see my previous post. If
at least one method on the stack does not have the permission being demanded, then the Demand() method will throw a SecurityException. If, however, all the methods on the stack do have the permission being demanded, then the Demand() method will indeicate this by not throwing the exception.
Всякий раз, когда дело доходит до stack, я вспоминаю
обложку "Programming Windows Security" by
Keith Brown,
но и сегодня будем только облизываться - всему свое время. (Кстати, для не посетивших PDC 2003 в LA -
это must все от того же Keith Brown).
Так вот Demand(), как правило, инициализирует StackWalk. Поскольку это интерфейсный метод, то, в принцине, каждый имплементор сам решает, where you want to walk. Большинство классов CLR отправляются именно на stack. Вот, например, как может выглядеть GetHostByName() implementation (потом заменю на что-нибудь более интересное из ADSI):
public static IPHostEntry GetHostByName(string host)
{
// enforce policy through StackWalk
DnsPermission perm = new DnsPermission(PermissionState.Unrestricted);
perm.Demand();
// if we get here, all callers on the stack have DnsPermission
// ... perform the actual work
}
Это пример т.наз.
imperative security demand. Тот же пример может быть переписан и так:
[DnsPermission(SecurityAction.Demand, Unrestricted=true)]
public static IPHostEntry GetHostByName(string host)
{
// if we get here, all callers on the stack have DnsPermission
// ... perform the actual work
}
Этот стиль называется
declarative. Главное его преимущество в том, что с его помощью можно узнать о security requiremenets методов из metadata, не запуская код.
Самому же проходу по stack, не осталось почти никакой работы, кроме как вызвать ps.IsSubsetOf() у проверяемого permission для всех методов, разузнав их PermissionSets из соответствующего assembly через его evidence - см. пред.post.
Вот так о одном месте сходятся design of permission's set operations ( IsSubsetOf() ), design of evidence ( получение Assembly.Evidence ), и наконец, Demand() enforcement.
Не спуская глаз с этой жемчужины CLR, нужно еще и вспомнить о классе CodeAccessPermission уже хотя-бы по той причине, что именно в нем эта жемчужина и лежит. А именно, этот класс реализует IPermission и еще довабляет к нему виртуальные методы Deny(), PermitOnly(), Assert() и группу RevertXXX(). Относительно PermitOnly() - его предназначение в том, чтобы дать возможность
Читать далее...