Per-Instance Authorization Help

Per-Instance Authorization Help

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


Biceman posted on Saturday, June 13, 2009

I am trying to understand per-instance authorization. 

I have a list of Products (BLB of BB) which contain items (BB) created by both the system and users.  Each Product (BB) has a product id (the unique key) and a product id < 100 indicates the entry was created by the system.

My Use Case states:
Only users in the "Admin" role can modify an item created by the system
Items created by the system can never be deleted
Users in the "Guest" or "Admin" roles can add, modify, read, and delete all non-system entries

Additionally, there are no per-property type authorizations; read authority at the type-level applies to all properties; modify authority at the type-level applies to all properties

Since the authorization rules are based on a value unique to each instance, I figured per-instance authorization would be appropriate.  The type-level authorization I based on the "Guest", "Admin" roles (bullet 3 of the Use Case)

The VB 2008 book p 351 shows examples of per-instance authorization rules.  Now maybe I'm missing something but why would you create per-instance authorization rules that are not based on some data in that particular instance? 

What does:

   AuthorizationRules.InstanceAllowRead(NameProperty, "Supervisor", "Guest")

give you that

   AuthorizationRules.AllowRead(NameProperty, "Supervisor", "Guest")

doesn't?

My idea was as follows:

Protected Overrides Sub AddInstanceAuthorizationRules()
   If Product-Id < 100 then
         'Override the type-level delete authorizations as appropriate
         AuthorizationRules.InstanceAllowExecute("Delete", "** NO ONE **")
         AuthorizationRules.InstanceAllowExecute("Modify", "Admin")
   End If
End Sub

but the AddInstanceAuthorizationRules() subroutine fires before the Product-Id property is loaded from the database.  As such the IF test always evaluates to True so that idea is out.

Even if the above code had worked, I'm not real sure what would have kept the Grid from deleting the Product (BB) in the Products (BBL) that "NO ONE" has authority to delete.

So at this point I thought I would ask for some advice on how to best implement my Use Case rules while keeping within the CSLA authorization scheme (if possible).

Finally, is this a mistake in the book?  Refering back to:

   AuthorizationRules.InstanceAllowRead(NameProperty, "Supervisor", "Guest")

from p 351 of the VB 2008 book.  The naming convention used throughout is such that "NameProperty" would be of type PropertyInfo.  However, Intellisense for the InstanceAllowRead method states the first argument must be of type String.

RockfordLhotka replied on Sunday, June 14, 2009

Per-instance authz rules should be avoided. The feature was implemented in version 2.0, but turned out to be very expensive in terms of memory and performance. I left the feature in the framework for backward compatibility, but I recommend against using the feature.

The feature doesn't exist, for example, in CSLA .NET for Silverlight, and someday I hope to eliminate it from CSLA .NET for Windows as well.

Biceman replied on Sunday, June 14, 2009

Rocky, might I suggest that should the next iteration of your Expert VB/C# 2008 books still contain a section on "Per-Instance Authorization Rules", you:
Had I read this, I would have known I was headed down the wrong path.

It would be helpful if the book discussed alternative approaches to handling per-instance authorization (presumably based on some property within the business object) without using the InstanceAllowXxxxx or InstanceDenyXxxxx methods.

bjb

glenntoy replied on Sunday, June 14, 2009

BiceMen,

My Use Case states:
Only users in the "Admin" role can modify an item created by the system
Items created by the system can never be deleted
Users in the "Guest" or "Admin" roles can add, modify, read, and delete all non-system entries

Just a suggestion, why not overrides the save method of your business object to fit your needs. For example, if ProductId < 300 are all system entries.. then your logic under your overrided Save will be

if  (ProductId < 300) AndAlso (Not Csla.ApplicationContext.User.IsInRole("Admin")) Then
 throw an exception that it can't be save
else
 do the saving
end if
.
Point out that instance-rules are set during creation of the object instance;  <-- I don't know if you have the business object 2005 book or not. But it was explained in second edition the when a businessbase is created through its constructor it calls AddBusinessRules() and AddAuthorizationRules() methods.

This can be found on chapter 3 - business framework impelmentation under ValidationRules object



JonnyBee replied on Monday, June 15, 2009

Hi,

I would do the following actions:
Override CanWriteProperty   -  for rules concerned whether properties are editable (or locked). Here - properties on "System" owned items are only editable if user has system role.

Custom checks in Dataportal_XYZ methods to prevent Save/Insert/Update/Delete on System

ex:
public override bool CanWriteProperty(string propertyName) {
    if (!base.CanWriteProperty(propertyName)) return false;

    if (Product-Id < 100) return Csla.ApplicationContext.User.IsInRole("Admin");
    return true;
}


public override bool CanExecuteMethod(string methodName)
{
     if (!base.CanExecuteMethod(methodName)) return false;

     if ((Product-Id < 100) return Csla.ApplicationContext.User.IsInRole("Admin");
     return true;
}

You could use that code to set Enabled on buttons in the UI and in your Dataportal Methods:
private void DataPortal_Update(...) {
     if (!CanExecuteMethod("Save")) {
           throw new System.Security.SecurityException("Save not allowed");
    }

    // other update code goes here .....

}

/Jonny

Biceman replied on Tuesday, June 16, 2009

Thanks Jonny, I've give this a try.

Copyright (c) Marimer LLC