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?
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With