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?
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.