blob: 2ba396de71c6cced7797b393292aa01ac1d2261b [file] [log] [blame]
defmodule AuthCacheTest do
use CouchTestCase
@moduletag :authentication
@tag :pending
@tag :with_db
test "auth cache management", context do
db_name = context[:db_name]
server_config = [
%{
:section => "chttpd_auth",
:key => "authentication_db",
:value => db_name
},
%{
:section => "chttpd_auth",
:key => "auth_cache_size",
:value => "3"
},
%{
:section => "httpd",
:key => "authentication_handlers",
:value => "{couch_httpd_auth, default_authentication_handler}"
},
%{
:section => "chttpd_auth",
:key => "secret",
:value => generate_secret(64)
}
]
run_on_modified_server(server_config, fn -> test_fun(db_name) end)
end
defp generate_secret(len) do
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|> String.splitter("", trim: true)
|> Enum.take_random(len)
|> Enum.join("")
end
defp hits() do
hits = request_stats(["couchdb", "auth_cache_hits"], true)
hits["value"] || 0
end
defp misses() do
misses = request_stats(["couchdb", "auth_cache_misses"], true)
misses["value"] || 0
end
defp logout(session) do
assert Couch.Session.logout(session).body["ok"]
end
defp login_fail(user, password) do
resp = Couch.login(user, password, :fail)
assert resp.error, "Login error is expected."
end
defp login(user, password) do
sess = Couch.login(user, password)
assert sess.cookie, "Login correct is expected"
sess
end
defp wait_until_compact_complete(db_name) do
retry_until(
fn -> Map.get(info(db_name), "compact_running") == false end,
200,
10_000
)
end
defp assert_cache(event, user, password, expect \\ :expect_login_success) do
hits_before = hits()
misses_before = misses()
session =
case expect do
:expect_login_success -> login(user, password)
:expect_login_fail -> login_fail(user, password)
_ -> assert false
end
hits_after = hits()
misses_after = misses()
if expect == :expect_success do
logout(session)
end
case event do
:expect_miss ->
assert misses_after == misses_before + 1,
"Cache miss is expected for #{user} after login"
assert hits_after == hits_before,
"No cache hit is expected for #{user} after login"
:expect_hit ->
assert misses_after == misses_before,
"No cache miss is expected for #{user} after login"
assert hits_after == hits_before + 1,
"Cache hit is expected for #{user} after login"
_ ->
assert false
end
end
defp compact(db_name) do
resp = Couch.post("/#{db_name}/_compact")
assert resp.status_code == 202
resp.body
end
def save_doc(db_name, body) do
resp = Couch.put("/#{db_name}/#{body["_id"]}", body: body)
assert resp.status_code in [201, 202]
assert resp.body["ok"]
Map.put(body, "_rev", resp.body["rev"])
end
def delete_doc(db_name, body) do
resp = Couch.delete("/#{db_name}/#{body["_id"]}", query: [rev: body["_rev"]])
assert resp.status_code in [200, 202]
assert resp.body["ok"]
{:ok, resp}
end
defp test_fun(db_name) do
fdmanana =
prepare_user_doc([
{:name, "fdmanana"},
{:password, "qwerty"},
{:roles, ["dev"]}
])
{:ok, resp} = create_doc(db_name, fdmanana)
fdmanana = Map.put(fdmanana, "_rev", resp.body["rev"])
chris =
prepare_user_doc([
{:name, "chris"},
{:password, "the_god_father"},
{:roles, ["dev", "mafia", "white_costume"]}
])
create_doc(db_name, chris)
joe =
prepare_user_doc([
{:name, "joe"},
{:password, "functional"},
{:roles, ["erlnager"]}
])
create_doc(db_name, joe)
johndoe =
prepare_user_doc([
{:name, "johndoe"},
{:password, "123456"},
{:roles, ["user"]}
])
create_doc(db_name, johndoe)
assert_cache(:expect_miss, "fdmanana", "qwerty")
assert_cache(:expect_hit, "fdmanana", "qwerty")
assert_cache(:expect_miss, "chris", "the_god_father")
assert_cache(:expect_miss, "joe", "functional")
assert_cache(:expect_miss, "johndoe", "123456")
# It's a MRU cache, joe was removed from cache to add johndoe
# BUGGED assert_cache(:expect_miss, "joe", "functional")
assert_cache(:expect_hit, "fdmanana", "qwerty")
fdmanana = Map.replace!(fdmanana, "password", "foobar")
fdmanana = save_doc(db_name, fdmanana)
# Cache was refreshed
# BUGGED
# assert_cache(:expect_hit, "fdmanana", "qwerty", :expect_login_fail)
# assert_cache(:expect_hit, "fdmanana", "foobar")
# and yet another update
fdmanana = Map.replace!(fdmanana, "password", "javascript")
fdmanana = save_doc(db_name, fdmanana)
# Cache was refreshed
# BUGGED
# assert_cache(:expect_hit, "fdmanana", "foobar", :expect_login_fail)
# assert_cache(:expect_hit, "fdmanana", "javascript")
delete_doc(db_name, fdmanana)
assert_cache(:expect_hit, "fdmanana", "javascript", :expect_login_fail)
# login, compact authentication DB, login again and verify that
# there was a cache hit
assert_cache(:expect_hit, "johndoe", "123456")
compact(db_name)
wait_until_compact_complete(db_name)
assert_cache(:expect_hit, "johndoe", "123456")
end
end