Suggestions???

Suggestions???

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


SonOfPirate posted on Thursday, February 08, 2007

I have a complex design issue to overcome and thought I'd toss it up for discussion/suggestions here on how you think you might solve this in your CSLA apps...

Our company has three divisions: Division A, Division B and Division C.  Division A has two groups: Group A1 and Group A2.  Group A1 has three business units (let's call 'em departments): Dept A1A, Dept A1B and Dept A1C.  Getting the picture?

What we need is a design that will ensure that a user (Bob) assigned to Dept A1A can only "see" data from that department.  Likewise, a user assigned to Dept A1B (Steve) should only see there data.  However, another user (Cathy) can be assigned to Group A1.  When she uses the system, she should be able to see the data for ALL of the departments within their group.  The same holds for someone at the division or corporate level.  And a user assigned to Dept A1A AND Dept A1B needs access to both.

To accomodate the security structure, we have a tree data structure holding our OrganizationalUnit data.  We also have a many-to-many table that relates a user to the OUs that they are assigned (since a user may be assigned to more than one OU!).  Then, all of our data is ultimately referred back to an "owning" OU.  Unfortunately, it is implementing this design from this point forward that is causing some trouble.

Let's use the example of running a standard Sales Volume Report which lists the annual sales amount for each customer.  When Bob runs the report, we should return results for customers belonging to the "Dept A1A" OU.  When Steve runs it, only data from the "Dept A1B" OU should be shown.  But, when Cathy runs the report, we need to return records for all customers belonging to all four OUs (3 departments and the parent group) in which she can access.

In our BO's, we can typically handle a parent-child scenario and, in some odd cases, a parent-child-grandchild.  But those are clear-cut and 'static' relationships.  In this case, our CustomerSalesVolumeList could be retrieved as a child collection of our OU - which is fine for our lowest level OUs (the departments).  But, at the group level, our collection would be the customers assigned to the group AND all child OU's.  Carry this up on up the chain to where we are accumulating aggregate data from across the whole organization and we'll be dealing with great-grandchildren before long!

The flip-side is also true in that there are attributes that we need to inherit down the heirarchy as well.  So, if users in Group A1 are not allowed to edit a particular object, users in the child OUs should inherit this restriction as well.

I'm going to stop here rather than start down some path and leave it to you for suggestions.  I'm sure someone has had to deal with this situation and hopefully I've painted a good enough picture for you to understand the situation.  If not, let me know.

Thanks in advance.

 

SonOfPirate replied on Friday, February 09, 2007

Any ideas?

hayrob replied on Friday, February 09, 2007

I have implemented a solution which uses the child object AuthorisedUser. In my case, the data are Documents, so a document has a Collection of AuthorisedUsers. An AuthorisedUser has three levels - CanView, CanChange and CanChangeAccess(ie can allow others to view or change the Document). Documents can be Unrestricted which means that it has no AuthorisedUsers (since everyone can see the Document). This certainly works when the general rule is that Documents are "private" and access is granted to those who have a need to see it. May not be what you are looking for.

The key thing however seems to be that it is the data that needs to have access rights - not the Users.

 

SonOfPirate replied on Friday, February 09, 2007

There are two levels of security.  The first is based on what OU the user and the data are assigned to.  So, for instance, access to the list of customers is limited by what OU(s) the user and the data have in common.

The second level of access if provided by the standard CanRead, CanEdit, etc. methods via the permissions granted to the users.  So before the user can access the list of customers assigned to their OU, they have to be granted read access to the customers (via CanReadCustomer() method).

This doesn't help me with the problem of inheritance where the data returned consists of all items in the current OU and all child OUs or where settings at a parent OU are inherited by the child OUs.  I don't have any problem limiting access to customer data when the user has read access and belongs to only a leaf OU.  It is when the user belongs to a parent node that the problem begins.

 

jeff replied on Friday, February 09, 2007

Why not pass an OU as a fetch criteria to CustomerSales or some other collection object? Seems to me that OU business objects may not be needed in this scenario, at least not to hold collections of customer sales data.

SonOfPirate replied on Friday, February 09, 2007

That would be fine if I was only dealing with a single BO but I can have anywhere from zero (0) to three (3) levels of child OUs that would need to be included.  And, it is not always the case that we will include all child OUs when a parent OU is requested.

Let me give another use case that may help convey the nature of the problem.

One of the parameters that the users have to work with is the Manufacturing Plant used to fulfill an order.  The application must allow us to define the default Manufacturing Plant at each level.  If it is not defined, then the value defined at the parent level is to be used.  So, we will define a value for each division, say, and that needs to be the value we use for all groups and their departments unless specifically overriden.

I can certainly copy the value for each OU when a child is added but what about cases where we aren't dealing with a scalar value, such as security rights?  Or when the value at the parent level is changed?  Given the variable number of child nodes, trying to handle this in SQL seems highly complex and using an object graph to propogate the information (e.g. return (_defaultMfgPlant == null) ? Parent.DefaultMfgPlant : _defaultMfgPlant;) seems resource intensive and goes against the decoupled model that I am used to with Csla.  Plus, imo this is business logic and should be in our BOs.

I guess I'm surprised that no one has run into this, especially with regards to security.  I don't think this is too different from the way Windows cascades security priviledges and is the way CSS are applied in a browser.  I was hoping for some real-world advise based on how someone else has already dealt with this situation.

 

SonOfPirate replied on Friday, February 09, 2007

FYI - for anyone interested in this...

The approach I decided to follow was to simply specify the OU of the current user and allow SQL Server to do the work figuring out what records to return.  But, I didn't know how to do this given the variables discussed before.  So, I posted the question of how to retrieve heirarchical data in a single resultset on Experts Exchange and viola!  The answer.

Here's a great link about SQL Server 2005's new Common Table Expressions feature which does exactly what I need:

http://www.simple-talk.com/sql/sql-server-2005/sql-server-2005-common-table-expressions/

This page describes the exact setup that I'll use:

http://msdn2.microsoft.com/en-us/library/ms186243.aspx

 

Using a CTE in the query, I can have a single BO for the data and retrieve the appropriate results no matter how complex the organizational structure becomes or where in it the current user belongs.

Thanks for moving my thought process along.

 

Copyright (c) Marimer LLC