views:

583

answers:

4

I've thought about this too much now with no obviously correct solution. It might be a real wood-for-the-trees situation, so I need stackoverflow's help.

I'm trying to enforce database filtering on a regional basis. My system has various users and each one is assigned to a regional office. I only want users to be able to see data that is associated with their regional office.

Put simply my application is: Java App -> JPA (hibernate) -> MySQL

The database contains object from all regions, but I only want the users to be able to manipulate objects from their own region. I've thought about the following ways of doing it:

1) modify all database querys so they read something like select * from tablex where region="myregion". This is nasty. It doesn't work to well with JPA eg the entitymanager.find() method only accepts primary key. Of course I can go native, but I only have to miss one select statement and my security is shot

2) use a mysql proxy to filter results. kind of funky, but then the mysql proxy just sees the raw call and doesn't really know how it should be filtering them (ie which region the user that made this request belongs to). Ok, I could start a proxy for each region, but it starts getting a little messy..

3) use separate schemas for each region. yeah, simple, I'm using spring so I could use the RoutingDataSource to route the requests via the correct datasource (1 datasource per schema). Of the course the problem now is somewhere down the line I'm going to want to filter by region and some other category. ohps.

4) ACL - not really sure about this. If a did a select * from tablex; would it quietly filter out objects I don't have access for or would a load of access exceptions be thrown?

But am I thinking too much about this? This seems like a really common problem. There must be some easy solution I'm just too dumb to see. I'm sure it'll be something close to / or in the database as you want to filter as near to source as possible, but what?

Not looking to be spoonfed - any links, keywords, ideas, commerical/opensource product suggestions would be really appreciated!! thanks.

+1  A: 

Good Question.

Seems like #1 is the best since it's the most flexible.

Region happens to be what you're filtering on today, but it could be region + department + colour of hair tomorrow.

If you start carving up the data too much it seems like you'll be stuck working harder than necessary to glue them all back together for reporting.

Allain Lalonde
+1  A: 

I've just been implementing something similar (REALbasic talking to MySQL) over the last couple of weeks for a hierarchical multi-company extension to an accounting package.

There's a large body of existing code which composes SQL statements so we had to live with that and just do a lot of auditing to ensure the restrictions were included in each table as appropriate. One gotcha was related lookups where lookup tables were normally only used in combination with a primary table but for some maintenance GUIs would load the lookup table itself, directly.

There's a danger of giving away implied information such as revealing that Acme Pornstars are a client of some division of the company ;-)

The only solution for that part was very careful construction of DB diagrams to show all implied relationships and lots of auditing and grepping source code, with careful commenting to indicate areas which had been OK'd as not needing additional restrictions.

The one pattern I've come up with to make this more generalised in future is, rather than explicit region=currentRegionVar type searches, using an arbitrary entityID which is supplied by a global CurrentEntityForRole("blah") function.

This abstraction allows for sharing of some data as well as implementing pseudo-entities which represent other restriction boundaries.

I don't know enough about Java and Spring to be able to tell but is there a way you could use views to provide a single-key lookup, where the views are restricted by the region filter?

The desire to provide aggregations and possible data sharing was why we didn't go down the separate database route.

Andy Dent
i'm coming to the same conclusion... I'm just going to have to capture all direct/indirect SQL statements. could you expand a touch on how you use your CurrentEntityForRole() function - I'm not quite sure I understand?
Corin Fletcher
"WHERE accounts.corpEntityID=" + CorporateEntities.IDforRoleQuoted("accounts") allows for a different entity instead of the current user's. Say companies and divisions share chart of accounts - a division gets its parent company's ID. It maps CurrentID+Role => effectiveID. Rarely used but useful.
Andy Dent
got you! - thanks
Corin Fletcher
A: 

I am having the same problem. It is hard to believe that such a common task (filtering a list of model entities based on the user profile) has not a 'standard' way, pattern or best-practice to do it.

I've found pgacl, a PostgreSQL module. Basically, you do your query like you normally would, and then you tack on an acl_access() predicate to work as a filter.

Maybe there is something similar for MySQL.

Guido
A: 

I suggest you to use ACL. It is more flexible than other choices. Use Spring Security. You can use it without using Spring Framework. Read the tutorial from link text

Gok Demir