Data-driven Authorizations

Data-driven Authorizations

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


mercule posted on Friday, March 23, 2007

I'm retrofitting an existing web application to use CSLA during an upgrade release.

I've got an object in my application that can be marked as one of several categories.  The category determines, in part, which roles have edit access to the data.  This relation is pulled from a table and is subject to change.  Are there any best-practices on how to do this?

From searching the forums, I've come up with a couple of ideas. 

One is to make the CanEditObject and CanGetObject methods non-static and put my code there.  In testing it, though, I can get the correct boolean to return, but if the UI calls the save, anyway, no exception is thrown.  That is not what I'd expect.  Or is the intended use for me to call these from the DataPortal_Update method myself?

If that's the case, then does it really matter what the method name really is, so long as I make in public and non-static?

I also found a recommendation to use multiple objects for authorizations if this is a workflow situation.  I have both workflow and non-workflow data-driven authorizations for this object.  Can someone give a brief overview of how the multiple objects model would be used?  I assume it uses polymorphism, but I'm getting hung up on exactly how my page would get the right version of the class -- by the time you've got enough data to figure out which version to call, you've already loaded the object.

ajj3085 replied on Friday, March 23, 2007

Its up to you to put the necessary security checks in the Save method.  Overload it, and use the existing methods to check permissions.

As for your workflow vs non-workflow, I'm not sure I follow.  The auth rules change based on if the item in question is going through a workflow or not?   You may need some kind of factory to help you here.. the factory could return the proper instance based on the data... you would likely need an interface.

But how do your UI know if it needs to show the workflow UI vs. the non-workflow UI?

mercule replied on Friday, March 23, 2007

ajj3085:
Its up to you to put the necessary security checks in the Save method.  Overload it, and use the existing methods to check permissions.

Okay.  Thanks.

As for your workflow vs non-workflow, I'm not sure I follow.  The auth rules change based on if the item in question is going through a workflow or not?   You may need some kind of factory to help you here.. the factory could return the proper instance based on the data... you would likely need an interface.

But how do your UI know if it needs to show the workflow UI vs. the non-workflow UI?

The workflow piece was something I saw recommended elsewhere in these forums for a similar issue.  I didn't quite follow the whole discussion, thus the vagueness in my question.  But it seemed at least tangentally applicable.

In my case, there are two conditions for authorization checking.  The first is the straightforwardish role checking I mentioned above.  The second is that there is a point at which part of the form is marked "complete" and some fields are made uneditable to RoleA while others are made editable to RoleB.  This second case is what seemed appropriate for the workflow discussion.

SonOfPirate replied on Friday, March 23, 2007

If I am understanding your explanation, an example of workflow authorization would be a case were your data item could no longer be edited because of its state.  For instance, suppose the current user was granted the right to create and edit a Quote object.  Once that quote was submitted, it should be locked with no further changes permitted.  The user still possesses the right to create new Quotes and edit Quotes in general, but for this particular Quote, its state indicates that this right is nullified and CanEditObject would/should return false.

I have implemented this in a number of cases.  In the past I have simply hard-coded the conditions within the authorization method.  However, I am in the process of evaluating how to expand the AuthorizationRules feature to support conditionalizing the rules.  Haven't come up with anything yet, still reviewing the notion.

HTH

 

mercule replied on Friday, March 23, 2007

The specific post that got me thinking was this one.  The idea of using sibling classes isn't actually stated (re-reading it, I think I might have misinterpretted what he was saying), but that is the only way I can think to do it without having a bizarre UI.

Taking the idea of a Quote, a sales rep would create and submit it then the accountants would review it.  (Actually, this is functionally similar to what I'm doing, just simplified.)  Between creation and submission, sales could tinker freely and add comments.  Between submission and reviewed, the accountants could tinker and add comments in a different section.  After review, the entire form is locked.

What I'd picked up from Rocky's comment was that you could design three similar classes that all inherited from a common QuoteParent class.  About the only difference between the child classes would be the AddAuthorizationRules method.

Where I ran into a problem was reconciling that to my UI which lists all Quotes in one list and links to the same page to edit any given Quote.  I'm not sure how to get the class to build the correct version of itself.

For my current application, the solution I'd started pursuing was to add a LocalAuthorizationRules method that is called from the DataPortal_Fetch method.  That way, the rules are added after the data is loaded.  So far, I haven't found any bugs in the way it's getting handled.  Of course, I'm still very green to using CSLA and many of the concepts behind it.

PStanev replied on Friday, March 23, 2007

That post ( http://forums.lhotka.net/forums/thread/8937.aspx )was mine. I have not decided yet how to implement the data driven authorization rules , because I have so many WF states, so many roles and so many property in the BO and so many project types. I'm planning to use 2 SQL tables. One for selecting the valid cases for roles vs. WF states vs. project types. And second table each case vs. BO property. Then will take me a lot of time to get all the cases in the tables. Then I think with sql store procedure passing the current role, wf state and property name, get the authorization for it (read/write/required). I don't now if any of this make sense for your case.

  

SonOfPirate replied on Friday, March 23, 2007

The question this raises in my mind is why introduce the database into the mix?  Do your authorization rules change?  I can't think of any other reason to store the rules in a database unless they were dynamic in nature.

I realize that the objects and the true/false value of any authorization condition will be dynamic and vary based on all of the conditions you specify but, in reality, those conditions don't change do they?  Only the result of those conditions.

For example, and I like mercule's scenerio in his last post, you would have the following in your CanEditObject method:

if (Csla.ApplicationContext.User.IsInRole("SalesRep"))
    return (State == Draft);
else if (Csla.ApplicationContext.User.IsInRole("Accountant"))
    return (State == Submitted);
else
    return false;

...or something.

Beyond that, you are looking at implementing property-level rules which gets more complicated but is just as static.  This is where I was developing the idea of exposing the authorization as a property/delegate pair instead of a property/role pair.  Then I would have a method in the object named CanChangeSalesPrice(), for instance, that would be used to apply the authorization rules for the SalesPrice property.

The problem I have with this approach is the number of methods that are required to support this - one for each property.  Plus, I have a difficult time rationalizing the per-property rules when typically the per-class rule governs them all anyway.

In the case of workflow-type scenerios such as what mercule describes, I've actually found that Rocky's suggestion works best.  In a similar situation where an estimator was required to complete "his" portion of the data after the quote was drafted by the sales rep and before it could be submitted, I broke the code into two classes: Quote and CostEstimation.  The latter became a child element of the former for validation purposes but authorization (and thereby, access) was specified for each.

Can someone give me a tangible example of how you've made use of the per-property authorization rules?  Even in the ProjectTracker sample app, all of the rules applied in AddAuthorizationRules are simply the same rule as defined in CanEditObject.  Seems redundant to me.  Is this simply to provide a second check in the event the UI developer misuses CanEditObject?

Anyway, somewhat meandering but HTH somehow nonetheless...

 

Copyright (c) Marimer LLC