views:

920

answers:

4

Hi,

How can I check and make sure that a class uses my own custom security attribute? I know that I can use reflection to get normal attributes, but if the custom attribute is based on a security attribute as shown below reflection doesn't show it. Is there any way to check that?

Why I would need this is to make sure that a plugin that is loaded to a cloud based system must use security attribute so the class that get's loaded cannot access any restricted files and so on.

Here is the custom security class I'm using:

public class PluginSection : CodeAccessSecurityAttribute
{
    public PluginSection(SecurityAction action)
        : base(action)
    {
    }

    public override IPermission CreatePermission()
    {
        // WebSites.GetInstance().LocalBaseDir returns the base directory where the class has accesss to login
        return new FileIOPermission(FileIOPermissionAccess.Write, WebSites.GetInstance().LocalBaseDir);
    }

}

I must use a class based on CodeAccessSecurityAttribute so that the FileIOPermission would work.

Also if there is another way to restrict the access of the plugin being loaded I could use that too.

+1  A: 

Reflection seems to work fine for me:

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

public class PluginSection : CodeAccessSecurityAttribute
{
    public PluginSection(SecurityAction action)
        : base(action)
    {
    }

    public override IPermission CreatePermission()
    {
        // Removed for demo purposes
        return null;
    }

}

class NotApplied {}

[PluginSection(SecurityAction.Demand)]
class Applied{}

class Test
{
    static void Main()
    {
        Console.WriteLine(IsPluginSection(typeof(Applied)));
        Console.WriteLine(IsPluginSection(typeof(NotApplied)));
    }

    static bool IsPluginSection(Type type)
    {
        return type.IsDefined(typeof(PluginSection), false)
    }
}
Jon Skeet
Interesting that GetCustomAttributes throws a TypeLoadException though. Presumably you're not expected to have any extra data on a CAS attribute that you might want to access?
Thom
It still doesn't seem to work. I use it on a control that is loaded with Page.LoadControl method. Could that be the reason. The plugin it self is a usercontrol on a webpage.
Gabfine
Hmm... GetCustomAttributes() doesn't give me a TypeLoadException. What's the exact exception message? Is this attribute declared in an assembly which is failing to load?
Jon Skeet
I don't get any error. It loads just perfectly but it just doesn't see the security attribute. It might be something to do about the way I load the control. I have a base class which I use to load the control, because I have no way of knowing what is the name of class user has created for the plugin. Because of this even a normal attribute cannot be seen if not used type.IsDefined(typeof(PluginSection, true) method with the true flag for inheritance. So I can see a normal attribute but the CAS attribute is never shown. I could ignore this if I could get CAS working from a inherited base class.
Gabfine
Where is PluginSection defined? Is it in more than one assembly? That would certainly cause problems. I would go back to GetCustomAttribute and investigate why that wasn't working - I think once you've solved that, it'll fall into place.
Jon Skeet
PluginSection is in the same namespace as is the rest of the code. I even iterated manually trough all the attributes of the class and it just isn't there. The actual place of where PluginSection is inside App_code directory.
Gabfine
How are you loading the type? I've found `BuildManager.GetType()` is the more reliable than `Assembly.GetType` for App_Code.
devstuff
A: 

I don't think it is necessary to use reflection to check, if an attribute is assigned to the plugin. Permissions is based on scope, so they will propagate downwards in your call hierarchy.

If it is possible with your current design, you should just decorate the method that executes your code with the custom attribute:

[SomePermission(SecurityAction.PermitOnly)]
public void PluginExecutor(Plugin plugin)
{
 plugin.Something();
}

Something will only be given the same rights as your PluginExecutor method. Therefore you can assign whatever permissions at this point, without worrying if the plugin uses them - and without having to rely on reflection.

troethom
A: 

I don't have an answer, but if it gives people more information to reproduce the issue:

[TestFixture]
public class SecurityExperiments
{
    [Test]
    public void ShouldGetCustomSecurityAttributes()
    {
        Assert.That(typeof (Applied).GetCustomAttributes(true),
                    Has.Some.InstanceOf<PluginSection>());
    }

    public class PluginSection : CodeAccessSecurityAttribute
    {
        public PluginSection(SecurityAction action)
            : base(action)
        {
        }

        public override IPermission CreatePermission()
        {
            // Removed for demo purposes
            return null;
        }

    }

    [PluginSection(SecurityAction.Demand)]
    class Applied { }
}

Causes (for my test project, at least):

System.TypeLoadException: Could not load type 'PluginSection' from assembly 'StackOverflow, Version=1.0.0.0, Culture=neutral'.
at System.Reflection.PseudoCustomAttribute._GetSecurityAttributes(Void* module, Int32 token, Object[]& securityAttributes)
at System.Reflection.PseudoCustomAttribute.GetCustomAttributes(RuntimeType type, Type caType, Boolean includeSecCa, ref Int32 count)
at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeType type, RuntimeType caType, Boolean inherit)
at System.RuntimeType.GetCustomAttributes(Boolean inherit)
at StackOverflow.SecurityExperiments.ShouldGetCustomSecurityAttributes() in SecurityExperiments.cs: line 13
Thom