Base class:
public class MyBusinessBase<T> : BusinessBase<T> where T: MyBusinessBase<T>
{
protected static void AddObjectAuthorizationRules()
{
var tp = typeof(T);
var roleName = "role_" + tp;
BusinessRules.AddRule(tp, new IsInRole(AuthorizationActions.CreateObject, roleName));
BusinessRules.AddRule(tp, new IsInRole(AuthorizationActions.GetObject, roleName));
}
}
If we will change "AuthorizationRuleManager" behaviour like this:
private static void InitializePerTypeRules(AuthorizationRuleManager mgr, Type type)
{
...
var type2 = type;
var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.DeclaredOnly;
while (type2 != typeof(object))
{
// invoke method to add auth roles
var method = type2.GetMethod("AddObjectAuthorizationRules", flags);
if (method != null)
{
method.Invoke(null, null);
break;
}
type2 = type2.BaseType;
}
...
}
We will achive next:
- all inherited objects will inherit "AddObjectAuthorizationRules" method. And I can even override this method.
So, is this good or bad idea?
I believe you have missed one very important point.
There can only be one-1 authorization rule for each Type - MethodInfo and AuthorizationAction.
For object authorization rules the MethodInfo is null - so there can only be one authorization rule per AuthorizationAction.
This limitation - in my opinion - makes it non-practical to call into a base class or make this an override method..
"There can only be one-1 authorization rule for each Type - MethodInfo and AuthorizationAction."
"AddObjectAuthorizationRules()" method is static. So it's OK. If I need to override base "AddObjectAuthorizationRules" method I can just declare new method:
static void AddObjectAuthorizationRules()
{
BusinessRules.AddRule(typeof(NewType), new IsInRole(AuthorizationActions.CreateObject, "role_NewType_Create"));
}
So, "AuthorizationRuleManager" will call only this one method. Base method will stay untouched.
"For object authorization rules the MethodInfo is null - so there can only be one authorization rule per AuthorizationAction."
As you can see, new behaviour doesn't break this limitation.
I see as usually you didn't understand me.
I think we are like from different planets. Maybe the problem is in my english or we have different kind of thinking?
Let's look at little example:
public class MyBusinessBase<T> : BusinessBase<T> where T : MyBusinessBase<T>
{
protected static void AddObjectAuthorizationRules()
{
var tp = typeof(T);
var roleName = "role_" + tp.Name;
BusinessRules.AddRule(tp, new IsInRole(AuthorizationActions.CreateObject, roleName));
BusinessRules.AddRule(tp, new IsInRole(AuthorizationActions.GetObject, roleName));
}
}
public class Invoice : MyBusinessBase<Invoice>
{
}
public class Order : MyBusinessBase<Order>
{
// override base method
new static void AddObjectAuthorizationRules()
{
BusinessRules.AddRule(typeof(Order), new IsInRole(AuthorizationActions.CreateObject, "role_admin"));
BusinessRules.AddRule(typeof(Order), new IsInRole(AuthorizationActions.GetObject, "role_admin"));
}
}
So, as you can see "Invoice" will use "base" "AddObjectAuthorizationRules" method. And "Order" "overrides" "AddObjectAuthorizationRules" method.
For now, CSLA doesn't allow me to do that and "Invoice" class should look like this:
public class Invoice :
BusinessBase
<Invoice>
{
static void AddObjectAuthorizationRules()
{
var tp = typeof(Invoice);
var roleName = "role_Invoice"; //"role_" + tp.Name;
BusinessRules.AddRule(tp, new IsInRole(AuthorizationActions.CreateObject, roleName));
BusinessRules.AddRule(tp, new IsInRole(AuthorizationActions.GetObject, roleName));
}
}
Is it clear now?
So what you propose is to add a new BindingFlags.FlattenHierarchy like this:
// invoke method to add auth roles var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.DeclaredOnly | BindingFlags.FlattenHierarchy; System.Reflection.MethodInfo method = type.GetMethod("AddObjectAuthorizationRules", flags); if (method != null) method.Invoke(null, null);
I need Rocky to chime in to this - for now I will add an Issue for this.
"So what you propose is to add a new BindingFlags.FlattenHierarchy like this:"
Yes. I forgot about FlattenHierarchy.
But flags should look like this (without DeclaredOnly):
var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
P.S.
By the way. How do you insert colored text? "Paste from Word" never works for me.
I use the CopyAsHtml extension for VS2010 - or HtmlCopy in Productivity Power Tools for VS2012 and paste the code into Firefox or IE browser.
Paste unfortunately doesn't work that nicely in Chrome.
Which versions are we looking at here? The BindingFlags.FlattenHierarchy flag appeared to disappear somewhere between version 4.1.x and 4.3.14.
We have a task / role based security system and we implemented a standard implementation (in our MyBusinessBase<T> class). This checks for an attribute on the sub-class and if it exists adds the rules using the Attribute Value.
This allows for a sub-class to be simply decorated with the "Security SubTaskID", or it can implement it's own rules if need be. Unfortunately we have recently upgraded to 4.3.14 and lost this behaviour.
Copyright (c) Marimer LLC