ChiliProject is not maintained anymore. Please be advised that there will be no more updates.

We do not recommend that you setup new ChiliProject instances and we urge all existing users to migrate their data to a maintained system, e.g. Redmine. We will provide a migration script later. In the meantime, you can use the instructions by Christian Daehn.

[Proposal] New Permissions

Added by Holger Just at 2011-05-04 05:30 pm

Some time ago I thought about some basic requirements of a permission/authorization system for ChiliProject. The following ideas and concepts are the result of that.

From what I have read, most of the requirements can be satisfied by using https://github.com/stffn/declarative_authorization. We should create a prototype to confirm that. The only thing that seems to be missing is the free declaration of roles. We might need to adapt some code here. But all in all, it looks really impressive.

The basic ideas

Permission should be always bound to model objects.

Only model objects can reliably check whether then can be seen/updated/deleted by the current user (or any other user). We have two cases here:
  • dealing with a single object (like a single issue)
  • dealing with aggregations (like a sum of hours of some time entries)

In the first case, it is rather simple: we can can have the model instance check itself using some instance methods, like issue.allow_read_by(User.current). The second case is a bit harder, as we have to express our accessibility restrictions in SQL (or AREL expressions in Rails3). So in the worst case, we have to express the same specification in two different ways.

Enforcing permissions

When handling permissions it is critical that they are actually checked. When they actually need to be checked depends heavily on the permission itself.

Let's first focus on single objects. We can basically distinguish the 4 basic CRUD operations, which means we have one read operation and 3 different write operations (create, update, delete).

Write Operations

Write operations can easily be checked just before changes are actually written to the database (e.g. as part of object validation).

Read operations

When to validate the read permission is a bit harder. I see basically 2 variants when to check those.

The first would be to check permissions at the transition from controller to view. Unfortunately, this might be too late, depending on how the model object is accessed or transformed in the controller. We would either have to traverse the complete object graph of all objects passed from the controller to the view and check permissions of each of them or implement a complex tainting system. There, read permission checks could be enforced if an attribute is accessed in view code, but not in controller code.

Both of the variants are hard to implement and have a few gaping holes nevertheless. The biggest issue is that objects could be serialized to XML or JSON before it even reaches any view code. Or there could be even just a new attributes extracted.

All in all, this sound way too complex and insecure.

The second approach would be to directly check permissions after fetching them from the database, as part of the find or reference traversal on objects. This approach would imply that it is impossible to read objects from the database layer when the current user doesn't has read-permission for it which sounds like a rather secure approach. But it also has a few issues.

How to bootstrap authentication information? This would probably require that user, group, and permission information can be read (rather) unrestricted.

It also restricts the use-case of complex data aggregation in Ruby code, i.e. when the user could see sums of a certain granularity, but not the individual objects, for example in a complex reporting environment. When read permissions are enforced before the controller can get the data to aggregate it, this doesn't work.

We would need a way to gradually turn of read permission checking in a controlled way. That would require extreme caution by the programmer to not let unrestricted objects pass to the user agent. This could be partly mitigated with requiring strict programming guidelines. Another alternative could be to only allow unrestricted read-access in a kind of sandbox (like a block). Objects could be restricted to only pass outside of that block when they are untainted in some way. However, this would still not disable passing of certain attributes to the outside world.

Remaining Issues

  • check context (@project, ...)
    • is this actually an issue? The model should be absolutely clear about their state for a given user.
  • link_to_if_authorized for arbitrary locations?
    • Check general read right when I set the link (issue.allow_read_by(User.current) or Issue.allow_read_by(User.current))
  • emulate/adapt *_path style methods

Replies (4)

RE: [Proposal] New Permissions - Added by Holger Just at 2011-05-04 05:34 pm

What's obviously missing from my writeup is the question where and how to check permissions for objects we have not yet retrieved from the database.

Here we basically need to transform all the requirements to SQL conditions. The rest of the stuff (especially the issues with read-permissions) applies the same as above, but even more so when we start to use more aggregation functions.

RE: [Proposal] New Permissions - Added by Chris Woerle at 2011-09-26 10:04 am

Hi Holger et. al.

We are currently working on some specific issues with permissions and try to figure out, what's needed and what could be done conformly with chiliproject.

I shortly write down, what we think, even if it duplicates, what's said above.

Our Goals

  • make sure, that permissions are checked everytime a resource is called, even if it's find_by_id
  • remove the project level permission scope and go forwards
  • adding the ability to give permissions for every single item and every single user
  • remove the need to check permissions in the database (though that lower performance) and instead
  • make it possible to define permissions complex, in ruby
  • Come to a point, where we can give permissions for parts of an item (such as specific issue properties)

Libraries, we would use

We currently seem to decide for this one:
https://github.com/makandra/consul because we know it and use it often and it's simple and flexible.

We could compare it with declarative_authorization, that would be good.

Our proposal for the prototype

We create an own branch from chiliproject/unstable and do exactly this

  • create one 'Power' (the thing in consul handling the scopes) for at first issues
  • make sure, that Issue.visible (or a different scope) is called everytime, we retrieve a collection
  • make sure, that we (can) pass in everyting we need, instead of just the current project
  • the hard part replace every call on .find

General Issues and Annotations

  • We would decide against checking permissions in the views, but we thought about a helper, that would deal with the case of nil (or flagged as 'denied') attributes in a way, where the view can remain as it is, but just does not display, what it cannot see (instead of raising basically)
  • we have a branch, where we have overridden 'find', it works basically, but we don't like it, do we all agree, that we don't want this?
  • We also agreed, that certain 'complex aggregations' are being runned without checking permissions (due to the reasons you mention above) and we focus on the restriction of the display of the result
  • We would rather create a Context - class, where we can easily add different things, even in a before filter, with the advantage in mind, that we never ever have to touch any of the object retrievers, such as .find_visible(params[:id],current_project,current_whatever). Instead it should be .find_visible(arg,context)

RE: [Proposal] New Permissions - Added by Frédéric LEUBA at 2012-08-24 12:44 am

Hello, what's the state of that new permission system ? It is getting a pretty old discussion now, we would expect to see something coming. Thanks

(1-4/4)