До сих пор рассматривались ситуации, основанные на наследовании permissions on stack downstream. The mechanism that enables any callee on the stack to narrow its permissioms was described. In fact, however, there is a situation, when it is impossible to consistently inherit permissions downsteam. For example, calling any native API will ultimately require Unmanaged permission, но нелепо требовать этого от всех components in current call, but only most trusted libraries. To hahdle this condition, CLR provides CodeAccessSecurity class with Assert() method. By calling Assert() the caller sets the watermark on the frame upon witch the security permissions are not evaluated. This means, in particular, that the caller may not nave the required permissions, but sequencial Demand() on the stack will succeed. To perform Assert() the caller itself must pass the security validation for particular permission. One grants such a permission to specific code in policy.
Ну, вот. Если с Assert'ом разобрались, то пережде чем перейти к практике, осталось привести табличку наиболее часто используемых build-in permissions из CLR 1.1.
В левой колонке - имя класса permission, в правой - контролируемые операции.
SecurityPermission |
Execution, UnmanagedCode, Assertion etc. |
FileIOPermission |
Read, Write, Append, Path Disc. |
EventLogPermission |
Browse, Audit, Instrument |
RegistryPermision |
Read, Write, Create |
SqlClientPermission |
|
Стоит ли говорить, это все классы, упомянытые здесь в левой колонке (да с ними еще с десяток, используемых реже) - все наследуют от рассмотернной ниже жемчужины - CodeAccessPermission?
Теперь простой пример (по пути к Feeder'ам): kод загружает assembly, с намерениями вызвать некоторый метод. Код разрешает вызов метода только если соответсвующий policy опеределяет для загруженного assembly, как минимум, execute permission. Сам код выглядит так:
string strAssemblyFile = "file://" + strCodeBase;
Assembly fAsm = Assembly.LoadFrom(strAssemblyFile);
PolicyLevel polLevel = SecurityManager.LoadPolicyLevelFromFile(@"xxx.config", PolicyLevelType.AppDomain);
PolicyStatement statement = polLevel.Resolve(evidence);
PermissionSet ps = statement.PermissionSet;
IPermission perm = new SecurityPermission(SecurityPermissionFlag.Execution);
PermissionSet requiredPS = new PermissionSet(PermissionState.None);
requiredPS.AddPermission(perm);
bool bRes = requiredPS.IsSubsetOf(ps);
if( !bRes )
{
Console.WriteLine("Assmebly {0} has not granted the execution permission", strCodeBase);
return;
}
Допустим, сам policy имеет, для просты дела, такую top CodeGroup:
<CodeGroup
class="FirstMatchCodeGroup"
version="1"
PermissionSetName="Nothing">
<IMembershipCondition
class="AllMembershipCondition"
version="1"
/>
<CodeGroup class="UnionCodeGroup"
version="1"
PermissionSetName="Execution" >
<IMembershipCondition class="UrlMembershipCondition"
version="1"
Url="codebase"/>
</CodeGroup>
</CodeGroup>
Соответствующий PermissionSet (named "Execution") выглядит так :
<PermissionSet
class="NamedPermissionSet"
version="1"
Name="Execution">
<IPermission
class="SecurityPermission"
version="1"
Flags="Execution"
/>
</PermissionSet>
Если запустить приведенный код через такой policy, то загруженный assembly пройдет security check. Из-за второго, вложенного элемента CodeGroup, кот. связывает его Url с SecurityPermission.ExecutionFlag. Разумеется, codebase, кот. используется в LoadFrom() (на его основе, как следует из поста 2, создается Evidence), должен быть таким же, как и в UrlMembershipCondition из этого CodeGroup.