couchdb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Brian Candler <B.Cand...@pobox.com>
Subject Re: DB ACLs (was Re: 0.11 Release / Feature Freeze for 1.0)
Date Sun, 07 Feb 2010 09:19:28 GMT
On Sat, Feb 06, 2010 at 10:52:57AM -0800, Chris Anderson wrote:
> I'd be pretty surprised if the ACLs that ship with 0.11 are
> significantly different from what I committed last week.

I thought so, which is why I haven't coded up any alternative in erlang.

> Can you explain your application needs? I'm pretty sure that the
> current ACLs can support them. But if you have a common use case falls
> out side what can be done with readers / admins / validations, maybe
> there are minimal tweaks we can do to make it easier for you.

OK. Let me start by outlining what I have now; you'll see that in many ways
this *does* align well to couchdb's new security model.

>From the user's point of view
-----------------------------

A user signs up for a database. They are its initial administrator.

They can grant access to other users. As well as read access, they can
grant:
   [X] Update
   [X] Admin
rights to those other users. "Update" allows database writes, and "Admin"
allows adding new users and changing their update/admin rights flags. I plan
to make "Update" more granular in future.

For safety, an admin cannot remove themselves, nor change their own rights
flags.  They have to ask another admin on the database to do it for them. 
That's so that databases can't end up being accidentally orphaned, without
any administrator, which would be a dead-end situation.

When you login as a user, you could have access to multiple databases.  In
that case you are given a list to choose from.

For audit purposes, all saves automatically update the "updated_by" and
"updated_at" fields (with username and timestamp respectively).  This is
enforced for "Update" users.  However an admin user is allowed to import a
CSV file containing "updated_by" and "updated_at" columns, and those
uploaded values are honoured.  That is to make it possible to accurately
restore a database from a CSV file.

So, an admin user could destroy the audit information if they wanted to, but
regular update users cannot.

The current implementation
--------------------------

Each database is a separate couchdb database, with all mediation via a Rails
app.

There is a global authorisation database with "User" and "Db" docs.

"User" contains usernames and passwords, and system-wide prefs for that user
(e.g. timezone)

There is one "Db" doc per database, and its id is the same as the database
name. It contains
  {
    "authz":{
      "user1":[],
      "user2":["admin"],
    }
  }
plus database-level preferences. By putting these docs in the global database
rather than the databases to which they refer, I can use a view to find all
databases that a user has access to.

These docs give me what _readers, _admins and _security will provide.

Issues with changing to couchdb native features
-----------------------------------------------

(1) I could implement the "update" right in couchdb using the _security
document, perhaps putting something like

  {"updaters":{
    "names":[],
    "roles":[]
  }

to be similar to _readers and _admins. This means that the authz info is
spread across three places.  In futon you either won't be able to set the
"update" right at all, or you'll have to do it in a completely different way
to readers and admins.

(2) In couchdb, an "admin" confers two distinct rights: the ability to change
rights on the database, and the ability to modify design docs.  My "admin"
right is only the first of these.

So I have to either: (a) bite the bullet and let admin users be full
database admins too, or (b) implement a more restricted "manager" right
myself.  This would require and external process sitting in front of
couchdb, which ran with admin rights, and mediated requests for adding and
removing users and rights.

This would not be necessary if the access controls were in a "real" doc,
because I could use validate_doc_update to limit who could add what access
(in the same way as validate_doc_update already works in the _users
database)

(3) There's no concurrency control on _readers, _admins or _security. It
*will* break if two people try to change them at once.

Again, the workaround is for me not to grant any real database _admins, but
have a front-end manager process which performs these changes.  The
front-end will need to contain a mutex to serialise these requests.

(4) I am currently backing up the system just by dumping _all_docs, and
there's enough info to restore the whole system from there.  It's line-based
and git-packs nicely.

However once there are hidden _reader, _admin and _security resources, those
will have to be backed up separately for each database.

(5) I won't be able to use _all_dbs to show what databases the user has
access to, either because it will show to much, or because it will be
blocked to non-server-admins.

This isn't a huge problem if I ask the user to type in the database name
they want to access the first time they use it, and then I store it in some
sort of persistent cache, so that next time they can select it from a list.

A spare field in their _users database entry would be the obvious place, but
it's not clear if this will be allowed going forward.
 
(Futon uses a persistent cookie, I believe, which wouldn't work well for me
because a user switching to a different browser or PC would lose the list of
databases they had access to. Maybe using _users for the list of recent
databases would be better for futon too).

(6) Other privacy issues as described before: I don't want user A to see
that user X exists on the system, and certainly not to see their encrypted
password.  Furthermore I don't want user A to know the names of any
databases that they don't have access to.

I can workaround the first by blocking read access to _users and
implementing privileged services in front for changing passwords and
preferences. The second requires me to put couchdb behind a HTTP reverse
proxy, unless _all_dbs becomes an admin-only resource as has been proposed.

(7) Timestamps are slightly awkward. I can update timestamps in an _update
function, but not prevent users from going direct to the database.  The best
I can think of is to add a second layer of checks in validate_doc_update:
for example, that the "updated_at" timestamp must be plus or minus two
minutes from the current time, and "updated_by" field must match the
userctx.name.

So in summary, the main points are:

* I can't trust end-users to be _admins, because there are too many ways
  they can shoot themselves in the foot, and couchdb doesn't provide
  validate_doc_update level of control. Result: I have to build external
  processes to mediate admin-type requests, and document the APIs.

* It's all just rather messy. To check if they're an _admin I need to look
  in userctx. To check if they have update rights I need to look in the
  _security resource. To enable access to the database I need to list them
  in the _readers resource.

Regards,

Brian.

Mime
View raw message