summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjiangphcn <jiangph@cn.ibm.com>2017-12-15 15:07:04 +0800
committerJan Lehnardt <jan@apache.org>2018-01-23 12:38:30 +0100
commitd16f2db901c9b3b24c7189acfec35ec42895bd25 (patch)
tree66a013dc5f0c8ab3a76bc0825756862950b43175
parentb2e0e13d9a3b0d24575e4813a147a28251db49ee (diff)
downloadcouchdb-d16f2db901c9b3b24c7189acfec35ec42895bd25.tar.gz
Make peruser database prefix configurable
Fixes #876
-rw-r--r--rel/overlay/etc/default.ini4
-rw-r--r--src/couch_peruser/src/couch_peruser.erl52
-rw-r--r--src/couch_peruser/test/couch_peruser_test.erl68
3 files changed, 105 insertions, 19 deletions
diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index c473495fe..7e429f624 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -91,6 +91,10 @@ delete_dbs = false
; Set a default q value for peruser-created databases that is different from
; cluster / q
;q = 1
+; prefix for user databases. If you change this after user dbs have been
+; created, the existing databases won’t get deleted if the associated user
+; gets deleted because of the then prefix mismatch.
+database_prefix = userdb-
[httpd]
port = {{backend_port}}
diff --git a/src/couch_peruser/src/couch_peruser.erl b/src/couch_peruser/src/couch_peruser.erl
index bbf40126c..886fb4f6e 100644
--- a/src/couch_peruser/src/couch_peruser.erl
+++ b/src/couch_peruser/src/couch_peruser.erl
@@ -35,7 +35,8 @@
delete_dbs :: boolean(),
changes_pid :: pid(),
changes_ref :: reference(),
- q_for_peruser_db :: integer()
+ q_for_peruser_db :: integer(),
+ peruser_dbname_prefix :: binary()
}).
-record(state, {
@@ -45,10 +46,11 @@
states :: list(),
mem3_cluster_pid :: pid(),
cluster_stable :: boolean(),
- q_for_peruser_db :: integer()
+ q_for_peruser_db :: integer(),
+ peruser_dbname_prefix :: binary()
}).
--define(USERDB_PREFIX, "userdb-").
+-define(DEFAULT_USERDB_PREFIX, "userdb-").
-define(RELISTEN_DELAY, 5000).
-define(DEFAULT_QUIET_PERIOD, 60). % seconds
-define(DEFAULT_START_PERIOD, 5). % seconds
@@ -73,6 +75,14 @@ init_state() ->
"couch_httpd_auth", "authentication_db", "_users")),
DeleteDbs = config:get_boolean("couch_peruser", "delete_dbs", false),
Q = config:get_integer("couch_peruser", "q", 1),
+ Prefix = config:get("couch_peruser", "database_prefix", ?DEFAULT_USERDB_PREFIX),
+ case couch_db:validate_dbname(Prefix) of
+ ok -> ok;
+ Error ->
+ couch_log:error("couch_peruser can't proceed as illegal database prefix ~p.
+ Error: ~p", [Prefix, Error]),
+ throw(Error)
+ end,
% set up cluster-stable listener
@@ -90,7 +100,8 @@ init_state() ->
delete_dbs = DeleteDbs,
mem3_cluster_pid = Mem3Cluster,
cluster_stable = false,
- q_for_peruser_db = Q
+ q_for_peruser_db = Q,
+ peruser_dbname_prefix = ?l2b(Prefix)
}
end.
@@ -100,7 +111,8 @@ start_listening(#state{states=ChangesStates}=State)
when length(ChangesStates) > 0 ->
% couch_log:debug("peruser: start_listening() already run on node ~p in pid ~p", [node(), self()]),
State;
-start_listening(#state{db_name=DbName, delete_dbs=DeleteDbs, q_for_peruser_db = Q} = State) ->
+start_listening(#state{db_name=DbName, delete_dbs=DeleteDbs,
+ q_for_peruser_db = Q, peruser_dbname_prefix = Prefix} = State) ->
% couch_log:debug("peruser: start_listening() on node ~p", [node()]),
try
States = lists:map(fun (A) ->
@@ -108,7 +120,8 @@ start_listening(#state{db_name=DbName, delete_dbs=DeleteDbs, q_for_peruser_db =
parent = State#state.parent,
db_name = A#shard.name,
delete_dbs = DeleteDbs,
- q_for_peruser_db = Q
+ q_for_peruser_db = Q,
+ peruser_dbname_prefix = Prefix
},
{Pid, Ref} = spawn_opt(
?MODULE, init_changes_handler, [S], [link, monitor]),
@@ -144,7 +157,8 @@ init_changes_handler(#changes_state{db_name=DbName} = ChangesState) ->
changes_handler(
{change, {Doc}, _Prepend},
_ResType,
- ChangesState=#changes_state{db_name=DbName, q_for_peruser_db = Q}) ->
+ ChangesState=#changes_state{db_name=DbName, q_for_peruser_db = Q,
+ peruser_dbname_prefix = Prefix}) ->
% couch_log:debug("peruser: changes_handler() on DbName/Doc ~p/~p", [DbName, Doc]),
case couch_util:get_value(<<"id">>, Doc) of
@@ -153,16 +167,16 @@ changes_handler(
true ->
case couch_util:get_value(<<"deleted">>, Doc, false) of
false ->
- UserDb = ensure_user_db(User, Q),
+ UserDb = ensure_user_db(Prefix, User, Q),
ok = ensure_security(User, UserDb, fun add_user/3),
ChangesState;
true ->
case ChangesState#changes_state.delete_dbs of
true ->
- _UserDb = delete_user_db(User),
+ _UserDb = delete_user_db(Prefix, User),
ChangesState;
false ->
- UserDb = user_db_name(User),
+ UserDb = user_db_name(Prefix, User),
ok = ensure_security(User, UserDb, fun remove_user/3),
ChangesState
end
@@ -207,9 +221,9 @@ should_handle_doc_int(ShardName, DocId) ->
false
end.
--spec delete_user_db(User :: binary()) -> binary().
-delete_user_db(User) ->
- UserDb = user_db_name(User),
+-spec delete_user_db(Prefix:: binary(), User :: binary()) -> binary().
+delete_user_db(Prefix, User) ->
+ UserDb = user_db_name(Prefix, User),
try
case fabric:delete_db(UserDb, [?ADMIN_CTX]) of
ok -> ok;
@@ -220,9 +234,9 @@ delete_user_db(User) ->
end,
UserDb.
--spec ensure_user_db(User :: binary(), Q :: integer()) -> binary().
-ensure_user_db(User, Q) ->
- UserDb = user_db_name(User),
+-spec ensure_user_db(Prefix:: binary(), User :: binary(), Q :: integer()) -> binary().
+ensure_user_db(Prefix, User, Q) ->
+ UserDb = user_db_name(Prefix, User),
try
{ok, _DbInfo} = fabric:get_db_info(UserDb)
catch error:database_does_not_exist ->
@@ -300,11 +314,11 @@ ensure_security(User, UserDb, TransformFun) ->
end
end.
--spec user_db_name(User :: binary()) -> binary().
-user_db_name(User) ->
+-spec user_db_name(Prefix :: binary(), User :: binary()) -> binary().
+user_db_name(Prefix, User) ->
HexUser = list_to_binary(
[string:to_lower(integer_to_list(X, 16)) || <<X>> <= User]),
- <<?USERDB_PREFIX,HexUser/binary>>.
+ <<Prefix/binary,HexUser/binary>>.
-spec exit_changes(State :: #state{}) -> ok.
exit_changes(State) ->
diff --git a/src/couch_peruser/test/couch_peruser_test.erl b/src/couch_peruser/test/couch_peruser_test.erl
index 1ce1964ed..f6ef88f0b 100644
--- a/src/couch_peruser/test/couch_peruser_test.erl
+++ b/src/couch_peruser/test/couch_peruser_test.erl
@@ -156,6 +156,20 @@ should_create_user_db_with_default(TestAuthDb) ->
?_assertEqual(1, couch_util:get_value(q, ClusterInfo))
].
+should_create_user_db_with_custom_prefix(TestAuthDb) ->
+ set_config("couch_peruser", "database_prefix", "newuserdb-"),
+ create_user(TestAuthDb, "fooo"),
+ wait_for_db_create(<<"newuserdb-666f6f6f">>),
+ delete_config("couch_peruser", "database_prefix", "newuserdb-"),
+ ?_assert(lists:member(<<"newuserdb-666f6f6f">>, all_dbs())).
+
+should_create_user_db_with_custom_special_prefix(TestAuthDb) ->
+ set_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+ create_user(TestAuthDb, "fooo"),
+ wait_for_db_create(<<"userdb_$()+--/666f6f6f">>),
+ delete_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+ ?_assert(lists:member(<<"userdb_$()+--/666f6f6f">>, all_dbs())).
+
should_create_anon_user_db_with_default(TestAuthDb) ->
create_anon_user(TestAuthDb, "fooo"),
wait_for_db_create(<<"userdb-666f6f6f">>),
@@ -166,6 +180,20 @@ should_create_anon_user_db_with_default(TestAuthDb) ->
?_assertEqual(1, couch_util:get_value(q, ClusterInfo))
].
+should_create_anon_user_db_with_custom_prefix(TestAuthDb) ->
+ set_config("couch_peruser", "database_prefix", "newuserdb-"),
+ create_anon_user(TestAuthDb, "fooo"),
+ wait_for_db_create(<<"newuserdb-666f6f6f">>),
+ delete_config("couch_peruser", "database_prefix", "newuserdb-"),
+ ?_assert(lists:member(<<"newuserdb-666f6f6f">>, all_dbs())).
+
+should_create_anon_user_db_with_custom_special_prefix(TestAuthDb) ->
+ set_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+ create_anon_user(TestAuthDb, "fooo"),
+ wait_for_db_create(<<"userdb_$()+--/666f6f6f">>),
+ delete_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+ ?_assert(lists:member(<<"userdb_$()+--/666f6f6f">>, all_dbs())).
+
should_create_user_db_with_q4(TestAuthDb) ->
set_config("couch_peruser", "q", "4"),
create_user(TestAuthDb, "foo"),
@@ -214,6 +242,40 @@ should_delete_user_db(TestAuthDb) ->
AfterDelete = lists:member(UserDbName, all_dbs()),
[?_assert(AfterCreate), ?_assertNot(AfterDelete)].
+should_delete_user_db_with_custom_prefix(TestAuthDb) ->
+ User = "bar",
+ UserDbName = <<"newuserdb-626172">>,
+ set_config("couch_peruser", "delete_dbs", "true"),
+ set_config("couch_peruser", "database_prefix", "newuserdb-"),
+ create_user(TestAuthDb, User),
+ wait_for_db_create(UserDbName),
+ AfterCreate = lists:member(UserDbName, all_dbs()),
+ delete_user(TestAuthDb, User),
+ wait_for_db_delete(UserDbName),
+ delete_config("couch_peruser", "database_prefix", "newuserdb-"),
+ AfterDelete = lists:member(UserDbName, all_dbs()),
+ [
+ ?_assert(AfterCreate),
+ ?_assertNot(AfterDelete)
+ ].
+
+should_delete_user_db_with_custom_special_prefix(TestAuthDb) ->
+ User = "bar",
+ UserDbName = <<"userdb_$()+--/626172">>,
+ set_config("couch_peruser", "delete_dbs", "true"),
+ set_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+ create_user(TestAuthDb, User),
+ wait_for_db_create(UserDbName),
+ AfterCreate = lists:member(UserDbName, all_dbs()),
+ delete_user(TestAuthDb, User),
+ wait_for_db_delete(UserDbName),
+ delete_config("couch_peruser", "database_prefix", "userdb_$()+--/"),
+ AfterDelete = lists:member(UserDbName, all_dbs()),
+ [
+ ?_assert(AfterCreate),
+ ?_assertNot(AfterDelete)
+ ].
+
should_reflect_config_changes(TestAuthDb) ->
User = "baz",
UserDbName = <<"userdb-62617a">>,
@@ -445,11 +507,17 @@ couch_peruser_test_() ->
fun setup/0, fun teardown/1,
[
fun should_create_anon_user_db_with_default/1,
+ fun should_create_anon_user_db_with_custom_prefix/1,
+ fun should_create_anon_user_db_with_custom_special_prefix/1,
fun should_create_user_db_with_default/1,
+ fun should_create_user_db_with_custom_prefix/1,
+ fun should_create_user_db_with_custom_special_prefix/1,
fun should_create_user_db_with_q4/1,
fun should_create_anon_user_db_with_q4/1,
fun should_not_delete_user_db/1,
fun should_delete_user_db/1,
+ fun should_delete_user_db_with_custom_prefix/1,
+ fun should_delete_user_db_with_custom_special_prefix/1,
fun should_reflect_config_changes/1,
fun should_add_user_to_db_admins/1,
fun should_add_user_to_db_members/1,