I want to store users' private information on a CouchDB in Cloudant - i.e. each user should be able to read and update only his own document. Usually such information is saved in the _users db, but I really liked Cloudant's API keys and don't want to manage users and passwords myself.
I found several solutions in this wiki: http://wiki.apache.org/couchdb/PerDocumentAuthorization but they all had limitations:
- "Database per User" is really annoying to manage.
- "Smart Proxy" takes the fun out of CouchDB and CouchApps.
- "Document encryption on a per user basis" is way too complicated.
Then I figured out a new solution - I created a database (called "test") and configured all the users as _writer
s, without any _reader
s.
To prevent users from writing over each others documents, I set validate_doc_update
in my _design/app
to:
function(newDoc, savedDoc, userCtx) {
if ((userCtx.roles.indexOf('_admin') < 0) && (userCtx.name != newDoc._id)) {
throw ({unauthorized: "cannot access others"});
}
}
To let the users' read their own document, I wrote the following update function (called "update_hack"):
function(doc, req) {
return [doc, toJSON(doc)];
}
Now, every user can "get" his document by sending a POST request to:
http://<username>:<password>@<host>/db/_design/app/_update/update_hack/<username>
If the user tries to send a POST request to a document of a different user, say:
http://<username>:<password>@<host>/test/_design/app/_update/update_hack/someoneelse
then he'll get an {"error":"unauthorized","reason":"cannot access others"}
response for trying to "update" the document.
There is some inefficiency in this trick because every time a user "gets" his document, the revision of the document has to change. There is also the issue of realizing whether a username exist or not by sending POST requests (if the document does not exist, a "null" will be returned).
Do you see any security flaws in this trick?
Is there a better way to store private document per user when the users are generated via API keys? (Even if there is, I still think that my trick is cool).