You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by mi...@apache.org on 2014/12/04 11:52:13 UTC

[1/3] couchdb commit: updated refs/heads/2452-users-db-security-on-clustered-interface to ed4a4a9

Repository: couchdb
Updated Branches:
  refs/heads/2452-users-db-security-on-clustered-interface [created] ed4a4a9e2


Teach dev/run to clear nodes DB

This commit makes dev/run replace the nodes DB with an empty DB
before adding the nodes doc. This changes the previous behaviour
which was to just try adding the docs and ignore conflicts.

The change makes it possible for a developer to run `dev/run -n 1`
(to spawn a single node cluster) having previously run `dev/run`
(which spawns a three node cluster). Without replacing the nodes
DB the `dev/run -n 1` single-node cluster would still have two
other nodes in the nodes DB and therefore not work correctly.

Note that we explicitly delete each node doc rather than deleting
the whole database because the cluster membership layer gets upset
when the nodes database itself is deleted/recreated.


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/49f03e2b
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/49f03e2b
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/49f03e2b

Branch: refs/heads/2452-users-db-security-on-clustered-interface
Commit: 49f03e2be48dac56c27b220b11cd70676df50f99
Parents: 126ec76
Author: Mike Wallace <mi...@apache.org>
Authored: Wed Nov 26 23:17:04 2014 +0000
Committer: Mike Wallace <mi...@apache.org>
Committed: Wed Dec 3 19:11:09 2014 +0000

----------------------------------------------------------------------
 dev/run | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/49f03e2b/dev/run
----------------------------------------------------------------------
diff --git a/dev/run b/dev/run
index ada5492..bce55f1 100755
--- a/dev/run
+++ b/dev/run
@@ -17,6 +17,7 @@ import contextlib
 import functools
 import glob
 import inspect
+import json
 import optparse
 import os
 import re
@@ -230,6 +231,7 @@ def hashify(pwd, salt=COMMON_SALT, iterations=10, keylen=20):
 def startup(ctx):
     atexit.register(kill_processes, ctx)
     boot_nodes(ctx)
+    reset_nodes_db(ctx, "127.0.0.1")
     join_nodes(ctx, "127.0.0.1", 15986)
 
 
@@ -295,6 +297,27 @@ def boot_node(ctx, node):
     return sp.Popen(cmd, stdin=sp.PIPE, stdout=log, stderr=sp.STDOUT, env=env)
 
 
+@log('Reset nodes DB')
+def reset_nodes_db(ctx, host):
+    _, port = get_ports(1)
+    conn = httpclient.HTTPConnection(host, port)
+    conn.request('GET', '/nodes/_all_docs')
+    resp = conn.getresponse()
+    if not resp.status == 200:
+        print('Could not read nodes DB documents', resp.reason)
+        exit(1)
+    nodes = json.loads(resp.read())['rows']
+    for node in nodes:
+        node_id = node['id']
+        rev = node['value']['rev']
+        conn = httpclient.HTTPConnection(host, port)
+        conn.request('DELETE', '/nodes/{0}?rev={1}'.format(node_id, rev))
+        resp = conn.getresponse()
+        if not resp.status == 200:
+            print('Failed to reset nodes DB', resp.reason)
+            exit(1)
+
+
 @log('Join nodes into cluster')
 def join_nodes(ctx, host, port):
     for node in ctx['nodes']:


[2/3] couchdb commit: updated refs/heads/2452-users-db-security-on-clustered-interface to ed4a4a9

Posted by mi...@apache.org.
Test _users security on the cluster and admin port

This commit modifies the _users DB security test so that it tests
the authentication DB against the clustered interface in addition
to the admin interface.

Previously this test was only being run against the admin port.

COUCHDB-2452


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/23d79b3f
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/23d79b3f
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/23d79b3f

Branch: refs/heads/2452-users-db-security-on-clustered-interface
Commit: 23d79b3f606245ab657900fe7b1bc6ef77ace16e
Parents: 49f03e2
Author: Mike Wallace <mi...@apache.org>
Authored: Thu Nov 27 15:13:44 2014 +0000
Committer: Mike Wallace <mi...@apache.org>
Committed: Wed Dec 3 19:11:12 2014 +0000

----------------------------------------------------------------------
 share/www/script/test/users_db_security.js | 687 +++++++++++++-----------
 1 file changed, 369 insertions(+), 318 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/23d79b3f/share/www/script/test/users_db_security.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/users_db_security.js b/share/www/script/test/users_db_security.js
index f2ca8bc..ae13950 100644
--- a/share/www/script/test/users_db_security.js
+++ b/share/www/script/test/users_db_security.js
@@ -9,100 +9,111 @@
 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 // License for the specific language governing permissions and limitations under
 // the License.
-
 couchTests.users_db_security = function(debug) {
-  var usersDb = new CouchDB("test_suite_users", {"X-Couch-Full-Commit":"false"});
-  if (debug) debugger;
-
-  function wait(ms) {
-    var t0 = new Date(), t1;
-    do {
-      CouchDB.request("GET", "/");
-      t1 = new Date();
-    } while ((t1 - t0) <= ms);
-  }
+  function run_test_against_url(url) {
+    CouchDB.urlPrefix = url;
+    var usersDb = new CouchDB("test_suite_users", {"X-Couch-Full-Commit":"false"});
+    if (debug) debugger;
+
+    function wait(ms) {
+      var t0 = new Date(), t1;
+      do {
+        CouchDB.request("GET", "/");
+        t1 = new Date();
+      } while ((t1 - t0) <= ms);
+    }
 
-  var loginUser = function(username) {
-    var pws = {
-      jan: "apple",
-      jchris: "mp3",
-      jchris1: "couch",
-      fdmanana: "foobar",
-      benoitc: "test"
+    var loginUser = function(username) {
+      var pws = {
+        jan: "apple",
+        jchris: "mp3",
+        jchris1: "couch",
+        fdmanana: "foobar",
+        benoitc: "test"
+      };
+      var username1 = username.replace(/[0-9]$/, "");
+      var password = pws[username];
+      T(CouchDB.login(username1, pws[username]).ok);
     };
-    var username1 = username.replace(/[0-9]$/, "");
-    var password = pws[username];
-    T(CouchDB.login(username1, pws[username]).ok);
-  };
-
-  var open_as = function(db, docId, username) {
-    loginUser(username);
-    try {
-      return db.open(docId, {"anti-cache": Math.round(Math.random() * 100000)});
-    } finally {
-      CouchDB.logout();
-    }
-  };
-
-  var view_as = function(db, viewname, username) {
-    loginUser(username);
-    try {
-      return db.view(viewname);
-    } finally {
-      CouchDB.logout();
-    }
-  };
-
-  var save_as = function(db, doc, username)
-  {
-    loginUser(username);
-    try {
-      return db.save(doc);
-    } catch (ex) {
-      return ex;
-    } finally {
-      CouchDB.logout();
-    }
-  };
-
-  var changes_as = function(db, username)
-  {
-    loginUser(username);
-    try {
-      return db.changes();
-    } catch(ex) {
-      return ex;
-    } finally {
-      CouchDB.logout();
-    }
-  };
-
-  var testFun = function()
-  {
-
-    // _users db
-    // a doc with a field 'password' should be hashed to 'derived_key'
-    //  with salt and salt stored in 'salt', 'password' is set to null.
-    //  Exising 'derived_key' and 'salt' fields are overwritten with new values
-    //  when a non-null 'password' field exists.
-    // anonymous should be able to create a user document
-    var userDoc = {
-      _id: "org.couchdb.user:jchris",
-      type: "user",
-      name: "jchris",
-      password: "mp3",
-      roles: []
+
+    var open_as = function(db, docId, username) {
+      loginUser(username);
+      try {
+        return db.open(docId, {"anti-cache": Math.round(Math.random() * 100000)});
+      } finally {
+        CouchDB.logout();
+      }
+    };
+
+    var view_as = function(db, viewname, username) {
+      loginUser(username);
+      try {
+        return db.view(viewname);
+      } finally {
+        CouchDB.logout();
+      }
     };
 
-    // jan's gonna be admin as he's the first user
-    TEquals(true, usersDb.save(userDoc).ok, "should save document");
-    userDoc = usersDb.open("org.couchdb.user:jchris");
-    TEquals(undefined, userDoc.password, "password field should be null 1");
-    TEquals(40, userDoc.derived_key.length, "derived_key should exist");
-    TEquals(32, userDoc.salt.length, "salt should exist");
+    var save_as = function(db, doc, username)
+    {
+      loginUser(username);
+      try {
+        return db.save(doc);
+      } catch (ex) {
+        return ex;
+      } finally {
+        CouchDB.logout();
+      }
+    };
+
+    var changes_as = function(db, username)
+    {
+      loginUser(username);
+      try {
+        return db.changes();
+      } catch(ex) {
+        return ex;
+      } finally {
+        CouchDB.logout();
+      }
+    };
 
-    // create server admin
-    run_on_modified_server([
+    var testFun = function()
+    {
+
+      // _users db
+      // a doc with a field 'password' should be hashed to 'derived_key'
+      //  with salt and salt stored in 'salt', 'password' is set to null.
+      //  Exising 'derived_key' and 'salt' fields are overwritten with new values
+      //  when a non-null 'password' field exists.
+      // anonymous should be able to create a user document
+      var userDoc = {
+        _id: "org.couchdb.user:jchris",
+        type: "user",
+        name: "jchris",
+        password: "mp3",
+        roles: []
+      };
+
+      CouchDB.urlPrefix = url;
+      // The users DB may or may not exist at this point depending on whether
+      // the test is being run against the cluster or admin port so use allDocs
+      // to check
+      try {
+        usersDb.allDocs();
+      } catch(e) {
+        usersDb.createDb();
+      }
+      // jan's gonna be admin as he's the first user
+      TEquals(true, usersDb.save(userDoc).ok, "should save document");
+      userDoc = usersDb.open("org.couchdb.user:jchris");
+      TEquals(undefined, userDoc.password, "password field should be null 1");
+      TEquals(40, userDoc.derived_key.length, "derived_key should exist");
+      TEquals(32, userDoc.salt.length, "salt should exist");
+
+      CouchDB.urlPrefix = '';
+      // create server admin
+      run_on_modified_server([
         {
           section: "couch_httpd_auth",
           key: "iterations",
@@ -115,205 +126,208 @@ couchTests.users_db_security = function(debug) {
         }
       ], function() {
 
-      // anonymous should not be able to read an existing user's user document
-      var res = usersDb.open("org.couchdb.user:jchris");
-      TEquals(null, res, "anonymous user doc read should be not found");
-
-      // anonymous should not be able to read /_users/_changes
-      try {
-        var ch = usersDb.changes();
-        T(false, "anonymous can read _changes");
-      } catch(e) {
-        TEquals("unauthorized", e.error, "anoymous can't read _changes");
-      }
-
-      // user should be able to read their own document
-      var jchrisDoc = open_as(usersDb, "org.couchdb.user:jchris", "jchris");
-      TEquals("org.couchdb.user:jchris", jchrisDoc._id);
-
-      // user should not be able to read /_users/_changes
-      var changes = changes_as(usersDb, "jchris");
-      TEquals("unauthorized", changes.error, "user can't read _changes");
-
-      // new 'password' fields should trigger new hashing routine
-      jchrisDoc.password = "couch";
-
-      TEquals(true, save_as(usersDb, jchrisDoc, "jchris").ok);
-      wait(100);
-      var jchrisDoc = open_as(usersDb, "org.couchdb.user:jchris", "jchris1");
-
-      TEquals(undefined, jchrisDoc.password, "password field should be null 2");
-      TEquals(40, jchrisDoc.derived_key.length, "derived_key should exist");
-      TEquals(32, jchrisDoc.salt.length, "salt should exist");
-
-      TEquals(true, userDoc.salt != jchrisDoc.salt, "should have new salt");
-      TEquals(true, userDoc.derived_key != jchrisDoc.derived_key,
-        "should have new derived_key");
-
-      // SHA-1 password hashes are upgraded to PBKDF2 on successful
-      // authentication
-      var rnewsonDoc = {
-        _id: "org.couchdb.user:rnewson",
-        type: "user",
-        name: "rnewson",
-        // password: "plaintext_password",
-        password_sha: "e29dc3aeed5abf43185c33e479f8998558c59474",
-        salt: "24f1e0a87c2e374212bda1073107e8ae",
-        roles: []
-      };
+        CouchDB.urlPrefix = url;
+        // anonymous should not be able to read an existing user's user document
+        var res = usersDb.open("org.couchdb.user:jchris");
+        TEquals(null, res, "anonymous user doc read should be not found");
+
+        // anonymous should not be able to read /_users/_changes
+        try {
+          var ch = usersDb.changes();
+          T(false, "anonymous can read _changes");
+        } catch(e) {
+          TEquals("unauthorized", e.error, "anoymous can't read _changes");
+        }
 
-      var password_sha = rnewsonDoc.password_sha,
+        // user should be able to read their own document
+        var jchrisDoc = open_as(usersDb, "org.couchdb.user:jchris", "jchris");
+        TEquals("org.couchdb.user:jchris", jchrisDoc._id);
+
+        // user should not be able to read /_users/_changes
+        var changes = changes_as(usersDb, "jchris");
+        TEquals("unauthorized", changes.error, "user can't read _changes");
+
+        // new 'password' fields should trigger new hashing routine
+        jchrisDoc.password = "couch";
+
+        TEquals(true, save_as(usersDb, jchrisDoc, "jchris").ok);
+        wait(5000); // chttpd_auth_cache may not have started listening for changes
+        var jchrisDoc = open_as(usersDb, "org.couchdb.user:jchris", "jchris1");
+
+        TEquals(undefined, jchrisDoc.password, "password field should be null 2");
+        TEquals(40, jchrisDoc.derived_key.length, "derived_key should exist");
+        TEquals(32, jchrisDoc.salt.length, "salt should exist");
+
+        TEquals(true, userDoc.salt != jchrisDoc.salt, "should have new salt");
+        TEquals(true, userDoc.derived_key != jchrisDoc.derived_key,
+                "should have new derived_key");
+
+        // SHA-1 password hashes are upgraded to PBKDF2 on successful
+        // authentication
+        var rnewsonDoc = {
+          _id: "org.couchdb.user:rnewson",
+          type: "user",
+          name: "rnewson",
+          // password: "plaintext_password",
+          password_sha: "e29dc3aeed5abf43185c33e479f8998558c59474",
+          salt: "24f1e0a87c2e374212bda1073107e8ae",
+          roles: []
+        };
+
+        var password_sha = rnewsonDoc.password_sha,
         salt = rnewsonDoc.salt,
         derived_key,
         iterations;
 
-      usersDb.save(rnewsonDoc);
-      rnewsonDoc = open_as(usersDb, rnewsonDoc._id, "jan");
-      T(!rnewsonDoc.password_scheme);
-      T(!rnewsonDoc.derived_key);
-      T(!rnewsonDoc.iterations);
-
-      // check that we don't upgrade when the password is wrong
-      TEquals("unauthorized", CouchDB.login("rnewson", "wrong_password").error);
-      rnewsonDoc = open_as(usersDb, rnewsonDoc._id, "jan");
-      TEquals(salt, rnewsonDoc.salt);
-      TEquals(password_sha, rnewsonDoc.password_sha);
-      T(!rnewsonDoc.password_scheme);
-      T(!rnewsonDoc.derived_key);
-      T(!rnewsonDoc.iterations);
-
-      TEquals(true, CouchDB.login("rnewson", "plaintext_password").ok);
-      rnewsonDoc = usersDb.open(rnewsonDoc._id);
-      TEquals("pbkdf2", rnewsonDoc.password_scheme);
-      T(rnewsonDoc.salt != salt);
-      T(!rnewsonDoc.password_sha);
-      T(rnewsonDoc.derived_key);
-      T(rnewsonDoc.iterations);
-
-      salt = rnewsonDoc.salt,
-      derived_key = rnewsonDoc.derived_key,
-      iterations = rnewsonDoc.iterations;
-
-      // check that authentication is still working
-      // and everything is staying the same now
-      CouchDB.logout();
-      TEquals(true, CouchDB.login("rnewson", "plaintext_password").ok);
-      rnewsonDoc = usersDb.open(rnewsonDoc._id);
-      TEquals("pbkdf2", rnewsonDoc.password_scheme);
-      TEquals(salt, rnewsonDoc.salt);
-      T(!rnewsonDoc.password_sha);
-      TEquals(derived_key, rnewsonDoc.derived_key);
-      TEquals(iterations, rnewsonDoc.iterations);
-
-      CouchDB.logout();
-
-      // user should not be able to read another user's user document
-      var fdmananaDoc = {
-        _id: "org.couchdb.user:fdmanana",
-        type: "user",
-        name: "fdmanana",
-        password: "foobar",
-        roles: []
-      };
-
-      usersDb.save(fdmananaDoc);
-
-      var fdmananaDocAsReadByjchris =
-        open_as(usersDb, "org.couchdb.user:fdmanana", "jchris1");
-      TEquals(null, fdmananaDocAsReadByjchris,
-        "should not_found opening another user's user doc");
+        usersDb.save(rnewsonDoc);
+        rnewsonDoc = open_as(usersDb, rnewsonDoc._id, "jan");
+        T(!rnewsonDoc.password_scheme);
+        T(!rnewsonDoc.derived_key);
+        T(!rnewsonDoc.iterations);
+
+        // check that we don't upgrade when the password is wrong
+        TEquals("unauthorized", CouchDB.login("rnewson", "wrong_password").error);
+        rnewsonDoc = open_as(usersDb, rnewsonDoc._id, "jan");
+        TEquals(salt, rnewsonDoc.salt);
+        TEquals(password_sha, rnewsonDoc.password_sha);
+        T(!rnewsonDoc.password_scheme);
+        T(!rnewsonDoc.derived_key);
+        T(!rnewsonDoc.iterations);
+
+        TEquals(true, CouchDB.login("rnewson", "plaintext_password").ok);
+        rnewsonDoc = usersDb.open(rnewsonDoc._id);
+        TEquals("pbkdf2", rnewsonDoc.password_scheme);
+        T(rnewsonDoc.salt != salt);
+        T(!rnewsonDoc.password_sha);
+        T(rnewsonDoc.derived_key);
+        T(rnewsonDoc.iterations);
 
+        salt = rnewsonDoc.salt,
+        derived_key = rnewsonDoc.derived_key,
+        iterations = rnewsonDoc.iterations;
+
+        // check that authentication is still working
+        // and everything is staying the same now
+        CouchDB.logout();
+        wait(5000); // Increased because change seems to take a while to propagate to auth cache
+        TEquals(true, CouchDB.login("rnewson", "plaintext_password").ok);
+        rnewsonDoc = usersDb.open(rnewsonDoc._id);
+        TEquals("pbkdf2", rnewsonDoc.password_scheme);
+        TEquals(salt, rnewsonDoc.salt);
+        T(!rnewsonDoc.password_sha);
+        TEquals(derived_key, rnewsonDoc.derived_key);
+        TEquals(iterations, rnewsonDoc.iterations);
+
+        CouchDB.logout();
+
+        // user should not be able to read another user's user document
+        var fdmananaDoc = {
+          _id: "org.couchdb.user:fdmanana",
+          type: "user",
+          name: "fdmanana",
+          password: "foobar",
+          roles: []
+        };
+
+        usersDb.save(fdmananaDoc);
+
+        var fdmananaDocAsReadByjchris =
+          open_as(usersDb, "org.couchdb.user:fdmanana", "jchris1");
+        TEquals(null, fdmananaDocAsReadByjchris,
+                "should not_found opening another user's user doc");
+
+
+        // save a db admin
+        var benoitcDoc = {
+          _id: "org.couchdb.user:benoitc",
+          type: "user",
+          name: "benoitc",
+          password: "test",
+          roles: ["user_admin"]
+        };
+        save_as(usersDb, benoitcDoc, "jan");
+
+        TEquals(true, CouchDB.login("jan", "apple").ok);
+        T(usersDb.setSecObj({
+          "admins" : {
+            roles : [],
+            names : ["benoitc"]
+          }
+        }).ok);
+        CouchDB.logout();
+
+        // user should not be able to read from any view
+        var ddoc = {
+          _id: "_design/user_db_auth",
+          views: {
+            test: {
+              map: "function(doc) { emit(doc._id, null); }"
+            }
+          }
+        };
 
-      // save a db admin
-      var benoitcDoc = {
-        _id: "org.couchdb.user:benoitc",
-        type: "user",
-        name: "benoitc",
-        password: "test",
-        roles: ["user_admin"]
-      };
-      save_as(usersDb, benoitcDoc, "jan");
+        save_as(usersDb, ddoc, "jan");
 
-      TEquals(true, CouchDB.login("jan", "apple").ok);
-      T(usersDb.setSecObj({
-        "admins" : {
-          roles : [],
-          names : ["benoitc"]
+        try {
+          usersDb.view("user_db_auth/test");
+          T(false, "user had access to view in admin db");
+        } catch(e) {
+          TEquals("forbidden", e.error,
+                  "non-admins should not be able to read a view");
         }
-      }).ok);
-      CouchDB.logout();
-
-      // user should not be able to read from any view
-      var ddoc = {
-        _id: "_design/user_db_auth",
-        views: {
-          test: {
-            map: "function(doc) { emit(doc._id, null); }"
-          }
-        }
-      };
 
-      save_as(usersDb, ddoc, "jan");
+        // admin should be able to read from any view
+        var result = view_as(usersDb, "user_db_auth/test", "jan");
+        TEquals(4, result.total_rows, "should allow access and list four users to admin");
 
-      try {
-        usersDb.view("user_db_auth/test");
-        T(false, "user had access to view in admin db");
-      } catch(e) {
-        TEquals("forbidden", e.error,
-        "non-admins should not be able to read a view");
-      }
+        // db admin should be able to read from any view
+        var result = view_as(usersDb, "user_db_auth/test", "benoitc");
+        TEquals(4, result.total_rows, "should allow access and list four users to db admin");
 
-      // admin should be able to read from any view
-      var result = view_as(usersDb, "user_db_auth/test", "jan");
-      TEquals(4, result.total_rows, "should allow access and list four users to admin");
 
-      // db admin should be able to read from any view
-      var result = view_as(usersDb, "user_db_auth/test", "benoitc");
-      TEquals(4, result.total_rows, "should allow access and list four users to db admin");
+        // non-admins can't read design docs
+        try {
+          open_as(usersDb, "_design/user_db_auth", "jchris1");
+          T(false, "non-admin read design doc, should not happen");
+        } catch(e) {
+          TEquals("forbidden", e.error, "non-admins can't read design docs");
+        }
 
+        // admin should be able to read and edit any user doc
+        fdmananaDoc.password = "mobile";
 
-      // non-admins can't read design docs
-      try {
-        open_as(usersDb, "_design/user_db_auth", "jchris1");
-        T(false, "non-admin read design doc, should not happen");
-      } catch(e) {
-        TEquals("forbidden", e.error, "non-admins can't read design docs");
-      }
+        var result = save_as(usersDb, fdmananaDoc, "jan");
+        TEquals(true, result.ok, "admin should be able to update any user doc");
 
-      // admin should be able to read and edit any user doc
-      fdmananaDoc.password = "mobile";
-      var result = save_as(usersDb, fdmananaDoc, "jan");
-      TEquals(true, result.ok, "admin should be able to update any user doc");
-
-      // admin should be able to read and edit any user doc
-      fdmananaDoc.password = "mobile1";
-      var result = save_as(usersDb, fdmananaDoc, "benoitc");
-      TEquals(true, result.ok, "db admin by role should be able to update any user doc");
-
-      TEquals(true, CouchDB.login("jan", "apple").ok);
-      T(usersDb.setSecObj({
-        "admins" : {
-          roles : ["user_admin"],
-          names : []
-        }
-      }).ok);
-      CouchDB.logout();
+        // admin should be able to read and edit any user doc
+        fdmananaDoc.password = "mobile1";
+        var result = save_as(usersDb, fdmananaDoc, "benoitc");
+        TEquals(true, result.ok, "db admin by role should be able to update any user doc");
 
-      // db admin should be able to read and edit any user doc
-      fdmananaDoc.password = "mobile2";
-      var result = save_as(usersDb, fdmananaDoc, "benoitc");
-      TEquals(true, result.ok, "db admin should be able to update any user doc");
+        TEquals(true, CouchDB.login("jan", "apple").ok);
+        T(usersDb.setSecObj({
+          "admins" : {
+            roles : ["user_admin"],
+            names : []
+          }
+        }).ok);
+        CouchDB.logout();
 
-      // ensure creation of old-style docs still works
-      var robertDoc = CouchDB.prepareUserDoc({ name: "robert" }, "anchovy");
-      var result = usersDb.save(robertDoc);
-      TEquals(true, result.ok, "old-style user docs should still be accepted");
+        // db admin should be able to read and edit any user doc
+        fdmananaDoc.password = "mobile2";
+        var result = save_as(usersDb, fdmananaDoc, "benoitc");
+        TEquals(true, result.ok, "db admin should be able to update any user doc");
 
-      // log in one last time so run_on_modified_server can clean up the admin account
-      TEquals(true, CouchDB.login("jan", "apple").ok);
-    });
+        // ensure creation of old-style docs still works
+        var robertDoc = CouchDB.prepareUserDoc({ name: "robert" }, "anchovy");
+        var result = usersDb.save(robertDoc);
+        TEquals(true, result.ok, "old-style user docs should still be accepted");
 
-    run_on_modified_server([
+        // log in one last time so run_on_modified_server can clean up the admin account
+        TEquals(true, CouchDB.login("jan", "apple").ok);
+      });
+
+      run_on_modified_server([
         {
           section: "couch_httpd_auth",
           key: "iterations",
@@ -330,6 +344,21 @@ couchTests.users_db_security = function(debug) {
           value: "true"
         },
         {
+          section: "chttpd_auth",
+          key: "iterations",
+          value: "1"
+        },
+        {
+          section: "chttpd_auth",
+          key: "public_fields",
+          value: "name,type"
+        },
+        {
+          section: "chttpd_auth",
+          key: "users_db_public",
+          value: "true"
+        },
+        {
           section: "admins",
           key: "jan",
           value: "apple"
@@ -363,61 +392,83 @@ couchTests.users_db_security = function(debug) {
             }
           }));
         }
-      // log in one last time so run_on_modified_server can clean up the admin account
-      TEquals(true, CouchDB.login("jan", "apple").ok);
-    });
-
-    run_on_modified_server([
-      {
-        section: "couch_httpd_auth",
-        key: "iterations",
-        value: "1"
-      },
-      {
-        section: "couch_httpd_auth",
-        key: "public_fields",
-        value: "name"
-      },
-      {
-        section: "couch_httpd_auth",
-        key: "users_db_public",
-        value: "false"
-      },
-      {
-        section: "admins",
-        key: "jan",
-        value: "apple"
-      }
-    ], function() {
-      TEquals(true, CouchDB.login("jchris", "couch").ok);
+        // log in one last time so run_on_modified_server can clean up the admin account
+        TEquals(true, CouchDB.login("jan", "apple").ok);
+      });
 
-      try {
-        var all = usersDb.allDocs({ include_docs: true });
-        T(false); // should never hit
-      } catch(e) {
-        TEquals("forbidden", e.error, "should throw");
-      }
+      run_on_modified_server([
+        {
+          section: "couch_httpd_auth",
+          key: "iterations",
+          value: "1"
+        },
+        {
+          section: "couch_httpd_auth",
+          key: "public_fields",
+          value: "name"
+        },
+        {
+          section: "couch_httpd_auth",
+          key: "users_db_public",
+          value: "false"
+        },
+        {
+          section: "chttpd_auth",
+          key: "iterations",
+          value: "1"
+        },
+        {
+          section: "chttpd_auth",
+          key: "public_fields",
+          value: "name"
+        },
+        {
+          section: "chttpd_auth",
+          key: "users_db_public",
+          value: "false"
+        },
+        {
+          section: "admins",
+          key: "jan",
+          value: "apple"
+        }
+      ], function() {
+        TEquals(true, CouchDB.login("jchris", "couch").ok);
 
-      // COUCHDB-1888 make sure admins always get all fields
-      TEquals(true, CouchDB.login("jan", "apple").ok);
-      var all_admin = usersDb.allDocs({ include_docs: "true" });
-      TEquals("user", all_admin.rows[2].doc.type,
-          "should return type");
+        try {
+          var all = usersDb.allDocs({ include_docs: true });
+          T(false); // should never hit
+        } catch(e) {
+          TEquals("forbidden", e.error, "should throw");
+        }
 
+        // COUCHDB-1888 make sure admins always get all fields
+        TEquals(true, CouchDB.login("jan", "apple").ok);
+        var all_admin = usersDb.allDocs({ include_docs: "true" });
+        TEquals("user", all_admin.rows[2].doc.type,
+                "should return type");
 
-      // log in one last time so run_on_modified_server can clean up the admin account
-      TEquals(true, CouchDB.login("jan", "apple").ok);
-    });
-  };
 
-  usersDb.deleteDb();
-  run_on_modified_server(
-    [{section: "couch_httpd_auth",
-      key: "iterations", value: "1"},
-     {section: "couch_httpd_auth",
-      key: "authentication_db", value: usersDb.name}],
-    testFun
-  );
-  usersDb.deleteDb(); // cleanup
+        // log in one last time so run_on_modified_server can clean up the admin account
+        TEquals(true, CouchDB.login("jan", "apple").ok);
+      });
+    };
+
+    usersDb.deleteDb();
+    run_on_modified_server(
+      [{section: "couch_httpd_auth",
+        key: "iterations", value: "1"},
+       {section: "couch_httpd_auth",
+        key: "authentication_db", value: usersDb.name},
+       {section: "chttpd_auth",
+        key: "authentication_db", value: usersDb.name}],
+      testFun
+    );
+    usersDb.deleteDb(); // cleanup
+  }
 
+  // Run the test suite against the admin port
+  run_test_against_url("http://127.0.0.1:15986");
+  // Run the test suite against the cluster port
+  run_test_against_url("http://127.0.0.1:15984");
 };


[3/3] couchdb commit: updated refs/heads/2452-users-db-security-on-clustered-interface to ed4a4a9

Posted by mi...@apache.org.
Make users_db_security.js use N=1 clusters only

The users_db_security.js test will not work against a multi-node
cluster because it relies on config settings being made by the
test code. Because there is no generic way of discovering the
locations of the other nodes on a dev cluster (they may be on
unexpected ports for one reason or another) it is only possible
to guarantee those settings are made on a single node.

This commit therefore forces the users_db_security.js test to run
against a single node cluster by:

 - setting the cluster variables to N=Q=R=W=1
 - excluding the test in the Makefile and running it explicitly
   with `dev/run -n 1`
 - teaching run_on_modified_server to correctly preserve the old
   config settings when nested run_on_modified_server calls are
   made

COUCHDB-2452


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/ed4a4a9e
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/ed4a4a9e
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/ed4a4a9e

Branch: refs/heads/2452-users-db-security-on-clustered-interface
Commit: ed4a4a9e2bfbc906bc2339007fe7ef13137eba88
Parents: 23d79b3
Author: Mike Wallace <mi...@apache.org>
Authored: Mon Dec 1 13:22:46 2014 +0000
Committer: Mike Wallace <mi...@apache.org>
Committed: Wed Dec 3 19:11:13 2014 +0000

----------------------------------------------------------------------
 Makefile                                   |  1 +
 share/www/script/couch_test_runner.js      |  8 +++++
 share/www/script/test/users_db_security.js | 43 ++++++++++++++++++++-----
 test/javascript/run                        |  7 +++-
 4 files changed, 50 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed4a4a9e/Makefile
----------------------------------------------------------------------
diff --git a/Makefile b/Makefile
index 986d2dc..7f57830 100644
--- a/Makefile
+++ b/Makefile
@@ -69,3 +69,4 @@ eunit: compile
 
 javascript: compile
 	@dev/run -q test/javascript/run
+	@dev/run -n 1 -q test/javascript/run share/www/script/test/users_db_security.js

http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed4a4a9e/share/www/script/couch_test_runner.js
----------------------------------------------------------------------
diff --git a/share/www/script/couch_test_runner.js b/share/www/script/couch_test_runner.js
index efc4dc2..0617efd 100644
--- a/share/www/script/couch_test_runner.js
+++ b/share/www/script/couch_test_runner.js
@@ -363,6 +363,14 @@ function makeDocs(start, end, templateDoc) {
 }
 
 function run_on_modified_server(settings, fun) {
+  // Clone settings so we don't overwrite oldValue when making nested run_on_modified_server calls
+  var settings = settings.map(function(s) {
+    return {
+      section: s.section,
+      key: s.key,
+      value: s.value
+    };
+  });
   try {
     // set the settings
     for(var i=0; i < settings.length; i++) {

http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed4a4a9e/share/www/script/test/users_db_security.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/users_db_security.js b/share/www/script/test/users_db_security.js
index ae13950..3eb446c 100644
--- a/share/www/script/test/users_db_security.js
+++ b/share/www/script/test/users_db_security.js
@@ -10,7 +10,34 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 couchTests.users_db_security = function(debug) {
+  var clusterVars = [{
+      section: "cluster",
+      key: "q",
+      value: "1"
+    },
+    {
+      section: "cluster",
+      key: "n",
+      value: "1"
+    },
+    {
+      section: "cluster",
+      key: "w",
+      value: "1"
+    },
+    {
+      section: "cluster",
+      key: "r",
+      value: "1"
+    }
+  ];
   function run_test_against_url(url) {
+    // Ensure users DB is created with desired Q/N
+    run_on_modified_server(clusterVars, function() {
+      CouchDB.urlPrefix = url;
+      new CouchDB("test_suite_users", {"X-Couch-Full-Commit":"false"});
+    });
+
     CouchDB.urlPrefix = url;
     var usersDb = new CouchDB("test_suite_users", {"X-Couch-Full-Commit":"false"});
     if (debug) debugger;
@@ -113,7 +140,7 @@ couchTests.users_db_security = function(debug) {
 
       CouchDB.urlPrefix = '';
       // create server admin
-      run_on_modified_server([
+      run_on_modified_server(clusterVars.concat([
         {
           section: "couch_httpd_auth",
           key: "iterations",
@@ -124,7 +151,7 @@ couchTests.users_db_security = function(debug) {
           key: "jan",
           value: "apple"
         }
-      ], function() {
+      ]), function() {
 
         CouchDB.urlPrefix = url;
         // anonymous should not be able to read an existing user's user document
@@ -327,7 +354,7 @@ couchTests.users_db_security = function(debug) {
         TEquals(true, CouchDB.login("jan", "apple").ok);
       });
 
-      run_on_modified_server([
+      run_on_modified_server(clusterVars.concat([
         {
           section: "couch_httpd_auth",
           key: "iterations",
@@ -363,7 +390,7 @@ couchTests.users_db_security = function(debug) {
           key: "jan",
           value: "apple"
         }
-      ], function() {
+      ]), function() {
         var res = usersDb.open("org.couchdb.user:jchris");
         TEquals("jchris", res.name);
         TEquals("user", res.type);
@@ -396,7 +423,7 @@ couchTests.users_db_security = function(debug) {
         TEquals(true, CouchDB.login("jan", "apple").ok);
       });
 
-      run_on_modified_server([
+      run_on_modified_server(clusterVars.concat([
         {
           section: "couch_httpd_auth",
           key: "iterations",
@@ -432,7 +459,7 @@ couchTests.users_db_security = function(debug) {
           key: "jan",
           value: "apple"
         }
-      ], function() {
+      ]), function() {
         TEquals(true, CouchDB.login("jchris", "couch").ok);
 
         try {
@@ -455,13 +482,13 @@ couchTests.users_db_security = function(debug) {
     };
 
     usersDb.deleteDb();
-    run_on_modified_server(
+    run_on_modified_server(clusterVars.concat(
       [{section: "couch_httpd_auth",
         key: "iterations", value: "1"},
        {section: "couch_httpd_auth",
         key: "authentication_db", value: usersDb.name},
        {section: "chttpd_auth",
-        key: "authentication_db", value: usersDb.name}],
+        key: "authentication_db", value: usersDb.name}]),
       testFun
     );
     usersDb.deleteDb(); // cleanup

http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed4a4a9e/test/javascript/run
----------------------------------------------------------------------
diff --git a/test/javascript/run b/test/javascript/run
index ab145b1..4b272ba 100755
--- a/test/javascript/run
+++ b/test/javascript/run
@@ -37,6 +37,10 @@ SCRIPTS = """
     test/javascript/test_setup.js
 """.split()
 
+EXCLUDE = """
+    share/www/script/test/users_db_security.js
+""".split()
+
 RUNNER = "test/javascript/cli_runner.js"
 
 
@@ -109,7 +113,8 @@ def main():
         args = ["share/www/script/test"]
     for name in args:
         if os.path.isdir(name):
-            tests.extend(glob.glob(os.path.join(name, "*.js")))
+            tests_in_dir = glob.glob(os.path.join(name, "*.js"))
+            tests.extend([t for t in tests_in_dir if not t in EXCLUDE])
         elif os.path.isfile(name):
             tests.append(name)
         else: