C#: CallerPermission
От: SiAVoL Россия  
Дата: 30.08.04 18:18
Оценка: 164 (13)
Навеяно этим — Разделение доступа
Автор: Курилка
Дата: 18.08.04


Если вкратце, то это реализация permission, позволяющего указывать какие классы могут совершать вызовы методов. Т.е. можно написать так
    [CallerPermission(SecurityAction.LinkDemand, 
         FriendClassNames = "Protected.Secured;testCAS.Class1")]
    public interface IDoSmth
    {
        void DoSmth();
    }

теперь воспользоваться интерфейсом IDoSmth можно будет только из классов Protected.Secured или testCAS.Class1. В остальных случаях будет сгенерировано SecurityException. Как можно видеть из примера поддерживается декларативная запись. Ну и императивная запись естественно тоже поддерживается.
Список привелигированных классов указывается через ;

Для использования нужно сборке с CallerPermission дать строгое имя и положить ее в GAC

А теперь собственно код:

CallerPermission.cs

using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Security;
using System.Security.Permissions;

// вот здесь собственно и нужно указать путь к файлу с ключем
// сгенерировать ключ можно утилитой sn 
// например так sn -k SomeKey.snk
[assembly: AssemblyKeyFile("..\\..\\..\\key.snk")]
[assembly : AllowPartiallyTrustedCallers()]

namespace SiAVoL.Permissions
{
    public sealed class CallerPermission : IPermission
    {
        private string _FriendClassNames = "";
        public string FriendClassNames
        {
            get { return _FriendClassNames; }
        }

        private PermissionState _State;

        public CallerPermission(string friendClassNames)
        {
            _FriendClassNames = friendClassNames;
        }

        public CallerPermission(PermissionState state)
        {
            _State = state;
        }

        public IPermission Copy()
        {
            return new CallerPermission(_FriendClassNames);
        }

        private void VerifyType(IPermission target, bool isNullOk)
        {
            if (null == target)
            {
                if (true == isNullOk)
                    return;
                else
                    throw new ArgumentException("Target is not DoSthPermission [it is null]");
            }
            if (this.GetType() != target.GetType())
                throw new ArgumentException("Target is not DoSthPermission");
        }

        public IPermission Intersect(IPermission target)
        {
            return target;
        }

        public IPermission Union(IPermission target)
        {
            VerifyType(target, true);
            CallerPermission perm = (CallerPermission)target;

            return new CallerPermission(perm.FriendClassNames
                + ";" + this.FriendClassNames);
        }

        public bool IsSubsetOf(IPermission Target)
        {
            VerifyType(Target, true);
            if (null == Target)
                return false;
            return false;
        }

        public void Demand()
        {
            ArrayList names = new ArrayList(FriendClassNames.Split(';')); 
            StackTrace trace = new StackTrace();
            for (int i = 0; i < trace.FrameCount; i++)
            {
                MethodBase method = trace.GetFrame(i).GetMethod();
                string className = method.DeclaringType.FullName;
                if (names.Contains(className))
                    return;
            }
            throw new SecurityException("Данному классу запрещено совершать вызов");
        }

        public SecurityElement ToXml()
        {
            SecurityElement element = new SecurityElement("IPermission");

            String name = typeof (CallerPermission).AssemblyQualifiedName;
            element.AddAttribute("class", name);
            element.AddAttribute("version", "1.0");
            element.AddAttribute("FriendClassNames", FriendClassNames);

            return element;
        }


        public void FromXml(SecurityElement e)
        {
            String name = e.Attribute("class");
            if (name != typeof (CallerPermission).AssemblyQualifiedName)
                throw new ArgumentException("Wrong SecurityElement");

            String version = e.Attribute("version");
            if (version != "1.0")
                throw new ArgumentException("Version " + version + " does not match current version of the permission");

            String friend = e.Attribute("FriendClassNames");

            if (null != friend)
                _FriendClassNames = friend;
            else
                _FriendClassNames = "";
        }
    }
}


CallerPermissionAttribute.cs

using System;
using System.Security;
using System.Security.Permissions;


namespace SiAVoL.Permissions
{
    [AttributeUsage(
         AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Interface,
         AllowMultiple = true,
         Inherited = false )] 
    public sealed class CallerPermissionAttribute : CodeAccessSecurityAttribute
    {
        public CallerPermissionAttribute(SecurityAction action)
            : base(action)
        {
        }

        public override IPermission CreatePermission()
        {
            return new CallerPermission(FriendClassNames);
        }

        private string _FriendClassNames;
        public string FriendClassNames
        {
            get { return _FriendClassNames; }
            set { _FriendClassNames = value; }
        }
    }
}



PS: класс написан из чистого любопытства и реализация не совсем тщательна, например функции IsSubsetOf, Intersect не написаны (ничего сложного там нет, просто пока лень ). В общем as is и если что, то я не виноват
PPS: пользуясь случаем хочется передать привет бабушке
PPPS: и еще... RSDN рулез!
PPPPS: если у вас не работает, значит скорее всего вы не положили сборку в ГАК или не подписали ее.

... << RSDN@Home 1.1.4 @@release >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.