Most efficient way to determine CouchDB access permission - couchdb

I'm using the CouchDB permission system with per-db-and-user access rights. Each DB represents an app, which are being displayed in a home-screen-like overview and in other places. I need an efficient way to make CouchDB tell me whether a user has access to a db or not - for example a GET /_all_dbs that only returns the DBs for which current user has access. Polling a view or document turns out to be too slow once there are more than a dozen or so apps to display on one page, although I could still tune a view poll with limit=1. Isn't there a better way though?

Query the _security document of the database.
curl http://localhost:5984/db_name/_security
{"admins":{"names":["dbadmin"],"roles":["reader"]},"members":{"names":[],"roles":[]}}
For every database that has admins/users couchdb has a creates a special document called _security that holds a list of all the users for that database. You can make a curl request to that document and get an array that will give you all the admins and members for that database.
Edit
You know your application best but here is a strategy that I think could be helpful? Every couchdb user is stored in the _users database. It is just like any other database. You can create a view on it and then query it. You can even add additional fields to the documents to help with querying. How about when you create a user on a database you update the corresponding document in the _users database as well.
Now if you call _users/_all_docs?include_docs=true you get a list of users along with the databases they have access to. One request and you have everything you need.

Related

PouchDB/CouchDB usage/schema for user data

I'm using PouchDB + CouchDB to store and sync data in an angular app currently in development. Data is stored per user and contains things such as user authorities/settings, recently viewed content and cart items.
Currently, I have a single CouchDB database that contains a doc for each user. While this structure works well for quickly retrieving user-specific data, it's logically flawed because all user docs are synced to any device that accesses the app. In other words, I ultimately only need the currently logged in user's data to sync.
So, my question is, should I create a Couch database for each user instead of using a single database with a doc for each user? Or is there a better way to go about this?
If you look at the pouchdb-authentication plugin you'll see that you can store metadata for a user in the _user database. That might be all you need.

How can I prevent users to read and write from or into respectively from my CouchDB database?

I don't want other users to see my database and documents inside it. There is something read/write privilege to users. I don't have clear picture about it.
If you want to hide the database names you have to use a proxy server in front of the CouchDB.
If it's ok to see the names of the DBs but the doc read access should be restricted - you can use the security settings of each DB.
A more granular write access control is enabled by using the validate_doc_update function of a design document (which you have to create inside a db by your own).

CouchDB simple document design: need feedback

I am in the process of designing document storage for CouchDB and would really appreciate some feedback. These documents are to represent "assets".
These databases will also be synced locally to the browser via pouchdb.
Requirements:
Each user can have many assets
Users can share assets with others by providing them with a URI such as (xyz.com/some_id). Once users click this URI, they are considered to have been "joined" and are now part of a group.
Group users can share assets of their own with other members of the group.
My design
Each user will have his/her own database to store assets - let's call it "user". Each user DB will be prefixed with the his/her unique ID.
Shared assets will be stored in a separate database - let's call it "group". shared assets are DUPLICATED here and have an additional field for userId (to indicate creator).
Group database is prefixed with a unique ID just like a user database is prefixed with one too.
The reason for storing group assets in a separate database is because when pouchdb runs locally, it only knows about the current user and his/her shared assets. It does not know about other users and will should not query these "other" users' databases.
Any input would be GREATLY appreciated.
Seems like a great design. Another alternative would be to just have one database per group ("role"), and then replicate from a user's group(s) into their local PouchDB.
That might get hairy, though, when it comes time to replicate back to the server, because you're going to have to filter the documents as they leave the user's local database, depending on which group-database they belong to. Still, you're going to have to do that on the server side anyway with your current design.
Either way is fine, honestly. The only downside of your current approach is that documents are duplicated on the server side (once per user-db and once per group-db). On the other hand, your client code becomes dead-simple, because you don't have to do any filtered replication. If you have enough space on your server not to worry about it, then I would definitely go with your approach. :)

How to include CouchDB _users DB properties into another DB's view?

I am adding more user profile information to the _users DB in CouchDB. This includes things like first name, last name, etc. This works fine and I'm able to store additional profile information.
How do I get that profile information to be linked in (joined) from another DB's view map function? That is, each document has an author or user field which records the user that created the document. How do I get other profile information about the user included in the view created for this DB?
Unfortunately, you won't be able to join documents across different databases. The closest thing you can have to that is creating copies of user profile information inside your other database, and perhaps using replication to keep that information synchronized.
I'm not sure if there are any plans to have special databases like _users behave differently, but I'm sure there are enough use-cases to make it a worthwhile endeavor. However, there is no mention of this (as far as I've seen) in the Wiki or anywhere else of note.

CouchDB - prevent unauthorized reads

CouchDB has a mechanism in place to prevent unauthorized writes.
Can it also prevent unauthorized reads?
Yes, CouchDB can prevent unauthorized reads. Unfortunately, it is slightly less straightforward.
Imagine a secret auction application. You bid $20 and I bid $10; each bid in a couch document. Couch lets us read our own bid documents but no others. However, there is a map-reduce view showing the average. I load the view and see that the average is $15, so I conclude that your bid is $20 and I have broken the security policy. View output can leak some or all of a document's information. It is not feasible to enforce security at the document level. That is why read access is at the database level.
I know, it sucks. But that is the only correct, scalable answer.
This is part of the reason the Couch philosophy is to create many databases—even one (or more!) per user. Read permission to a database is set in the readers value of the database _security object. (Note, the field readers was renamed to members in CouchDB trunk because it also specifies who may write to the DB.)
The technique works like this:
Create a database for each user. It will hold all documents the user may read. Add the user (or the user's role) to the _security object.
In the master database, create a filter function which implements the read policy. (It could share code with validate_doc_update.)
Replicate from the master database to the user's database with ?filter=my_filter_function.
Allow the user to load (or replicate from) their database.
Of course, this is all for a pure Couch application, where users access Couch directly. If you have a middle layer (MVC controller, or just a reverse HTTP proxy), then you can enforce policy there, between the user and the couch. But be careful. For example, a _show function or a _rewrite rule might allow a user to load a view or document despite your policy.
Good luck!

Resources