couchdb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Chris Anderson <jch...@apache.org>
Subject Re: A thought: view access controls
Date Wed, 20 Jan 2010 18:09:31 GMT
On Wed, Jan 20, 2010 at 3:23 AM, Brian Candler <B.Candler@pobox.com> wrote:
> There has been discussion in the past on the (hard) problem of providing
> view access controls, i.e. leakage of view information where the user
> shouldn't be able to see it.
>
> I thought of a solution, which is efficient and reasonably simple and may
> be good enough for most uses.
>
> For those views which care about access, they could prefix the emitted keys
> with a tag for the user and/or role intended to see them.  Then at query
> time they would map the userCtx to permitted key ranges, and then couchdb
> would intersect the range of requested keys with the range of permitted keys
> for this user.
>
> We need a way of representing multiple ranges of keys (which is a query
> feature we've wanted anyway). Let's say for simplicity:
>
>    ranges = [[startkey1,endkey1], [startkey2,endkey2], ...]
>
> Then a view access control function might map a userCtx (containing user
> "fred" role "manager") to:
>
>    [[["u:fred"],["u:fred",{}]], [["r:manager"],["r:manager",{}]]
>
> meaning that the reader could only access keyspace within those ranges.
>
> Views would then emit rows with suitable keys, e.g.
>    ["u:fred", "a tale of two cities" ]
>    ["u:jim", "emmanuel returns" ]
>    ["r:reader", "daily telegraph" ]
>    ["r:manager", "oxford english dictionary" ]
>
> A client would have to build queries with the keys suitably prefixed, which
> could be handled in a client-side library or could be done server-side.  For
> example, if fred is looking for books beginning "a tale of", then the query
> to submit would be:
>
>   [
>    [["u:fred","a tale of"],["u:fred","a tale of",{}]],
>    [["r:reader","a tale of"],["r:reader","a tale of",{}]]
>   ]
>
> Finally couchdb needs to take this view query and intersect it with the
> permitted key ranges, and either silently truncate, or raise an error if the
> query tried to access outside of its allowed key ranges(s). That ensures
> that fred can't see which books are private to jim.
>
> There are many variants of query, but they could all be mapped to the ranges
> form first, to make it easy to intersect them.
>
>  key="foo"                     =>  [["foo","foo"]]
>  startkey="bar"&endkey="foo"   =>  [["bar","foo"]]
>  {keys:["foo","bar","baz"]}    =>  [["foo","foo"],["bar","bar"],["baz","baz"]]
>
> It sounds complicated when written down, but actually I think it should be
> fairly simple to implement.  It delegates the question of authorisation to
> the view designer, without breaking view building and query efficiency.
>
> Thoughts?

I think this is by far the simplest solution. It does have a lot of
space overhead (if you have rows that are readable by lots of distinct
roles/users).

This would probably be a design doc option:

view_access_control : {
  foo : true,
  bar : false
}

(in this case protect the "foo" view with the scheme Brian's described.)

The issues that make this tough are the space overhead, and the fact
that it could be easy to make a mistake and think you are more secure
than you are. (Eg, by accidentally having different doc-level security
than role-level security).

It's worth thinking about if this view-row security is useful in the
absence of per-document reader ACLs.

My guess is that we'd want to have them both, and maybe do something
like have a scopedEmit() function that knows how to emit N times, once
for each user in the document's ACL list.

I highly doubt doc-level or view-row level security will end up in
1.0, as we don't even have an implementation yet. That doesn't mean
it's not worth pursuing for post-1.0.

Also, if I were going to answer similar requirements, I'd do it with
filtered replication, which will be in 1.0. This way you could use a
filter to create a db-per-user that has just the documents they are
allowed to see in it. Then you don't have to do any fanciness in the
views.

Filtered replication to a db-per-user has the same space-inefficiency
problem that building a user-segmented view index has, but with more
benefits (users can write custom views, replicate data locally, etc),
so I'd pick it over the lots of users in one db approach.

Of course filtered replication means you need to verify / require the
use of particular filter functions. I'd be interested in thoughts
about how to do that in a standalone Couch way.

Chris

>
> Brian.
>
> P.S. I'm aware of the 'inclusive_end' issue (couchdb-194).
>
> Also, I realise that ["u:fred",{}] comes before ["u:fred",{"an":"object"}].
> However, applications which want to emit an object as a key can do so by
> wrapping it in an array:
>    ["u:fred",[{"an":"object"}]] # comes before...
>    ["u:fred",{}]                # ...the end key range sentinel value
>
> "Key prefixes" would be nice, if they were carefully designed to allow for
> array prefixes as above. In fact, unifying with group and group_level would
> be very cool.
>



-- 
Chris Anderson
http://jchrisa.net
http://couch.io

Mime
View raw message