Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Custom SecurityPermission is not loaded?

I created a CodeAccessSecurityAttribute implementation, witch use stack information to find the target class name, but in some classes the PrincipalPermition is not created, the system uses the previews one instead. What did I miss?

[ComVisible(true)]
[AttributeUsageAttribute(AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = true, Inherited = false)] 
public sealed class MyPrincipalPermissionAttribute : CodeAccessSecurityAttribute
{
    public MyPrincipalPermissionAttribute(SecurityAction action) : base(action) { }

    public override IPermission CreatePermission()
    {
        if (Unrestricted)
            return new PrincipalPermission(PermissionState.Unrestricted);
        var stackTrace = new StackTrace();

        var fullnameArray = new List<String>();
        foreach (var frame in stackTrace.GetFrames())
        {
            try
            {
                var method = frame.GetMethod();
                if (method != null && method.ReflectedType.IsSubclassOf(typeof (BaseClass)))
                    fullnameArray.Add(method.ReflectedType.FullName);
            } catch {}
        }

        if (fullnameArray.Count() > 0)
            return new PrincipalPermission(null, fullnameArray[0], true);

        return new PrincipalPermission(PermissionState.Unrestricted);
    }
}

And the usage

public class MyClassCalledFirstWork: BaseClass
{
    [MyPrincipalPermission(SecurityAction.Demand)]
    public override void DoSomething()
    {
        return;
    }
}

public class MyClassCalledSecondDontWork: BaseClass
{
    [MyPrincipalPermission(SecurityAction.Demand)]
    public override void DoSomething()
    {
        return;
    }
}
like image 378
maiconmm Avatar asked May 13 '11 12:05

maiconmm


1 Answers

This is from documentation for SecurityAttribute.CreatePermission ():

"CreatePermission method creates a permission object that can then be serialized into binary form and persistently stored along with the SecurityAction in an assembly's metadata."

"At compile time, attributes convert security declarations to a serialized form in metadata. Declarative security data in metadata is created from the permission that this method returns that corresponds to this attribute."

It looks like there can be only one permission object (of some type) corresponding with custom CodeAccessSecurityAttribute stored for a specific SecurityAction. When you check the IL for DoSomething methods you can see that they contain identical permission demands with role defined during the first CreatePermission call.

.method public hidebysig virtual instance void 
        DoSomething() cil managed
{
    .permissionset demand
             = {class 'CustomSecurityPermission.Program+MyPrincipalPermissionAttribute, CustomSecurityPermission, Version=1.0.0.0, Culture=neutral' = {}}
    ...
} // end of method MyClassCalledSecondDontWork::DoSomething

.method public hidebysig virtual instance void 
        DoSomething() cil managed
{
    .permissionset demand
             = {class 'CustomSecurityPermission.Program+MyPrincipalPermissionAttribute, CustomSecurityPermission, Version=1.0.0.0, Culture=neutral' = {}}
    ...
} // end of method MyClassCalledFirstWork::DoSomething

An answer for your second question from comments is:
Instead of using declarative CAS I would use imperative:

public sealed class Security
{
    public static IPermission CreatePermission()
    {
        var stackTrace = new StackTrace();

        var fullnameArray = new List<String>();
        foreach (var frame in stackTrace.GetFrames())
        {
            try
            {
                var method = frame.GetMethod();
                if (method != null && method.ReflectedType.IsSubclassOf(typeof(BaseClass)))
                    fullnameArray.Add(method.ReflectedType.FullName);
            }
            catch { }
        }
        if (fullnameArray.Count() > 0)
        {
            return new PrincipalPermission(null, fullnameArray[0]);
        }
        return new PrincipalPermission(PermissionState.Unrestricted);
    }
}

public class MyClassCalledFirstWork : BaseClass
{
    public override void DoSomething()
    {
        Security.CreatePermission().Demand();
        return;
    }
}

public class MyClassCalledSecondDontWork : BaseClass
{
    public override void DoSomething()
    {
        Security.CreatePermission().Demand();
        return;
    }
}
like image 66
Maciej Rogoziński Avatar answered Oct 05 '22 07:10

Maciej Rogoziński