diff options
author | Paul J. Davis <paul.joseph.davis@gmail.com> | 2019-07-12 12:42:17 -0500 |
---|---|---|
committer | Paul J. Davis <paul.joseph.davis@gmail.com> | 2019-07-31 11:55:30 -0500 |
commit | 858c947394623006db17ac28015458e7d0920c6d (patch) | |
tree | ae6ebacc9179ddfc0dc841fe52fcf21b5a6470e9 | |
parent | 79ea59e68a45cb41cb21ebcedb82f2880b40075a (diff) | |
download | couchdb-858c947394623006db17ac28015458e7d0920c6d.tar.gz |
Reinitialize chttpd_auth_cache on config change
The old test got around this by using couch_httpd_auth cache in its
tests which is fairly odd given that we run chttpd_auth_cache in
production. This fixes that mistake and upgrades chttpd_auth_cache so
that it works in the test scenario of changing the authentication_db
configuration.
-rw-r--r-- | src/chttpd/src/chttpd_auth_cache.erl | 58 | ||||
-rw-r--r-- | src/fabric/src/fabric2_db.erl | 6 | ||||
-rw-r--r-- | test/elixir/test/security_validation_test.exs | 4 |
3 files changed, 56 insertions, 12 deletions
diff --git a/src/chttpd/src/chttpd_auth_cache.erl b/src/chttpd/src/chttpd_auth_cache.erl index e986af6c3..9eee19605 100644 --- a/src/chttpd/src/chttpd_auth_cache.erl +++ b/src/chttpd/src/chttpd_auth_cache.erl @@ -12,16 +12,19 @@ -module(chttpd_auth_cache). -behaviour(gen_server). +-behaviour(config_listener). -export([start_link/0, get_user_creds/2, update_user_creds/3]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([listen_for_changes/1, changes_callback/2]). +-export([handle_config_change/5, handle_config_terminate/3]). -include_lib("couch/include/couch_db.hrl"). -include_lib("couch/include/couch_js_functions.hrl"). -define(CACHE, chttpd_auth_cache_lru). +-define(RELISTEN_DELAY, 5000). -record(state, { changes_pid, @@ -101,17 +104,28 @@ maybe_increment_auth_cache_miss(UserName) -> %% gen_server callbacks init([]) -> - try - fabric2_db:open(dbname(), [?ADMIN_CTX]) - catch error:database_does_not_exist -> - case fabric2_db:create(dbname(), [?ADMIN_CTX]) of - {ok, _} -> ok; - {error, file_exists} -> ok - end - end, + ensure_auth_db(), + ok = config:listen_for_changes(?MODULE, nil), self() ! {start_listener, 0}, {ok, #state{}}. +handle_call(reinit_cache, _From, State) -> + #state{ + changes_pid = Pid + } = State, + + % The database may currently be cached. This + % ensures that we've removed it so that the + % system db callbacks are installed. + fabric2_server:remove(dbname()), + + ensure_auth_db(), + ets_lru:clear(?CACHE), + exit(Pid, shutdown), + self() ! {start_listener, 0}, + + {reply, ok, State#state{changes_pid = undefined}}; + handle_call(_Call, _From, State) -> {noreply, State}. @@ -130,6 +144,9 @@ handle_info({'DOWN', _, _, Pid, Reason}, #state{changes_pid=Pid} = State) -> {noreply, State#state{last_seq=Seq}}; handle_info({start_listener, Seq}, State) -> {noreply, State#state{changes_pid = spawn_changes(Seq)}}; +handle_info(restart_config_listener, State) -> + ok = config:listen_for_changes(?MODULE, nil), + {noreply, State}; handle_info(_Msg, State) -> {noreply, State}. @@ -181,6 +198,19 @@ changes_callback({timeout, _ResponseType}, Acc) -> changes_callback({error, _}, EndSeq) -> exit({seq, EndSeq}). + +handle_config_change("chttpd_auth", "authentication_db", _DbName, _, _) -> + {ok, gen_server:call(?MODULE, reinit_cache, infinity)}; +handle_config_change(_, _, _, _, _) -> + {ok, nil}. + +handle_config_terminate(_, stop, _) -> + ok; +handle_config_terminate(_Server, _Reason, _State) -> + Dst = whereis(?MODULE), + erlang:send_after(?RELISTEN_DELAY, Dst, restart_config_listener). + + load_user_from_db(UserName) -> {ok, Db} = fabric2_db:open(dbname(), [?ADMIN_CTX]), try fabric2_db:open_doc(Db, docid(UserName), [conflicts]) of @@ -194,6 +224,18 @@ load_user_from_db(UserName) -> nil end. + +ensure_auth_db() -> + try + fabric2_db:open(dbname(), [?ADMIN_CTX]) + catch error:database_does_not_exist -> + case fabric2_db:create(dbname(), [?ADMIN_CTX]) of + {ok, _} -> ok; + {error, file_exists} -> ok + end + end. + + dbname() -> DbNameStr = config:get("chttpd_auth", "authentication_db", "_users"), iolist_to_binary(DbNameStr). diff --git a/src/fabric/src/fabric2_db.erl b/src/fabric/src/fabric2_db.erl index 43d555c0e..711490307 100644 --- a/src/fabric/src/fabric2_db.erl +++ b/src/fabric/src/fabric2_db.erl @@ -736,10 +736,14 @@ fold_changes(Db, SinceSeq, UserFun, UserAcc, Options) -> maybe_add_sys_db_callbacks(Db) -> IsReplicatorDb = fabric2_util:dbname_ends_with(Db, <<"_replicator">>), + AuthenticationDb = config:get("chttpd_auth", "authentication_db"), + IsAuthCache = if AuthenticationDb == undefined -> false; true -> + name(Db) == ?l2b(AuthenticationDb) + end, CfgUsersSuffix = config:get("couchdb", "users_db_suffix", "_users"), IsCfgUsersDb = fabric2_util:dbname_ends_with(Db, ?l2b(CfgUsersSuffix)), IsGlobalUsersDb = fabric2_util:dbname_ends_with(Db, <<"_users">>), - IsUsersDb = IsCfgUsersDb orelse IsGlobalUsersDb, + IsUsersDb = IsAuthCache orelse IsCfgUsersDb orelse IsGlobalUsersDb, {BDU, ADR} = if IsReplicatorDb -> diff --git a/test/elixir/test/security_validation_test.exs b/test/elixir/test/security_validation_test.exs index 0df3a780b..e10331477 100644 --- a/test/elixir/test/security_validation_test.exs +++ b/test/elixir/test/security_validation_test.exs @@ -53,9 +53,6 @@ defmodule SecurityValidationTest do on_exit(fn -> delete_db(auth_db_name) end) configs = [ - {"httpd", "authentication_handlers", - "{couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, default_authentication_handler}"}, - {"couch_httpd_auth", "authentication_db", auth_db_name}, {"chttpd_auth", "authentication_db", auth_db_name} ] @@ -72,6 +69,7 @@ defmodule SecurityValidationTest do Enum.each(users, fn {name, pass} -> doc = %{ :_id => "org.couchdb.user:#{name}", + :type => "user", :name => name, :roles => [], :password => pass |