Only admins access _users _all_docs on 5984 When couch_httpd_auth/users_db_public is set to false and the _users DB is on the admin interface (5986) only admins can read the _all_docs view.
This commit creates the same behaviour on the clustered interface (5984) when chttpd_auth/users_db_public is set to false. COUCHDB-2452 5/? Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/569b00f3 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/569b00f3 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/569b00f3 Branch: refs/heads/2452-users-db-security-on-clustered-interface Commit: 569b00f301232a4b4ce2e038ef5bdf92c3b52079 Parents: 593462c Author: Mike Wallace <[email protected]> Authored: Mon Nov 10 23:41:35 2014 +0000 Committer: Mike Wallace <[email protected]> Committed: Mon Nov 10 23:41:35 2014 +0000 ---------------------------------------------------------------------- src/chttpd_db.erl | 54 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/569b00f3/src/chttpd_db.erl ---------------------------------------------------------------------- diff --git a/src/chttpd_db.erl b/src/chttpd_db.erl index 695e540..38a3e9e 100644 --- a/src/chttpd_db.erl +++ b/src/chttpd_db.erl @@ -258,9 +258,23 @@ delete_db_req(#httpd{}=Req, DbName) -> throw(Error) end. +% TODO this duplicates code in couch_db:maybe_add_sys_db_callbacks/2. generalize and put somewhere sensible +% though only sys DBs which we'd allow on 5984, so _replicator and _users +get_db_options(DbName) -> + IsReplicatorDb = DbName == config:get("replicator", "db", "_replicator"), + IsUsersDb = DbName ==config:get("chttpd_auth", "authentication_db", "_users") orelse + binary_to_list(mem3:dbname(DbName)) == config:get("chttpd_auth", "authentication_db", "_users"), + case {IsReplicatorDb, IsUsersDb} of + {false, false} -> + []; + _Else -> + [sys_db] + end. + do_db_req(#httpd{path_parts=[DbName|_], user_ctx=Ctx}=Req, Fun) -> cassim:get_security(DbName, [{user_ctx,Ctx}]), % calls check_is_reader - Fun(Req, #db{name=DbName, user_ctx=Ctx}). + Options = get_db_options(DbName), + Fun(Req, #db{name=DbName, user_ctx=Ctx, options=Options}). db_req(#httpd{method='GET',path_parts=[DbName]}=Req, _Db) -> % measure the time required to generate the etag, see if it's worth it @@ -426,9 +440,9 @@ db_req(#httpd{path_parts=[_,<<"_purge">>]}=Req, _Db) -> db_req(#httpd{method='GET',path_parts=[_,<<"_all_docs">>]}=Req, Db) -> case chttpd:qs_json_value(Req, "keys", nil) of Keys when is_list(Keys) -> - all_docs_view(Req, Db, Keys); + all_docs_req(Req, Db, Keys); nil -> - all_docs_view(Req, Db, undefined); + all_docs_req(Req, Db, undefined); _ -> throw({bad_request, "`keys` parameter must be an array."}) end; @@ -437,9 +451,9 @@ db_req(#httpd{method='POST',path_parts=[_,<<"_all_docs">>]}=Req, Db) -> {Fields} = chttpd:json_body_obj(Req), case couch_util:get_value(<<"keys">>, Fields, nil) of Keys when is_list(Keys) -> - all_docs_view(Req, Db, Keys); + all_docs_req(Req, Db, Keys); nil -> - all_docs_view(Req, Db, undefined); + all_docs_req(Req, Db, undefined); _ -> throw({bad_request, "`keys` body member must be an array."}) end; @@ -542,6 +556,36 @@ db_req(#httpd{path_parts=[_, DocId]}=Req, Db) -> db_req(#httpd{path_parts=[_, DocId | FileNameParts]}=Req, Db) -> db_attachment_req(Req, Db, DocId, FileNameParts). +all_docs_req(Req, Db, Keys) -> + case couch_db:is_system_db(Db) of + true -> + case (catch couch_db:check_is_admin(Db)) of + ok -> + all_docs_view(Req, Db, Keys); + _ -> + DbName = ?b2l(Db#db.name), + case config:get("chttpd_auth", + "authentication_db", + "_users") of + DbName -> + UsersDbPublic = config:get("chttpd_auth", "users_db_public", "false"), + PublicFields = config:get("chttpd_auth", "public_fields"), + case {UsersDbPublic, PublicFields} of + {"true", PublicFields} when PublicFields =/= undefined -> + all_docs_view(Req, Db, Keys); + {_, _} -> + throw({forbidden, <<"Only admins can access _all_docs", + " of system databases.">>}) + end; + _ -> + throw({forbidden, <<"Only admins can access _all_docs", + " of system databases.">>}) + end + end; + false -> + all_docs_view(Req, Db, Keys) + end. + all_docs_view(Req, Db, Keys) -> Args0 = couch_mrview_http:parse_params(Req, Keys), ETagFun = fun(Sig, Acc0) ->
