Return-Path: Delivered-To: apmail-couchdb-dev-archive@www.apache.org Received: (qmail 12892 invoked from network); 13 Sep 2009 06:08:26 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 13 Sep 2009 06:08:26 -0000 Received: (qmail 98183 invoked by uid 500); 13 Sep 2009 06:08:25 -0000 Delivered-To: apmail-couchdb-dev-archive@couchdb.apache.org Received: (qmail 98088 invoked by uid 500); 13 Sep 2009 06:08:25 -0000 Mailing-List: contact dev-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list dev@couchdb.apache.org Received: (qmail 98078 invoked by uid 99); 13 Sep 2009 06:08:25 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 13 Sep 2009 06:08:25 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of jchris@gmail.com designates 209.85.216.181 as permitted sender) Received: from [209.85.216.181] (HELO mail-px0-f181.google.com) (209.85.216.181) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 13 Sep 2009 06:08:13 +0000 Received: by pxi11 with SMTP id 11so1682645pxi.17 for ; Sat, 12 Sep 2009 23:07:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:sender:received:in-reply-to :references:date:x-google-sender-auth:message-id:subject:from:to :content-type:content-transfer-encoding; bh=6v4GrbRL7k/zHypULnGVdP8wWTvCy45e4GuQ6majLRA=; b=TXreAfEVnCTkx09x8EtJcoYfGxLbyRbl393Vg1LQ8IybAadeY9o+DaSXQ+TrCw1Oyw aenm5pDw2IPsVZQM1p413wFvZllVIqaklbuG3YhFCXfuKfcll3gcaZvc/wSeDv9nBLK/ S/0LOY/96ohOPVYIqXyc0q5UoslfdDuKXYknM= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:content-type :content-transfer-encoding; b=P/MIB0Nju0sakQcM9l9kDCKt60oUZajsD/z2CXNLYXz8xT508BJ7R1ZvouBSyMTm73 aZSRTJ5fSCZYowG2KLvZo5nTfuYRN1sIGlmWUWL9T81oDjGm7h0W5NCRWuflpH2PaJag P0O/eyakyHbQTZ9oZ7ctbiwfCKJ5dnDmHjVqw= MIME-Version: 1.0 Sender: jchris@gmail.com Received: by 10.140.128.12 with SMTP id a12mr822745rvd.283.1252822072216; Sat, 12 Sep 2009 23:07:52 -0700 (PDT) In-Reply-To: <8989606E-3CAF-42C9-9935-FCAC0FAD81D3@apache.org> References: <8F048321-4C3C-424C-8FC4-0C99354AB728@jasondavies.com> <8989606E-3CAF-42C9-9935-FCAC0FAD81D3@apache.org> Date: Sat, 12 Sep 2009 23:07:52 -0700 X-Google-Sender-Auth: 208c018892a9a02e Message-ID: Subject: Re: Per-DB Auth Ideas and Proposal From: Chris Anderson To: dev@couchdb.apache.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Virus-Checked: Checked by ClamAV on apache.org On Fri, Sep 11, 2009 at 6:43 AM, Jan Lehnardt wrote: > Hi, > > thanks Jason for starting the discussion here. The summary looks great. > >>> On 8 Sep 2009, at 00:50, Jason Davies wrote: >> >>> >>> 6. Future work: thisfred suggested that the pattern-matching could be >>> extended to the full URL instead of just the database name. =A0This see= ms like >>> a simple way to extend authorization. =A0Of course, it's dependent on a >>> particular node's URL mappings (these can be changed in the .ini). =A0T= his >>> then brings up the question of what the operations should be, it would = make >>> the most sense to let them be HTTP verbs, so that one could restrict ac= cess >>> to certain URLs to being only GET and HEAD for example. =A0This seems a= bit >>> too tied to HTTP for my liking, but I guess CouchDB is very much a REST= ful >>> and therefore HTTP-reliant database. =A0Any further ideas would be welc= omed. >> >> Chris Anderson: >> >> I think building RESTful assumptions into our default authorization >> model is perfectly reasonable. I agree the tie to HTTP is a smell, but >> I'd call it a good smell. > > The only nagging thought that keeps popping up in my head is that users > might think of read access as granting GET. But then we use POST for > multi-key get in views. Just something to be aware of I guess. > > On 9 Sep 2009, at 00:41, Adam Kocoloski wrote: > > >> On Sep 7, 2009, at 6:50 PM, Jason Davies wrote: >> >>> Hi all, >>> >>> There have been sporadic discussions about various granularities of >>> authorization. =A0The most simple level to tackle is per-db authorizati= on. >>> =A0What follows is a summary of discussions and ideas so far. >>> >>> I should point out that this is primarily to flesh out the default >>> authorization modules that address the needs of the majority of users. = =A0We >>> probably will have an authorization_handlers settings, analagous to >>> authentication_handlers, allowing custom authorization modules to be us= ed. >>> >>> 1. Where are the permission "objects" themselves stored? =A0The permiss= ions >>> determine which users can do what with each database. =A0I think storin= g these >>> in the per-node users database (called "users" by default) makes the mo= st >>> sense. =A0We are talking about per-db auth so it wouldn't make any sens= e to >>> store this information in the affected databases themselves. >> >> I think it's actually pretty sensible to store some authz information in >> the DB itself, for many of the same reasons outlined by Brian and Benoit= . >> =A0The big exception there is the ability to create new DBs. =A0That's >> traditionally the task of a server admin, but perhaps we could come up w= ith >> some special role that could be granted to users to allow them to do tha= t. > > +1 > >>> 2. What types of operations do we need to support? =A0I think the major= ity >>> of users will only care about being able to make particular databases >>> read-only, read/write, or write-only (not sure about the latter one). >> >> I think write-only is a keeper. =A0It may also be useful to distinguish >> between creating new documents and updating existing ones. =A0For instan= ce, >> SQL GRANT tables distinguish between INSERT and UPDATE. > > > validate_doc_update =3D function(doc, req) { > =A0if(doc._rev) { > =A0 =A0// handle update > =A0} else { > =A0 =A0// handle insert > =A0} > } > > Am I missing something? > > >>> 6. Future work: thisfred suggested that the pattern-matching could be >>> extended to the full URL instead of just the database name. =A0This see= ms like >>> a simple way to extend authorization. =A0Of course, it's dependent on a >>> particular node's URL mappings (these can be changed in the .ini). =A0T= his >>> then brings up the question of what the operations should be, it would = make >>> the most sense to let them be HTTP verbs, so that one could restrict ac= cess >>> to certain URLs to being only GET and HEAD for example. =A0This seems a= bit >>> too tied to HTTP for my liking, but I guess CouchDB is very much a REST= ful >>> and therefore HTTP-reliant database. =A0Any further ideas would be welc= omed. >> >> So, after giving this some thought I'm partial to the idea of Access >> Control Lists. Instead of directly granting privileges on databases in t= he >> users DB, we'd store an ordered list in the DB in a special document tha= t >> would allow|deny requests that match a rule. =A0For instance, if I wante= d to >> make a read-only DB where only I could access the _design documents I co= uld >> upload a document like >> >> { >> =A0 _id: "_authorization", >> =A0 _rev: "1-1340514305943", >> =A0 _acl: [ >> =A0 =A0 =A0 {"access":"allow", "role":"kocolosk", "method":"*", =A0 "pat= h":"*"}, >> =A0 =A0 =A0 {"access":"deny", =A0"role":"*", =A0 =A0 =A0 =A0"method":"*"= , >> "path":"_design*"} >> =A0 =A0 =A0 {"access":"allow", "role":"*", =A0 =A0 =A0 =A0"method":"GET"= , "path":"*"}, >> =A0 =A0 =A0 {"access":"deny", =A0"role":"*", =A0 =A0 =A0 =A0"method":"*"= , =A0 "path":"*"} >> =A0 ] >> } >> >> The rules in the ACL array are applied in order, and the first rule to >> match wins. =A0Here I've assumed that my user has a corresponding role, = like a >> UNIX group. > > > I like the ACLs. We can parse the JSON into Erlang matching patterns once > and and use then from there. I'd prefer that over Brian's possible soluti= on > of having another JavaScript function for this. > > >> Benoit mentioned that he wanted authz to replicate. =A0If we decide that= 's >> the way we want to go, storing the ACL in a regular document with a rese= rved >> ID would allow for that. =A0If we didn't want it to replicate, we could = just >> change that docid to something like _local/authorization > > As with history, I could see we'd want a document type that is a hybrid o= f a > regular doc and a _local doc, say _db/ for example, that can be replicate= d > conditionally with > > POST /_replicate > {source:..,target:...,replicate_db_doc:true} > > >> We might take this one step further and allow additional Access Control >> Elements in individual documents. =A0These ACEs would be prepended to th= e DB >> ACL and would allow you to specify custom authz for a subset of document= s in >> a DB without having to resort to path-based regex and editing the DB ACL >> every time. > > Sounds complicated. -1 > > >> Finally, there's the issue of authz in views. =A0What privileges does th= e >> view indexer have? =A0If a user who is only allowed to read some of the >> documents in the DB is allowed to upload a _design document, it seems to= me >> that the views generated from that _design document must exclude any >> forbidden documents. =A0I guess this can work if the _design doc stores = the >> roles of the user who saved it. =A0It seems like a tricky, but solvable >> problem. > > So far we don't have the notion per-doc ACL's. So a user can read all doc= s > in the DB or none, but not some. If we'd go there, I think users that can > modify design docs are higher in the auth* chain than users that only can > read some documents and thus inherit the role of read-all-docs. > > What are the next steps? > I think a per-doc reader ACL is a fine place to start. If a doc has an element like { "_id":"football playbook", "_rev":"2-a24d12b", "access" : { "roles" : ["players"], "users" : ["coach"] }, } or maybe "access" isn't the best name, but the idea should be clear enough I played around with read & write access lists but write can be handled by the validation function so it's not necessary. The only reason we have to standardize this stuff at all is to avoid a Spidermonkey call on read, so we can keep it as simple as possible. I also thought about adding allow/deny so that eg, everyone but Joan could see Joan's surprise party invitation. But that seems to wreck havoc with any kind of sane way to make security work with views. The other option is to require views be calculated on the client, which means you can punt on view security, and just let read-security handle it during replication. Chris > > Cheers > Jan > -- > > --=20 Chris Anderson http://jchrisa.net http://couch.io