You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2017/03/14 19:26:15 UTC
[20/50] couch-replicator commit: updated refs/heads/63012-scheduler
to 27a5eae
Fix transient replications authorization
Previously non-admin user could replace or cancel a replication job created
by admin or other users.
Allow replacement and cancelation only for admin and matching user.
Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-replicator/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-replicator/commit/b68d79e1
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-replicator/tree/b68d79e1
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-replicator/diff/b68d79e1
Branch: refs/heads/63012-scheduler
Commit: b68d79e118e54c4e9a70132d2f3bee4e77c7d9db
Parents: 1ad72e3
Author: Nick Vatamaniuc <va...@apache.org>
Authored: Wed Nov 2 21:39:36 2016 -0400
Committer: Nick Vatamaniuc <va...@apache.org>
Committed: Tue Nov 8 16:41:48 2016 -0500
----------------------------------------------------------------------
src/couch_replicator.erl | 99 +++++++++++++++++++++++++++++++++----------
1 file changed, 77 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-couch-replicator/blob/b68d79e1/src/couch_replicator.erl
----------------------------------------------------------------------
diff --git a/src/couch_replicator.erl b/src/couch_replicator.erl
index 0a159c3..59fb292 100644
--- a/src/couch_replicator.erl
+++ b/src/couch_replicator.erl
@@ -52,13 +52,20 @@ replicate(PostBody, Ctx) ->
#rep{id = RepId, options = Options, user_ctx = UserCtx} = Rep,
case get_value(cancel, Options, false) of
true ->
- case get_value(id, Options, nil) of
+ CancelRepId = case get_value(id, Options, nil) of
nil ->
- cancel_replication(RepId);
+ RepId;
RepId2 ->
- cancel_replication(RepId2, UserCtx)
+ RepId2
+ end,
+ case check_authorization(CancelRepId, UserCtx) of
+ ok ->
+ cancel_replication(CancelRepId);
+ not_found ->
+ {error, not_found}
end;
false ->
+ check_authorization(RepId, UserCtx),
{ok, Listener} = rep_result_listener(RepId),
Result = do_replication_loop(Rep),
couch_replicator_notifier:stop(Listener),
@@ -131,25 +138,6 @@ cancel_replication({BasedId, Extension} = RepId) ->
end.
--spec cancel_replication(rep_id(), #user_ctx{}) ->
- {ok, {cancelled, binary()}} | {error, not_found}.
-cancel_replication(RepId, #user_ctx{name = Name, roles = Roles}) ->
- case lists:member(<<"_admin">>, Roles) of
- true ->
- cancel_replication(RepId);
- false ->
- case couch_replicator_scheduler:rep_state(RepId) of
- #rep{user_ctx = #user_ctx{name = Name}} ->
- cancel_replication(RepId);
- #rep{user_ctx = #user_ctx{name = _Other}} ->
- throw({unauthorized,
- <<"Can't cancel a replication triggered by another user">>});
- nil ->
- {error, not_found}
- end
- end.
-
-
-spec replication_states() -> [atom()].
replication_states() ->
?REPLICATION_STATES.
@@ -305,3 +293,70 @@ doc_from_db(RepDb, DocId, UserCtx) ->
{not_found, _Reason} ->
{error, not_found}
end.
+
+
+-spec check_authorization(rep_id(), #user_ctx{}) -> ok | not_found.
+check_authorization(RepId, #user_ctx{name = Name} = Ctx) ->
+ case couch_replicator_scheduler:rep_state(RepId) of
+ #rep{user_ctx = #user_ctx{name = Name}} ->
+ ok;
+ #rep{} ->
+ couch_httpd:verify_is_server_admin(Ctx);
+ nil ->
+ not_found
+ end.
+
+
+-ifdef(TEST).
+
+-include_lib("eunit/include/eunit.hrl").
+
+authorization_test_() ->
+ {
+ foreach,
+ fun () -> ok end,
+ fun (_) -> meck:unload() end,
+ [
+ t_admin_is_always_authorized(),
+ t_username_must_match(),
+ t_replication_not_found()
+ ]
+ }.
+
+
+t_admin_is_always_authorized() ->
+ ?_test(begin
+ expect_rep_user_ctx(<<"someuser">>, <<"_admin">>),
+ UserCtx = #user_ctx{name = <<"adm">>, roles = [<<"_admin">>]},
+ ?assertEqual(ok, check_authorization(<<"RepId">>, UserCtx))
+ end).
+
+
+t_username_must_match() ->
+ ?_test(begin
+ expect_rep_user_ctx(<<"user">>, <<"somerole">>),
+ UserCtx1 = #user_ctx{name = <<"user">>, roles = [<<"somerole">>]},
+ ?assertEqual(ok, check_authorization(<<"RepId">>, UserCtx1)),
+ UserCtx2 = #user_ctx{name = <<"other">>, roles = [<<"somerole">>]},
+ ?assertThrow({unauthorized, _}, check_authorization(<<"RepId">>, UserCtx2))
+ end).
+
+
+t_replication_not_found() ->
+ ?_test(begin
+ meck:expect(couch_replicator_scheduler, rep_state, 1, nil),
+ UserCtx1 = #user_ctx{name = <<"user">>, roles = [<<"somerole">>]},
+ ?assertEqual(not_found, check_authorization(<<"RepId">>, UserCtx1)),
+ UserCtx2 = #user_ctx{name = <<"adm">>, roles = [<<"_admin">>]},
+ ?assertEqual(not_found, check_authorization(<<"RepId">>, UserCtx2))
+ end).
+
+
+expect_rep_user_ctx(Name, Role) ->
+ meck:expect(couch_replicator_scheduler, rep_state,
+ fun(_Id) ->
+ UserCtx = #user_ctx{name = Name, roles = [Role]},
+ #rep{user_ctx = UserCtx}
+ end).
+
+-endif.