[Grok-dev] Data modelling & security

Matthias nitro at dr-code.org
Thu Jan 20 21:07:11 EST 2011


Am 20.01.2011, 23:06 Uhr, schrieb Martijn Faassen <faassen at startifact.com>:

> On 01/17/2011 02:34 AM, Matthias wrote:
>
>> 1) Does the basic version or the alternative version make more sense?  
>> The
>> alternative version clearly marks any missing data. I am not sure if
>> that's good or bad.
>
> I'm not sure I understand the intent of the tables you mention. I mean,
> if Task and User are accessible, why would you return the task and the
> user? Is that because the assignment is inaccessible and you're actually
> querying for assignments?

Yes. Sometimes this can go over a hoop. E.g. if you want to get users  
which are assigned to a certain task, you first query the assignments  
relation, then you query the user attributes of the assignments.

> Could you model this then so that the
> Assignment permissions are the only ones directly checked, but you let
> them derive from the underlying task and user (and their own permission)?

I think there are two checks necessary. First it must query and check the  
assignment, then another check if the user may access the .user attribute  
of a given TaskAssignment. It could be possible to derive the permissions  
 from the underlying objects, that does not always make sense. E.g.  
sometimes an employee is well known, the project is also well known, but  
you don't know that the specific employee is assigned to the specific  
project.
The source for the security permissions for the TaskAssignment could be  
made flexible, so it could either have its own permissions or so the  
permissions are calculated from the user and task attributes of the task  
assignment.

>> 2) Each intermediate query result would need to be security checked. If
>> you think checking the resulting objects sufficed, just imagine the
>> results of the following query: "get any user where task == 'top  
>> secret'".
>> You'd get a list of users involved with that task even if though nobody
>> should've known that those users were assigned to the task.
>
> The question is whether this is in fact a query for a user at all. Isn't
> this really a query for "get all assignments where task == "top secret"?
>  From the assignments you can derive the users, yes, but is this really
> the target of the query?

You are right, bad query. "get assignment.user of all assignments where  
assignment.task == 'top secret'" makes more sense indeed.

> Anyway, I think it'd be interesting to set up at least a custom
> PermissionMap for Assignment, and perhaps the others.
>
> from zope.securitypolicy.interfaces import IPrincipalPermissionMap
> from zope.security.management import checkPermission
>
> class MyPermissionMap(grok.Adapter)
>      grok.context(Assignment)
>      grok.provides(IPrincipalPermissionMap)
>
>      # this is really the only method you have to implement, even though
>      # the interface defines more....
>      def getSetting(self, permission_id, principal_id, default=Unset)
>           if not checkPermission(permission_id, self.context.user):
>               return Unset
>           ...
>
> You probably have to watch out for crazy recursion issues in some cases,
> so perhaps instead of checkPermission you should go to a lower-level.

Thanks for the pointer to this, I will take a deeper look into permissions  
maps. I'll also have to check if dolmen.securitypolicies uses them.

>> 3) Resulting from 2) there might arise performance problems. I am not  
>> sure
>> if the query could be performed while collecting the necessary  
>> permissions
>> for each "row" in the result. Then one could check permissions only at  
>> the
>> end (and possibly against some form of index to speed things up or the
>> "top 10" of the results).
>
> I think doing the permission checks in the end is a lot easier to get
> right, and probably will perform better too.

Yes, I think so too. I could also just perform the query without any  
security checks. And then for every result being returned check if the  
security chain of the result was not broken. This will just perform bad if  
there are many, many results or if many of the results are forbidden.

>> 4) If a user is generally accessible, it should not return the  
>> "password"
>> attribute of the User except if the user is the querying user. I guess
>> this can be solved with zope.proxy/zope.security. Or by turning the
>> password attribute to a "PasswordProtected" relation between a user and
>> its password, then the relation can be protected at the object level,  
>> just
>> like the Assignment
>
> You could of course try solving this issue in the user interface as
> opposed to on the code level. The question here you have is how much do
> you trust the developers. Do you really not trust them enough to want to
> hide the password attribute? Is that either because they're too evil
> (okay, give up already) or because they're too stupid?

The issue at heart here is that it's not necessarily developers writing  
the queries. The queries are generated in your browser and sent from  
there. There are no hard-coded queries on the server side. Most queries  
are ad-hoc generated from users.
So while I trust users enough to not DoS the server with arbitrary long  
queries I don't trust them that they limit themselves to objects they are  
allowed to see. Let's imagine there's a "company yearly revenue" report  
only the company manager is allowed to see. A user should not be able to  
query for that object for example.

>> How do you guys deal with these problems? I'd really like avoid having  
>> to
>> write a special grok.View and explicitly checking permissions for each
>> operation the client might perform. If the queries could be all dynamic  
>> I
>> could a) develop faster, b) had less redundant code and c) clients could
>> create their own UIs/queries for their tasks.
>
> I've recently mostly had to deal with these problems when exposing
> SQLAlchemy objects, and PermissionMap works pretty well then. You can do
> whatever database query you need to determine whether someone has a
> permission.

What's your general impression of using SQLAlchemy over ZODB? Would you  
use the ZODB if it had better querying capabilities and a better interface  
to the outside world?

> You could do something similar: instead of using Zope's permissions you
> could instead use your own database structures (attributes) to talk
> about permissions in a way that is sensible to your application, and
> then use PermissionMap to translate these to permissions so that views
> show up or not. You could then use these attributes in your queries
> directly.

Good idea.

> You should only go for heavy-duty security proxies if you really don't
> trust your developers in some way. There's not a lot of experience with
> dealing this in a Grok context, but you should be able to make it work.
> You might have to disable Grok's custom publisher.

I trust the developers just not the users :-) I guess full security  
proxies might still be overkill, but I am not sure.

> I know it's tempting to get the security architecture right at a lower
> level. Zope 3 (and the ZTK) was designed to allow this kind of stuff,
> using the proxies. When we started the Grok project, I argued much for
> loosening some of these rules, because getting the security model right
> up-front (for all your methods and attributes) ends to take up a lot of
> time and effort that can really be a drag on development, and during
> early development you often don't even know enough about your data model
> yet to get it right. A lot of usability issues...

Yes, I can see the point for simplicity and I guess it's a good trade-off  
in most situations.

> That said, it might be possible to design a more lower level security
> system that is more usable. It might also be that in some projects, the
> investment in effort in the existing system is worth it.
>
>> Additionally, are there any comparable systems which feature full  
>> objects
>> like the ZODB does, yet allowing fully dynamic queries with fine-grained
>> security? It might be worth "stealing" from them :-)
>>
>> Is it even advisable to be able to query the ZODB in the way outlined
>> above?
>
> It's a matter of trade-offs.
>
>> Finally, is anybody else interested in features like this? Right now it
>> seems this could make your client side coding a lot easier, especially  
>> if
>> you have generic javascript widgets for lists, tables, forms and so on.
>
> I guess you're not satifisfied by just making sure your JSON methods are
> protected and don't deliver too much data? :)

:) No, that's how I started. It limits the user's abilities to do  
arbitrary things with the data. At least the part of the data he is  
allowed to access :)

> Thanks for bringing up this discussion! It's hard to get into, but it's
> quite interesting!

I will probably make a more clear example case if needed. I've finished  
writing my indexing code and my querying code has also made progress.  
Security will come after I made the basics work.

Thanks for taking the time to answer my somewhat convoluted mail :)

-Matthias


More information about the Grok-dev mailing list