summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuanjo Rodriguez <juanjo@apache.org>2020-09-29 11:24:39 +0200
committerJuanjo Rodriguez <jjrodrig@gmail.com>2020-10-01 22:30:13 +0200
commit87201b7baa9ab652a0ee723d769db6fd5903540a (patch)
treea09ea019b74836884300ffa6f6ae6f33d538e914
parentafea168331c55afaec5203c7f75f477e32802390 (diff)
downloadcouchdb-87201b7baa9ab652a0ee723d769db6fd5903540a.tar.gz
Complete the port of security_validation tests to Elixir
-rw-r--r--test/elixir/test/security_validation_test.exs248
-rw-r--r--test/javascript/tests/security_validation.js2
2 files changed, 118 insertions, 132 deletions
diff --git a/test/elixir/test/security_validation_test.exs b/test/elixir/test/security_validation_test.exs
index 0df3a780b..adc282a9e 100644
--- a/test/elixir/test/security_validation_test.exs
+++ b/test/elixir/test/security_validation_test.exs
@@ -20,6 +20,10 @@ defmodule SecurityValidationTest do
spike_cat: [
# spike:cat - which is wrong
authorization: "Basic c3Bpa2U6Y2F0"
+ ],
+ spike: [
+ # spike:dog
+ authorization: "Basic c3Bpa2U6ZG9n"
]
}
@@ -149,6 +153,15 @@ defmodule SecurityValidationTest do
end
@tag :with_db
+ test "try to set a wrong value for _security", context do
+ db_name = context[:db_name]
+ # try to do something lame
+ resp = Couch.put("/#{db_name}/_security", body: ["foo"])
+ assert resp.status_code == 400
+ assert resp.body["error"] == "bad_request"
+ end
+
+ @tag :with_db
test "Author presence and user security", context do
db_name = context[:db_name]
sec_obj = %{admin_override: false, admins: %{names: ["jerry"]}}
@@ -180,6 +193,12 @@ defmodule SecurityValidationTest do
assert resp.status_code == 403
assert resp.body["error"] == "forbidden"
+ # Admin cannot write the document (admin_override = false)
+ test_doc = Map.put(test_doc, "foo", 3)
+ resp = Couch.put("/#{db_name}/test_doc", body: test_doc)
+ assert resp.status_code == 401
+ assert resp.body["error"] == "unauthorized"
+
# Enable admin override for changing author values
assert Couch.put("/#{db_name}/_security", body: %{sec_obj | admin_override: true}).body[
"ok"
@@ -203,136 +222,103 @@ defmodule SecurityValidationTest do
resp = Couch.delete("/#{db_name}/test_doc?rev=#{test_doc["_rev"]}", opts)
resp.status_code == 401 and resp.body["error"] == "unauthorized"
end)
+
+ # Admin can write the document (admin_override = true)
+ test_doc = Map.put(test_doc, "foo", 4)
+ resp = Couch.put("/#{db_name}/test_doc", body: test_doc)
+ assert resp.body["ok"]
+
+ # Disable admin override
+ assert Couch.put("/#{db_name}/_security", body: %{sec_obj | admin_override: false}).body[
+ "ok"
+ ]
+
+ docs = [%{_id: "bahbah", author: "jerry", foo: "bar"}, %{_id: "fahfah", foo: "baz"}]
+
+ resp =
+ Couch.post(
+ "/#{db_name}/_bulk_docs",
+ body: %{
+ docs: docs
+ },
+ headers: jerry
+ )
+
+ assert Enum.at(resp.body, 0)["rev"]
+ assert !Enum.at(resp.body, 0)["error"]
+ assert !Enum.at(resp.body, 1)["rev"]
+ assert Enum.at(resp.body, 1)["error"] == "forbidden"
+
+ resp = Couch.get("/#{db_name}/bahbah")
+ assert resp.status_code == 200
+
+ resp = Couch.get("/#{db_name}/fahfah")
+ assert resp.status_code == 404
end
-end
-# TODO: port remainder of security_validation.js suite
-# remaining bits reproduced below:
-#
-# // try to do something lame
-# try {
-# db.setDbProperty("_security", ["foo"]);
-# T(false && "can't do this");
-# } catch(e) {}
-#
-# // go back to normal
-# T(db.setDbProperty("_security", {admin_override : false}).ok);
-#
-# // Now delete document
-# T(user2Db.deleteDoc(doc).ok);
-#
-# // now test bulk docs
-# var docs = [{_id:"bahbah",author:"jerry",foo:"bar"},{_id:"fahfah",foo:"baz"}];
-#
-# // Create the docs
-# var results = db.bulkSave(docs);
-#
-# T(results[0].rev)
-# T(results[0].error == undefined)
-# T(results[1].rev === undefined)
-# T(results[1].error == "forbidden")
-#
-# T(db.open("bahbah"));
-# T(db.open("fahfah") == null);
-#
-#
-# // now all or nothing with a failure - no more available on cluster
-# /* var docs = [
-# {_id:"booboo",author:"Damien Katz",foo:"bar"},{_id:"foofoo",foo:"baz"}
-# ];
-#
-# // Create the docs
-# var results = db.bulkSave(docs, {all_or_nothing:true});
-#
-# T(results.errors.length == 1);
-# T(results.errors[0].error == "forbidden");
-# T(db.open("booboo") == null);
-# T(db.open("foofoo") == null);
-# */
-#
-# // Now test replication
-# var AuthHeaders = {"Authorization": "Basic c3Bpa2U6ZG9n"}; // spike
-# adminDbA = new CouchDB("" + db_name + "_a", {"X-Couch-Full-Commit":"false"});
-# adminDbB = new CouchDB("" + db_name + "_b", {"X-Couch-Full-Commit":"false"});
-# var dbA = new CouchDB("" + db_name + "_a", AuthHeaders);
-# var dbB = new CouchDB("" + db_name + "_b", AuthHeaders);
-# // looping does not really add value as the scenario is the same anyway
-# // (there's nothing 2 be gained from it)
-# var A = CouchDB.protocol + CouchDB.host + "/" + db_name + "_a";
-# var B = CouchDB.protocol + CouchDB.host + "/" + db_name + "_b";
-#
-# // (the databases never exist b4 - and we made sure they're deleted below)
-# //adminDbA.deleteDb();
-# adminDbA.createDb();
-# //adminDbB.deleteDb();
-# adminDbB.createDb();
-#
-# // save and replicate a documents that will and will not pass our design
-# // doc validation function.
-# T(dbA.save({_id:"foo1",value:"a",author:"tom"}).ok);
-# T(dbA.save({_id:"foo2",value:"a",author:"spike"}).ok);
-# T(dbA.save({_id:"bad1",value:"a"}).ok);
-#
-# T(CouchDB.replicate(A, B, {headers:AuthHeaders}).ok);
-# T(CouchDB.replicate(B, A, {headers:AuthHeaders}).ok);
-#
-# T(dbA.open("foo1"));
-# T(dbB.open("foo1"));
-# T(dbA.open("foo2"));
-# T(dbB.open("foo2"));
-#
-# // save the design doc to dbA
-# delete designDoc._rev; // clear rev from previous saves
-# T(adminDbA.save(designDoc).ok);
-#
-# // no affect on already saved docs
-# T(dbA.open("bad1"));
-#
-# // Update some docs on dbB. Since the design hasn't replicated, anything
-# // is allowed.
-#
-# // this edit will fail validation on replication to dbA (no author)
-# T(dbB.save({_id:"bad2",value:"a"}).ok);
-#
-# // this edit will fail security on replication to dbA (wrong author
-# // replicating the change)
-# var foo1 = dbB.open("foo1");
-# foo1.value = "b";
-# T(dbB.save(foo1).ok);
-#
-# // this is a legal edit
-# var foo2 = dbB.open("foo2");
-# foo2.value = "b";
-# T(dbB.save(foo2).ok);
-#
-# var results = CouchDB.replicate({"url": B, "headers": AuthHeaders},
-# {"url": A, "headers": AuthHeaders}, {headers:AuthHeaders});
-# T(results.ok);
-# TEquals(1, results.history[0].docs_written);
-# TEquals(2, results.history[0].doc_write_failures);
-#
-# // bad2 should not be on dbA
-# T(dbA.open("bad2") == null);
-#
-# // The edit to foo1 should not have replicated.
-# T(dbA.open("foo1").value == "a");
-#
-# // The edit to foo2 should have replicated.
-# T(dbA.open("foo2").value == "b");
-# });
-#
-# // cleanup
-# db.deleteDb();
-# if(adminDbA){
-# adminDbA.deleteDb();
-# }
-# if(adminDbB){
-# adminDbB.deleteDb();
-# }
-# authDb.deleteDb();
-# // have to clean up authDb on the backside :(
-# var req = CouchDB.newXhr();
-# req.open("DELETE", "http://127.0.0.1:15986/" + authDb_name, false);
-# req.send("");
-# CouchDB.maybeThrowError(req);
-# };
+ test "Author presence and user security when replicated", _context do
+ db_name = random_db_name()
+ db_name_a = "#{db_name}_a"
+ db_name_b = "#{db_name}_b"
+ create_db(db_name_a)
+ create_db(db_name_b)
+ on_exit(fn -> delete_db(db_name_a) end)
+ on_exit(fn -> delete_db(db_name_b) end)
+
+ spike = @auth_headers[:spike]
+
+ # save and replicate a documents that will and will not pass our design
+ # doc validation function.
+ {:ok, _} = create_doc(db_name_a, %{_id: "foo1", value: "a", author: "tom"})
+ {:ok, _} = create_doc(db_name_a, %{_id: "foo2", value: "a", author: "spike"})
+ {:ok, _} = create_doc(db_name_a, %{_id: "bad1", value: "a"})
+ replicate(db_name_a, db_name_b, headers: spike)
+ replicate(db_name_b, db_name_a, headers: spike)
+
+ assert Couch.get("/#{db_name_a}/foo1").status_code == 200
+ assert Couch.get("/#{db_name_b}/foo1").status_code == 200
+ assert Couch.get("/#{db_name_a}/foo2").status_code == 200
+ assert Couch.get("/#{db_name_b}/foo2").status_code == 200
+
+ {:ok, _} = create_doc(db_name_a, @ddoc)
+
+ # no affect on already saved docs
+ assert Couch.get("/#{db_name_a}/bad1").status_code == 200
+
+ # Update some docs on dbB. Since the design hasn't replicated, anything
+ # is allowed.
+
+ # this edit will fail validation on replication to dbA (no author)
+ assert Couch.post(
+ "/#{db_name_b}",
+ body: %{id: "bad2", value: "a"},
+ headers: spike
+ ).body["ok"]
+
+ # this edit will fail security on replication to dbA (wrong author
+ # replicating the change)
+ foo1 = Couch.get("/#{db_name_b}/foo1").body
+ foo1 = Map.put(foo1, "value", "b")
+ assert Couch.put("/#{db_name_b}/foo1", body: foo1, headers: spike).body["ok"]
+
+ # this is a legal edit
+ foo2 = Couch.get("/#{db_name_b}/foo2").body
+ foo2 = Map.put(foo2, "value", "b")
+ assert Couch.put("/#{db_name_b}/foo2", body: foo2, headers: spike).body["ok"]
+
+ result = replicate(db_name_b, db_name_a, headers: spike)
+ assert Enum.at(result["history"], 0)["docs_written"] == 1
+ assert Enum.at(result["history"], 0)["doc_write_failures"] == 2
+
+ # bad2 should not be on dbA
+ assert Couch.get("/#{db_name_a}/bad2").status_code == 404
+
+ # The edit to foo1 should not have replicated.
+ resp = Couch.get("/#{db_name_a}/foo1")
+ assert resp.body["value"] == "a"
+
+ # The edit to foo2 should have replicated.
+ resp = Couch.get("/#{db_name_a}/foo2")
+ assert resp.body["value"] == "b"
+ end
+end
diff --git a/test/javascript/tests/security_validation.js b/test/javascript/tests/security_validation.js
index 6f0bd0f42..365f716e6 100644
--- a/test/javascript/tests/security_validation.js
+++ b/test/javascript/tests/security_validation.js
@@ -9,7 +9,7 @@
// 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.elixir = true;
couchTests.security_validation = function(debug) {
var db_name = get_random_db_name();