iilyak commented on a change in pull request #2007: Port javascript tests auth cache, cookie auth and users db to elixir URL: https://github.com/apache/couchdb/pull/2007#discussion_r317117374
########## File path: test/elixir/test/cookie_auth_test.exs ########## @@ -0,0 +1,401 @@ +defmodule CookieAuthTest do + use CouchTestCase + + @moduletag :authentication + + @users_db "_users" + + @password "3.141592653589" + + test "cookie auth" do + # Create db if not exists + Couch.put("/#{@users_db}") + + server_config = [ + %{ + :section => "chttpd_auth", + :key => "authentication_db", + :value => @users_db + }, + %{ + :section => "couch_httpd_auth", + :key => "authentication_db", + :value => @users_db + }, + %{ + :section => "couch_httpd_auth", + :key => "iterations", + :value => "1" + }, + %{ + :section => "admins", + :key => "jan", + :value => "apple" + } + ] + + resp = + Couch.get( + "/#{@users_db}/_changes", + query: [feed: "longpoll", timeout: 5000, filter: "_design"] + ) + + assert resp.body + + run_on_modified_server(server_config, &test_fun/0) + end + + defp login(user, password) do + sess = Couch.login(user, password) + assert sess.cookie, "Login correct is expected" + sess + end + + defp logout(session) do + assert Couch.Session.logout(session).body["ok"] + end + + defp login_as(user) do + pws = %{ + "jan" => "apple", + "Jason Davies" => @password, + "jchris" => "funnybone" + } + + user1 = Regex.replace(~r/[0-9]$/, user, "") + login(user1, pws[user]) + end + + defp create_doc_expect_error(db_name, doc, status_code, msg) do + resp = Couch.post("/#{db_name}", body: doc) + assert resp.status_code == status_code + assert resp.body["error"] == msg + resp + end + + defp open_as(db_name, doc_id, options) do + use_session = Keyword.get(options, :use_session) + user = Keyword.get(options, :user) + expect_response = Keyword.get(options, :expect_response, 200) + expect_message = Keyword.get(options, :error_message) + + session = use_session || login_as(user) + + resp = + Couch.get( + "/#{db_name}/#{URI.encode(doc_id)}", + headers: [ + Cookie: session.cookie, + "X-CouchDB-www-Authenticate": "Cookie" + ] + ) + + if use_session == nil do + logout(session) + end + + assert resp.status_code == expect_response + + if expect_message != nil do + assert resp.body["error"] == expect_message + end + + resp.body + end + + defp save_as(db_name, doc, options) do + use_session = Keyword.get(options, :use_session) + user = Keyword.get(options, :user) + expect_response = Keyword.get(options, :expect_response, [201, 202]) + expect_message = Keyword.get(options, :error_message) + + session = use_session || login_as(user) + + resp = + Couch.put( + "/#{db_name}/#{URI.encode(doc["_id"])}", + headers: [ + Cookie: session.cookie, + "X-CouchDB-www-Authenticate": "Cookie" + ], + body: doc + ) + + if use_session == nil do + logout(session) + end + + if is_list(expect_response) do + assert resp.status_code in expect_response + else + assert resp.status_code == expect_response + end + + if expect_message != nil do + assert resp.body["error"] == expect_message + end + + resp + end + + defp delete_as(db_name, doc, options) do + use_session = Keyword.get(options, :use_session) + user = Keyword.get(options, :user) + expect_response = Keyword.get(options, :expect_response, [200, 202]) + expect_message = Keyword.get(options, :error_message) + + session = use_session || login_as(user) + + resp = + Couch.delete( + "/#{db_name}/#{URI.encode(doc["_id"])}", + headers: [ + Cookie: session.cookie, + "X-CouchDB-www-Authenticate": "Cookie" + ] + ) + + if use_session == nil do + logout(session) + end + + if is_list(expect_response) do + assert resp.status_code in expect_response + else + assert resp.status_code == expect_response + end + + if expect_message != nil do + assert resp.body["error"] == expect_message + end + + resp + end + + defp test_change_admin_fun do + sess = login("jchris", "funnybone") + info = Couch.Session.info(sess) + assert info["userCtx"]["name"] == "jchris" + assert Enum.member?(info["userCtx"]["roles"], "_admin") + assert Enum.member?(info["userCtx"]["roles"], "foo") + + jchris_user_doc = + open_as( + @users_db, + "org.couchdb.user:jchris", + use_session: sess + ) + + jchris_user_doc = Map.drop(jchris_user_doc, [:salt, :password_sha]) + save_as(@users_db, jchris_user_doc, use_session: sess) + logout(sess) + sess = login("jchris", "funnybone") + info = Couch.Session.info(sess) + assert info["userCtx"]["name"] == "jchris" + assert Enum.member?(info["userCtx"]["roles"], "_admin") + assert info["info"]["authenticated"] == "cookie" + assert info["info"]["authentication_db"] == @users_db + assert Enum.member?(info["userCtx"]["roles"], "foo") + logout(sess) + end + + defp test_fun do + # test that the users db is born with the auth ddoc + ddoc = open_as(@users_db, "_design/_auth", user: "jan") + assert ddoc["validate_doc_update"] != nil + + jason_user_doc = + prepare_user_doc([ + {:name, "Jason Davies"}, + {:password, @password} + ]) + + create_doc(@users_db, jason_user_doc) + jason_check_doc = open_as(@users_db, jason_user_doc["_id"], user: "jan") + assert jason_check_doc["name"] == "Jason Davies" + + jchris_user_doc = + prepare_user_doc([ + {:name, "jchris"}, + {:password, "funnybone"} + ]) + + {:ok, resp} = create_doc(@users_db, jchris_user_doc) + jchris_rev = resp.body["rev"] + + duplicate_jchris_user_doc = + prepare_user_doc([ + {:name, "jchris"}, + {:password, "eh, Boo-Boo?"} + ]) + + create_doc_expect_error(@users_db, duplicate_jchris_user_doc, 409, "conflict") + + # we can't create _names + underscore_user_doc = + prepare_user_doc([ + {:name, "_why"}, + {:password, "copperfield"} + ]) + + create_doc_expect_error(@users_db, underscore_user_doc, 403, "forbidden") + + # we can't create malformed ids + bad_id_user_doc = + prepare_user_doc([ + {:id, "org.apache.couchdb:w00x"}, + {:name, "w00x"}, + {:password, "bar"} + ]) + + create_doc_expect_error(@users_db, bad_id_user_doc, 403, "forbidden") + + # login works + session = login_as("Jason Davies") + info = Couch.Session.info(session) + assert info["userCtx"]["name"] == "Jason Davies" + assert not Enum.member?(info["userCtx"]["roles"], "_admin") + + # update one's own credentials document + jason_user_doc = + jason_user_doc + |> Map.put("_rev", jason_check_doc["_rev"]) + |> Map.put("foo", 2) + + resp = save_as(@users_db, jason_user_doc, use_session: session) + jason_user_doc_rev = resp.body["rev"] + + # can't delete another users doc unless you are admin + + jchris_user_doc = Map.put(jchris_user_doc, "_rev", jchris_rev) + + delete_as( + @users_db, + jchris_user_doc, + use_session: session, + expect_response: 404, + error_message: "not_found" + ) + + logout(session) + + # test redirect on success + resp = + Couch.post( + "/_session", + query: [next: "/_up"], + body: %{ + :username => "Jason Davies", + :password => @password + } + ) + + assert resp.status_code == 302 + assert resp.body["ok"] + assert String.ends_with?(resp.headers["location"], "/_up") + + # test redirect on fail + resp = + Couch.post( + "/_session", + query: [fail: "/_up"], + body: %{ + :username => "Jason Davies", + :password => "foobar" + } + ) + + assert resp.status_code == 302 + assert resp.body["error"] == "unauthorized" + assert String.ends_with?(resp.headers["location"], "/_up") + + session = login("jchris", "funnybone") + info = Couch.Session.info(session) + assert info["userCtx"]["name"] == "jchris" + assert Enum.empty?(info["userCtx"]["roles"]) + + jason_user_doc = + jason_user_doc + |> Map.put("_rev", jason_user_doc_rev) + |> Map.put("foo", 3) + + save_as( + @users_db, + jason_user_doc, + use_session: session, + expect_response: 404, + error_message: "not_found" + ) + Review comment: JavaScript test has "// make sure we cant create duplicate users" comment. ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services