3👍
Overview
Couchdb has one overriding level of administrator setup in configuration instead of setup in the _users
database and assigned the _admin
permission to prevent any possibility of being locked out.
Each individual database then has a rough level security policy of 2 levels:
- admins
- members
specified via:
- names
- roles
making 4 fields.
These levels control access slightly differently for the 2 types of documents a db can contain:
- id:
_design/*
– Design documents can contain functions that will be executed in some context - id:
other
– Normal documents are just normal data
Both levels of database access have read access to all documents in the database, but admins have write access to _design documents. Write access to normal documents is usually given to all users granted any access to the db, but can be limited by validate design documents.
To Summarize
The process for setting a unique security policy up is:
- Experience the provided validate design document as a consumer while setting up _users.
- Setup a new database and its basic security giving your users member access.
- Add a design doc to the new database with a validate function that restricts member write access.
1 Setting up _users entries
Add a role to a user
As an admin add role: ["logger"]
to a user’s doc and save it, note that this must be done by admin due to this part of the default _users design document:
// DB: _users doc: _design/_auth
function(newDoc, oldDoc, userCtx, secObj) {
..
if (oldRoles.length !== newRoles.length) {
throw({forbidden: 'Only _admin may edit roles'});
}
Change the password for the user.
Either the admin or the user can change their password by setting password:"mynewpassword"
in their document (which couchdb will transform into a hashed/salted password during the save process). This works for a user since they can add/modify fields aside from their name and roles, as long as a user is editing their own doc:
// DB: _users doc: _design/_auth
function(newDoc, oldDoc, userCtx, secObj) {
..
if (userCtx.name !== newDoc.name) {
throw({
forbidden: 'You may only update your own user document.'
});
}
// then checks that they don't modify roles
You could repeat this process with a user you assign an adminlogger
role to create a delegated administrator that you assign permissions to can reconfigure a database or you can continue to use the couchdb admin with its _admin
role for all administration.
2 Setup a new database and its basic security
Create a db named logger
assign the logger a security policy:
{
"admins": {
"names": [
],
"roles": [
"adminlogger"
]
},
"members": {
"names": [
],
"roles": [
"logger"
]
}
}
3. Create a new validate design document in the new db
As either _admin user or a user with the adminlogger
role create a new validate design doc by copying the _users design document, removing the _rev and modifying the function:
// DB: logger doc: _design/auth
function(newDoc, oldDoc, userCtx, secObj) {
// Don't let non-admins write a pre-existing document:
if (!is_server_or_database_admin()) {
if (!!oldDoc) {
throw({
forbidden: 'You may not update existing documents.'
});
}
}
// Where the function to define admins can be copied verbatim from the doc:
var is_server_or_database_admin = function(userCtx, secObj) {
// see if the user is a server admin
if(userCtx.roles.indexOf('_admin') !== -1) {
return true; // a server admin
}
// see if the user a database admin specified by name
if(secObj && secObj.admins && secObj.admins.names) {
if(secObj.admins.names.indexOf(userCtx.name) !== -1) {
return true; // database admin
}
}
// see if the user a database admin specified by role
if(secObj && secObj.admins && secObj.admins.roles) {
var db_roles = secObj.admins.roles;
for(var idx = 0; idx < userCtx.roles.length; idx++) {
var user_role = userCtx.roles[idx];
if(db_roles.indexOf(user_role) !== -1) {
return true; // role matches!
}
}
}
return false; // default to no admin
}
}
If you followed these steps then the user you gave the logger role in step 1 can run your code to write new documents only in logger database configured in steps 2 and 3.