You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2019/07/12 17:43:59 UTC
[couchdb] branch prototype/fdb-layer updated: Reinitialize
chttpd_auth_cache on config change
This is an automated email from the ASF dual-hosted git repository.
davisp pushed a commit to branch prototype/fdb-layer
in repository https://gitbox.apache.org/repos/asf/couchdb.git
The following commit(s) were added to refs/heads/prototype/fdb-layer by this push:
new 4317652 Reinitialize chttpd_auth_cache on config change
4317652 is described below
commit 43176522a492d064f925e5562660836dd416fa5a
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Fri Jul 12 12:42:17 2019 -0500
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.
---
src/chttpd/src/chttpd_auth_cache.erl | 58 +++++++++++++++++++++++----
src/fabric/src/fabric2_db.erl | 6 ++-
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 e986af6..9eee196 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 43d555c..7114903 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 0df3a78..e103314 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