CanWriteProperty and AuthorizationActions.EditObject

CanWriteProperty and AuthorizationActions.EditObject

Old forum URL: forums.lhotka.net/forums/t/10611.aspx


mdbzntcd posted on Friday, August 12, 2011

I'm trying to enable/disable fields in a data grid in WPF using the PropertyInfo control.  A user may be able to edit some objects (parts or whole) in a list and not others depending on security groups and the status of the object.  There are per-type rules for the security groups for control editing of the object as a whole.  There per property methods to control editing depending upon the status.  The problem is that the PropertyInfo.CanWrite property, and the CanWriteProperty method in general, do not check the per-type authorization rule first.  Is there a reason for this?  It seems like if the user doesn't have permission to edit the object, CanWriteProperty should be false for all properties as well.

I'm just starting to dig into the authorization rules, so I may some concepts confused.  I have read most of the Using CSLA 4 Objects draft ebook about business rules, but I may need to go over it again.  I'm coding against CSLA 4.1 right now.

Thanks for any help.

RockfordLhotka replied on Tuesday, August 16, 2011

For performance reasons, exactly one authorization rule is allowed per type/property and per action.

But rules can be arbitrarily complex. If you feel the need for your per-property rules to check the per-type rules before doing any more detailed authorization logic, then you can absolutely write a rule that does such a thing.

Creating authorization rules isn't difficult. Just subclass AuthorizationRule and overrride the Execute method.

mdbzntcd replied on Tuesday, August 16, 2011

Thanks Rocky.

I ended up creating an aggregate authorization rule that I can stuff any number of sub rules into.  I also created a CanEditObject rule that I put in each aggregate rule for each property in addition to the other rule(s) for each property.  We'll wait and see what kind of performance issues we have, but I'm not sure of any other way around it with these checks being the requirements for the app.

It still seems like CanWriteProperty should return false if the user doesn't have permission edit the object.  That would at least save me from wiring it up to every property on every object in my library.

JonnyBee replied on Tuesday, August 16, 2011

You could even create a intermediate base class for BusinessBase that overrides CanWritePropery and checks for Authz on EditObject first and also add an overload to AddBusinessRules that adds a StopIfNotCanWrite rule to all properties that are not Child objects.

That would short circuit (stop) rule processing on all properties when user is not allowed to change the property values and will even work with DataAnnotation rules that are always added with priority 0.

  public class StopIfNotCanWrite : BusinessRule
  {
    public StopIfNotCanWrite(IPropertyInfo property) : base(property) { }
 
    protected override void Execute(RuleContext context)
    {
      var business = context.Target as BusinessBase;
      if (business == nullreturn;
 
      if (!business.CanWriteProperty(context.Rule.PrimaryProperty))
      {
        context.AddSuccessResult(true);
      }
    }
  }

Base class:

  [Serializable]
  public class MyBusinessBase<T> : Csla.BusinessBase<T> where T : MyBusinessBase<T>
  {
    public override bool CanWriteProperty(IPropertyInfo propertyName)
    {
      if (!Csla.Rules.BusinessRules.HasPermission(AuthorizationActions.EditObject, this))
        return false;
      return base.CanWriteProperty(propertyName);
    }
 
    protected override void AddBusinessRules()
    {
      base.AddBusinessRules();
 
      var props = FieldManager.GetRegisteredProperties().
                       Where((p => (p.RelationshipType & RelationshipTypes.Child) == 0));
 
      foreach (var propertyInfo in props)
      {
        BusinessRules.AddRule(new StopIfNotCanWrite(propertyInfo) { Priority = -1});
      }
    }
  }

And all you have to do in your app is make your business objects inherit from MyBusinessBase.

 

mdbzntcd replied on Wednesday, January 18, 2012

Thanks Johnny.  I did overwrite CanWriteProperty in our base class which allowed me to skip adding the rule for every property.

I did still have a need for the aggregate authorization rule as well.

Copyright (c) Marimer LLC