diff options
author | Juanjo Rodriguez <juanjo@apache.org> | 2020-09-29 11:24:39 +0200 |
---|---|---|
committer | Juanjo Rodriguez <jjrodrig@gmail.com> | 2020-10-07 09:13:30 +0200 |
commit | 2a0a525c6c0692636298782c2f7d51ab66a8ca92 (patch) | |
tree | e807003ac548e8b24f81d41fc535341c4f1a889b | |
parent | a4bfaaf346406f769588f1b583d6b5d80fcb0dd2 (diff) | |
download | couchdb-2a0a525c6c0692636298782c2f7d51ab66a8ca92.tar.gz |
Complete the port of security_validation tests to Elixir
-rw-r--r-- | test/elixir/test/security_validation_test.exs | 248 | ||||
-rw-r--r-- | test/javascript/tests/security_validation.js | 2 |
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 fda928cde..dddf7a7b8 100644 --- a/test/elixir/test/security_validation_test.exs +++ b/test/elixir/test/security_validation_test.exs @@ -21,6 +21,10 @@ defmodule SecurityValidationTest do spike_cat: [ # spike:cat - which is wrong authorization: "Basic c3Bpa2U6Y2F0" + ], + spike: [ + # spike:dog + authorization: "Basic c3Bpa2U6ZG9n" ] } @@ -148,6 +152,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"]}} @@ -179,6 +192,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" @@ -202,136 +221,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(); |