Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is ClaimsPrincipalPermissionAttribute sealed, and is there an alternative?

I'm implementing claims based security in my .net 4.5 application. Lots of hoops to jump through, but it is basically working.

The only part I don't like is that I can't create my own attributes. ClaimsPrincipalPermissionAttribute is sealed. Why?

I'm always marking throughout my application such as:

[ClaimsPrincipalPermission(SecurityAction.Demand, Resource = "Foo", Operation = "Bar")]

And since I want my resource and operation strings to not get misspelled and be easily refactorable, I have created classes so I can do this:

[ClaimsPrincipalPermission(SecurityAction.Demand, Resource = Resources.Foo, Operation = Operations.Foo.Bar)]

(Note that since different resources may have different operations, the operations themselves are subclassed by resource.)

This all works fine and dandy, but it's a hell of a lot to type or copy/paste every time. I'd rather do something like:

[DemandPermission(Resources.Foo, Operations.Foo.Bar)]

I could create this attribute, but I would need to inherit from ClaimsPrincipalPermissionAttribute, which I can't because it's sealed. :(

Is there some other way to approach this? Perhaps I don't need to inherit, but can I register my own attribute type somehow so it works in all the same places?

like image 812
Matt Johnson-Pint Avatar asked Dec 20 '22 17:12

Matt Johnson-Pint


1 Answers

ClaimsPrincipalPermissionAttribute derives from CodeAccessSecurityAttribute. It does almost nothing except implement CreatePermission() returning a new ClaimsPrincipalPermission based on the value of Resource and Operation that you pass in.

You could implement a new class deriving from CodeAccessSecurityAttribute (this is not sealed) that does what you want.

Using JustDecompile, you can see that the code in ClaimsPrincipalPermissionAttribute is simple. You could make your own attribute like this:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]
public sealed class DemandPermissionAttribute : CodeAccessSecurityAttribute
{
    public Operations Operation { get; set; }
    public Resources Resource { get; set; }

    public DemandPermissionAttribute(SecurityAction action = SecurityAction.Demand)
        : base(action)
    {
    }

    public override IPermission CreatePermission()
    {
        return new ClaimsPrincipalPermission(this.Resource.ToString(), this.Operation.ToString());
    }
}

One important thing to note on this is that you must define your custom attribute in a separate assembly from the one that is referencing it, otherwise the framework will throw a TypeLoadException as described here

http://msdn.microsoft.com/en-us/library/vstudio/yaah0wb2.aspx

Also, note the use of the default value for the constructor parameter. You need to have a constructor that takes a SecurityAction parameter for the attribute to get instantiated by the framework. Maybe DemandPermission is a bad name in this case, because you can override the SecurityAction to be something other than SecurityAction.Demand.

like image 84
Mike Goodwin Avatar answered Dec 30 '22 11:12

Mike Goodwin