CouchDB write/read only (no edit) user












3















Toolchain/frameworks



I'm using django==2.1.3 and python-cloudant==2.1.3 and running CouchDB ver. 2.2.0, and pretty much doing all of my setup/configuration through Fauxton. I like to think that I know my way around python/django in general, and I'm testing this approach in a small little project to see how it works



Problem Description



Suppose I have a fairly simple CRUD application with just 1 model:



class Asset(models.Model):
asset_id = models.CharField(max_length=32)
asset_name = models.CharField(max_length=32)


and I have a view that I use to create the asset



class CreateAssetView(views.View):
def get(self, request, *args, **kwargs):
#some code here


def post(self, request, *args, **kwargs):
#some code here|
#log request data into database
client = CouchDB('myusername', 'mypassword', url='http://127.0.0.1:5984', connect=True)
db = client['assets']

log_data = {'view_name': self.view_name, 'post_data': post_data,'user': request.user.username,
'time': str(timezone.now())}
db.create_document(log_data)
return render(...)


I understand that I should be doing the logging portion using a middleware (which I plan to) and probably just use django's CreateView in that case, I'm doing this approach for now just during early development.



What I'm having a problem wrapping my head around is creating a user with myusername and mypassword that has the permissions to:




  1. Write new documents

  2. Read old documents


  3. not edit already created documents


I could even settle for 1 and 3 only (and only use admin to read). I spent a little bit of time playing around with Fauxton's interface for permissions, but I can only basically create a user and assign a role (couldn't even get to assigning a password :/)



clarification



The Asset is not a CouchDB document, that's a normal SQL model, I only want to dump the logs with post data to CouchDB



Any help/gudiance/documentation pointers would be really appreciated










share|improve this question





























    3















    Toolchain/frameworks



    I'm using django==2.1.3 and python-cloudant==2.1.3 and running CouchDB ver. 2.2.0, and pretty much doing all of my setup/configuration through Fauxton. I like to think that I know my way around python/django in general, and I'm testing this approach in a small little project to see how it works



    Problem Description



    Suppose I have a fairly simple CRUD application with just 1 model:



    class Asset(models.Model):
    asset_id = models.CharField(max_length=32)
    asset_name = models.CharField(max_length=32)


    and I have a view that I use to create the asset



    class CreateAssetView(views.View):
    def get(self, request, *args, **kwargs):
    #some code here


    def post(self, request, *args, **kwargs):
    #some code here|
    #log request data into database
    client = CouchDB('myusername', 'mypassword', url='http://127.0.0.1:5984', connect=True)
    db = client['assets']

    log_data = {'view_name': self.view_name, 'post_data': post_data,'user': request.user.username,
    'time': str(timezone.now())}
    db.create_document(log_data)
    return render(...)


    I understand that I should be doing the logging portion using a middleware (which I plan to) and probably just use django's CreateView in that case, I'm doing this approach for now just during early development.



    What I'm having a problem wrapping my head around is creating a user with myusername and mypassword that has the permissions to:




    1. Write new documents

    2. Read old documents


    3. not edit already created documents


    I could even settle for 1 and 3 only (and only use admin to read). I spent a little bit of time playing around with Fauxton's interface for permissions, but I can only basically create a user and assign a role (couldn't even get to assigning a password :/)



    clarification



    The Asset is not a CouchDB document, that's a normal SQL model, I only want to dump the logs with post data to CouchDB



    Any help/gudiance/documentation pointers would be really appreciated










    share|improve this question



























      3












      3








      3


      1






      Toolchain/frameworks



      I'm using django==2.1.3 and python-cloudant==2.1.3 and running CouchDB ver. 2.2.0, and pretty much doing all of my setup/configuration through Fauxton. I like to think that I know my way around python/django in general, and I'm testing this approach in a small little project to see how it works



      Problem Description



      Suppose I have a fairly simple CRUD application with just 1 model:



      class Asset(models.Model):
      asset_id = models.CharField(max_length=32)
      asset_name = models.CharField(max_length=32)


      and I have a view that I use to create the asset



      class CreateAssetView(views.View):
      def get(self, request, *args, **kwargs):
      #some code here


      def post(self, request, *args, **kwargs):
      #some code here|
      #log request data into database
      client = CouchDB('myusername', 'mypassword', url='http://127.0.0.1:5984', connect=True)
      db = client['assets']

      log_data = {'view_name': self.view_name, 'post_data': post_data,'user': request.user.username,
      'time': str(timezone.now())}
      db.create_document(log_data)
      return render(...)


      I understand that I should be doing the logging portion using a middleware (which I plan to) and probably just use django's CreateView in that case, I'm doing this approach for now just during early development.



      What I'm having a problem wrapping my head around is creating a user with myusername and mypassword that has the permissions to:




      1. Write new documents

      2. Read old documents


      3. not edit already created documents


      I could even settle for 1 and 3 only (and only use admin to read). I spent a little bit of time playing around with Fauxton's interface for permissions, but I can only basically create a user and assign a role (couldn't even get to assigning a password :/)



      clarification



      The Asset is not a CouchDB document, that's a normal SQL model, I only want to dump the logs with post data to CouchDB



      Any help/gudiance/documentation pointers would be really appreciated










      share|improve this question
















      Toolchain/frameworks



      I'm using django==2.1.3 and python-cloudant==2.1.3 and running CouchDB ver. 2.2.0, and pretty much doing all of my setup/configuration through Fauxton. I like to think that I know my way around python/django in general, and I'm testing this approach in a small little project to see how it works



      Problem Description



      Suppose I have a fairly simple CRUD application with just 1 model:



      class Asset(models.Model):
      asset_id = models.CharField(max_length=32)
      asset_name = models.CharField(max_length=32)


      and I have a view that I use to create the asset



      class CreateAssetView(views.View):
      def get(self, request, *args, **kwargs):
      #some code here


      def post(self, request, *args, **kwargs):
      #some code here|
      #log request data into database
      client = CouchDB('myusername', 'mypassword', url='http://127.0.0.1:5984', connect=True)
      db = client['assets']

      log_data = {'view_name': self.view_name, 'post_data': post_data,'user': request.user.username,
      'time': str(timezone.now())}
      db.create_document(log_data)
      return render(...)


      I understand that I should be doing the logging portion using a middleware (which I plan to) and probably just use django's CreateView in that case, I'm doing this approach for now just during early development.



      What I'm having a problem wrapping my head around is creating a user with myusername and mypassword that has the permissions to:




      1. Write new documents

      2. Read old documents


      3. not edit already created documents


      I could even settle for 1 and 3 only (and only use admin to read). I spent a little bit of time playing around with Fauxton's interface for permissions, but I can only basically create a user and assign a role (couldn't even get to assigning a password :/)



      clarification



      The Asset is not a CouchDB document, that's a normal SQL model, I only want to dump the logs with post data to CouchDB



      Any help/gudiance/documentation pointers would be really appreciated







      python django nosql couchdb python-cloudant






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 20 '18 at 1:33







      robotHamster

















      asked Nov 20 '18 at 1:25









      robotHamsterrobotHamster

      343216




      343216
























          1 Answer
          1






          active

          oldest

          votes


















          1





          +50









          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:




          1. admins

          2. members


          specified via:




          1. names

          2. roles


          making 4 fields.



          These levels control access slightly differently for the 2 types of documents a db can contain:




          1. id: _design/* - Design documents can contain functions that will be executed in some context

          2. 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:




          1. Experience the provided validate design document as a consumer while setting up _users.

          2. Setup a new database and its basic security giving your users member access.

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






          share|improve this answer


























          • Thanks for the explanation! This is embarrasing but I've been scratching my head for a while and cant find the "user docs" you are referring to. my _users db only has the design doc (even though I had created users using the permissions window in fauxton)

            – robotHamster
            Dec 2 '18 at 23:44








          • 1





            @robotHamster it sounds like you were adding _admins instead of normal users? You can create a user in the _usersdb by creating a new document with the fields in 1.7.2.2, you can do it in fauxton as long as you change the _id field from a random one to org.couchdb.user:[username] (1.7.2.1).

            – lossleader
            Dec 3 '18 at 10:37











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53384941%2fcouchdb-write-read-only-no-edit-user%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1





          +50









          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:




          1. admins

          2. members


          specified via:




          1. names

          2. roles


          making 4 fields.



          These levels control access slightly differently for the 2 types of documents a db can contain:




          1. id: _design/* - Design documents can contain functions that will be executed in some context

          2. 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:




          1. Experience the provided validate design document as a consumer while setting up _users.

          2. Setup a new database and its basic security giving your users member access.

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






          share|improve this answer


























          • Thanks for the explanation! This is embarrasing but I've been scratching my head for a while and cant find the "user docs" you are referring to. my _users db only has the design doc (even though I had created users using the permissions window in fauxton)

            – robotHamster
            Dec 2 '18 at 23:44








          • 1





            @robotHamster it sounds like you were adding _admins instead of normal users? You can create a user in the _usersdb by creating a new document with the fields in 1.7.2.2, you can do it in fauxton as long as you change the _id field from a random one to org.couchdb.user:[username] (1.7.2.1).

            – lossleader
            Dec 3 '18 at 10:37
















          1





          +50









          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:




          1. admins

          2. members


          specified via:




          1. names

          2. roles


          making 4 fields.



          These levels control access slightly differently for the 2 types of documents a db can contain:




          1. id: _design/* - Design documents can contain functions that will be executed in some context

          2. 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:




          1. Experience the provided validate design document as a consumer while setting up _users.

          2. Setup a new database and its basic security giving your users member access.

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






          share|improve this answer


























          • Thanks for the explanation! This is embarrasing but I've been scratching my head for a while and cant find the "user docs" you are referring to. my _users db only has the design doc (even though I had created users using the permissions window in fauxton)

            – robotHamster
            Dec 2 '18 at 23:44








          • 1





            @robotHamster it sounds like you were adding _admins instead of normal users? You can create a user in the _usersdb by creating a new document with the fields in 1.7.2.2, you can do it in fauxton as long as you change the _id field from a random one to org.couchdb.user:[username] (1.7.2.1).

            – lossleader
            Dec 3 '18 at 10:37














          1





          +50







          1





          +50



          1




          +50





          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:




          1. admins

          2. members


          specified via:




          1. names

          2. roles


          making 4 fields.



          These levels control access slightly differently for the 2 types of documents a db can contain:




          1. id: _design/* - Design documents can contain functions that will be executed in some context

          2. 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:




          1. Experience the provided validate design document as a consumer while setting up _users.

          2. Setup a new database and its basic security giving your users member access.

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






          share|improve this answer















          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:




          1. admins

          2. members


          specified via:




          1. names

          2. roles


          making 4 fields.



          These levels control access slightly differently for the 2 types of documents a db can contain:




          1. id: _design/* - Design documents can contain functions that will be executed in some context

          2. 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:




          1. Experience the provided validate design document as a consumer while setting up _users.

          2. Setup a new database and its basic security giving your users member access.

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







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 3 '18 at 10:30

























          answered Nov 23 '18 at 20:39









          lossleaderlossleader

          9,43011829




          9,43011829













          • Thanks for the explanation! This is embarrasing but I've been scratching my head for a while and cant find the "user docs" you are referring to. my _users db only has the design doc (even though I had created users using the permissions window in fauxton)

            – robotHamster
            Dec 2 '18 at 23:44








          • 1





            @robotHamster it sounds like you were adding _admins instead of normal users? You can create a user in the _usersdb by creating a new document with the fields in 1.7.2.2, you can do it in fauxton as long as you change the _id field from a random one to org.couchdb.user:[username] (1.7.2.1).

            – lossleader
            Dec 3 '18 at 10:37



















          • Thanks for the explanation! This is embarrasing but I've been scratching my head for a while and cant find the "user docs" you are referring to. my _users db only has the design doc (even though I had created users using the permissions window in fauxton)

            – robotHamster
            Dec 2 '18 at 23:44








          • 1





            @robotHamster it sounds like you were adding _admins instead of normal users? You can create a user in the _usersdb by creating a new document with the fields in 1.7.2.2, you can do it in fauxton as long as you change the _id field from a random one to org.couchdb.user:[username] (1.7.2.1).

            – lossleader
            Dec 3 '18 at 10:37

















          Thanks for the explanation! This is embarrasing but I've been scratching my head for a while and cant find the "user docs" you are referring to. my _users db only has the design doc (even though I had created users using the permissions window in fauxton)

          – robotHamster
          Dec 2 '18 at 23:44







          Thanks for the explanation! This is embarrasing but I've been scratching my head for a while and cant find the "user docs" you are referring to. my _users db only has the design doc (even though I had created users using the permissions window in fauxton)

          – robotHamster
          Dec 2 '18 at 23:44






          1




          1





          @robotHamster it sounds like you were adding _admins instead of normal users? You can create a user in the _usersdb by creating a new document with the fields in 1.7.2.2, you can do it in fauxton as long as you change the _id field from a random one to org.couchdb.user:[username] (1.7.2.1).

          – lossleader
          Dec 3 '18 at 10:37





          @robotHamster it sounds like you were adding _admins instead of normal users? You can create a user in the _usersdb by creating a new document with the fields in 1.7.2.2, you can do it in fauxton as long as you change the _id field from a random one to org.couchdb.user:[username] (1.7.2.1).

          – lossleader
          Dec 3 '18 at 10:37




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53384941%2fcouchdb-write-read-only-no-edit-user%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          Xamarin.form Move up view when keyboard appear

          Post-Redirect-Get with Spring WebFlux and Thymeleaf

          Anylogic : not able to use stopDelay()