FAQ - Collection item Authorization

FAQ - Collection item Authorization

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


tiago posted on Saturday, August 14, 2010

I) The problem

I'm using CSLA.NET v.4.0.1.

I have a MyParentRoot (A) object that contains MyEditableChildCollection (B) of MyEditableItem (C), like this:

MyParentRoot (A)
  |
  |--- IdProperty
  |
  |--- NameProperty
  |
  |--- MyEditableChildCollection (B)
         |
         |-MyEditableItem_1 (C)
         |
         |-MyEditableItem_2 (C)

Managing authz for (A) and (B) is the bread and butter of every Csla developer (cough).
My issue is how do I manage authz for (C), i.e. for items of a collection, of any collection.

I can go to MyEditableItem and add an AddObjectAuthorizationRules() method that sets authorization Authz 4 way

BusinessRules.AddRule(typeof(MyEditableItem), new IsInRole(AuthorizationActions.GetObject"User"));

but that doesn't stop anyone to

MyParentRoot myParentRoot = MyParentRoot.NewMyParentRoot();
// get MyEditableItem_1 somehow (not important here)
myParentRoot.MyEditableChildCollection.Remove(MyEditableItem_1);

since in this context, Remove is a member of  System.Collections.ObjectModel.Collection<T> and Csla has no control over it.

 

II) How do we solve this problem?

1) Set the Allow* properties according to CSLA authz.
This solves the problem but the exception message is short and terse, like "Specified method is not supported."

2) Overcome the "short and terse" exception message (minor) issue by "hiding" (no, not override; just hide) the original System.Collections.ObjectModel.Collection<T> methods:
- public void Add(T item)
- public bool Remove(T item)

This solves most problems but not all. You have plenty of methods in System.Collections.ObjectModel.Collection<T> with exception messages "short and terse". We will leave out of the message solution the public methods:
- CopyTo(T[], int)
- Insert(int, T)
- RemoveAt(int)
Other collection methods like AddNew() and AddNewCore() are a different problem that won't be addressed here.
Note this isn't an essential part of the solution; it's just an user friendly way to solve it.

3) We can use the raw Authz 4 way of checking permission. In this example, we will use Can* methods that are less verbose and more programmer's friendly.

4) As a side note, please refer to "Preferred way of adding a child to a collection object" at http://forums.lhotka.net/forums/p/8649/41142.aspx concerning directions on collection and item handling.

 

III) The solution's code

(A) MyParentRoot - nothing to do

(B) MyEditableChildCollection

Constructor - the collection's Allow* properties are set according to the item's Can* methods.

protected internal MyEditableChildCollection()
{
    // Prevent direct creation

    // show the framework that this is a child object
    MarkAsChild();

    RaiseListChangedEvents = false;
    AllowNew = MyEditableItem.CanAddObject();
    AllowEdit = MyEditableItem.CanEditObject();
    AllowRemove = MyEditableItem.CanDeleteObject();
    RaiseListChangedEvents = true;
}

Note that the collection loader below must make sure it can add items to the collection. After loading, it sets the AllowNew collection property according to the item's CanAddObject().
In fact the "can" applies to the user actions. We allow the collection to populate itself but may forbid (or allow) the user to add new items to the collection.
This is just an example of the possible side effects and not really part of the solution.

private void Fetch(SafeDataReader dr)
{
    AllowNew = true;
    RaiseListChangedEvents = false;
    while (dr.Read())
    {
        MyEditableItem obj = MyEditableItem.GetMyEditableItem(dr);
        Add(obj);
    }
    RaiseListChangedEvents = true;
    AllowNew = MyEditableItem.CanAddObject();
}

Let's look at the hiding code of System.Collections.ObjectModel.Collection<T> methods.

public new void Add(MyEditableItem item)
{
    if (!AllowNew)
        throw new System.Security.SecurityException("User not authorized to create MyEditableItem.");

    base.Add(item);
}

public new bool Remove(MyEditableItem item)
{
    if (!AllowRemove)
        throw new System.Security.SecurityException("User not authorized to delete MyEditableItem.");

    return base.Remove(item);
}

(C) MyEditableItem

This is mostly the code for setting authorization under Authz 4 and the programmer's friendly Can* methods.

protected static void AddObjectAuthorizationRules()
{
    BusinessRules.AddRule(typeof(MyEditableItem), new IsInRole(AuthorizationActions.GetObject"User"));
    BusinessRules.AddRule(typeof(MyEditableItem), new IsInRole(AuthorizationActions.CreateObject"Author"));
    BusinessRules.AddRule(typeof(MyEditableItem), new IsInRole(AuthorizationActions.EditObject"Author"));
    BusinessRules.AddRule(typeof(MyEditableItem), new IsInRole(AuthorizationActions.DeleteObject"Admin""Manager"));
}
public static bool CanGetObject()
{
    return Csla.Rules.BusinessRules.HasPermission(Csla.Rules.AuthorizationActions.GetObjecttypeof(MyEditableItem));
}
public static bool CanAddObject()
{
    return Csla.Rules.BusinessRules.HasPermission(Csla.Rules.AuthorizationActions.CreateObjecttypeof(MyEditableItem));
}
public static bool CanEditObject()
{
    return Csla.Rules.BusinessRules.HasPermission(Csla.Rules.AuthorizationActions.EditObjecttypeof(MyEditableItem));
}
public static bool CanDeleteObject()
{
    return Csla.Rules.BusinessRules.HasPermission(Csla.Rules.AuthorizationActions.DeleteObjecttypeof(MyEditableItem));
}

And that's it!

Copyright (c) Marimer LLC