You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ja...@apache.org on 2019/08/26 08:09:57 UTC
[couchdb] branch access updated (5ca0d46 -> a4fea48)
This is an automated email from the ASF dual-hosted git repository.
jan pushed a change to branch access
in repository https://gitbox.apache.org/repos/asf/couchdb.git.
from 5ca0d46 feat: implement _users role handling
new dade59f test: add two more tests and reformat for eadability
new 7f26e04 feat: conflicted docs are admin-only
new 2a5f506 feat: forbid querying non _users ddocs
new 73acc3c feat: allow querying _users ddocs
new bde3a72 test: doc updates
new a4fea48 feat: add _users ddocs to _all_docs
The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
rel/overlay/etc/default.ini | 2 +-
src/chttpd/src/chttpd_view.erl | 9 +
src/couch/src/couch_db.erl | 29 +++-
src/couch/src/couch_db_updater.erl | 1 +
src/couch/src/couch_doc.erl | 4 +
src/couch/test/couchdb_access_tests.erl | 262 +++++++++++++++++++++++++----
src/couch_mrview/src/couch_mrview.erl | 47 +++++-
src/couch_mrview/src/couch_mrview_http.erl | 4 +-
8 files changed, 307 insertions(+), 51 deletions(-)
[couchdb] 01/06: test: add two more tests and reformat for
eadability
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jan pushed a commit to branch access
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit dade59f92177943b679fc269945757f90909939f
Author: Jan Lehnardt <ja...@apache.org>
AuthorDate: Sun Aug 25 14:29:21 2019 +0200
test: add two more tests and reformat for eadability
---
src/couch/test/couchdb_access_tests.erl | 125 +++++++++++++++++++++++---------
1 file changed, 89 insertions(+), 36 deletions(-)
diff --git a/src/couch/test/couchdb_access_tests.erl b/src/couch/test/couchdb_access_tests.erl
index 74ee77c..e386f60 100644
--- a/src/couch/test/couchdb_access_tests.erl
+++ b/src/couch/test/couchdb_access_tests.erl
@@ -66,11 +66,13 @@ access_test_() ->
Tests = [
fun should_not_let_anonymous_user_create_doc/2,
fun should_let_admin_create_doc_with_access/2,
+ fun should_let_admin_create_doc_without_access/2,
fun should_let_user_create_doc_for_themselves/2,
fun should_not_let_user_create_doc_for_someone_else/2,
fun should_let_admin_read_doc_with_access/2,
fun user_with_access_can_read_doc/2,
fun user_without_access_can_not_read_doc/2,
+ fun user_can_not_read_doc_without_access/2,
fun should_let_admin_delete_doc_with_access/2,
fun should_let_user_delete_doc_for_themselves/2,
fun should_not_let_user_delete_doc_for_someone_else/2,
@@ -78,6 +80,9 @@ access_test_() ->
fun should_let_user_fetch_their_own_all_docs/2,
fun should_let_admin_fetch_changes/2,
fun should_let_user_fetch_their_own_changes/2
+ % TODO: create test db with role and not _users in _security.members
+ % and make sure a user in that group can access while a user not
+ % in that group cant
],
{
"Access tests",
@@ -103,87 +108,135 @@ should_not_let_anonymous_user_create_doc(_PortType, Url) ->
?_assertEqual(401, Code).
should_let_admin_create_doc_with_access(_PortType, Url) ->
- {ok, Code, _, _} = test_request:put(Url ++ "/db/a", ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ ?_assertEqual(201, Code).
+
+should_let_admin_create_doc_without_access(_PortType, Url) ->
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1}"),
?_assertEqual(201, Code).
should_let_user_create_doc_for_themselves(_PortType, Url) ->
- {ok, Code, _, _} = test_request:put(Url ++ "/db/b", ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/b",
+ ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
?_assertEqual(201, Code).
should_not_let_user_create_doc_for_someone_else(_PortType, Url) ->
- {ok, Code, _, _} = test_request:put(Url ++ "/db/c", ?USERY_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/c",
+ ?USERY_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
?_assertEqual(403, Code).
% Doc reads
should_let_admin_read_doc_with_access(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a", ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:get(Url ++ "/db/a", ?ADMIN_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS),
?_assertEqual(200, Code).
user_with_access_can_read_doc(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a", ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:get(Url ++ "/db/a", ?USERX_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
+ ?USERX_REQ_HEADERS),
?_assertEqual(200, Code).
user_without_access_can_not_read_doc(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a", ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:get(Url ++ "/db/a", ?USERY_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
+ ?USERY_REQ_HEADERS),
+ ?_assertEqual(403, Code).
+
+user_can_not_read_doc_without_access(_PortType, Url) ->
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1}"),
+ {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
+ ?USERX_REQ_HEADERS),
?_assertEqual(403, Code).
% Doc deletes
should_let_admin_delete_doc_with_access(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a", ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:delete(Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5", ?ADMIN_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:delete(Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5",
+ ?ADMIN_REQ_HEADERS),
?_assertEqual(201, Code).
should_let_user_delete_doc_for_themselves(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a", ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, _, _, _} = test_request:get(Url ++ "/db/a", ?USERX_REQ_HEADERS),
- {ok, Code, _, _} = test_request:delete(Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5", ?USERX_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, _, _, _} = test_request:get(Url ++ "/db/a",
+ ?USERX_REQ_HEADERS),
+ {ok, Code, _, _} = test_request:delete(Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5",
+ ?USERX_REQ_HEADERS),
?_assertEqual(201, Code).
should_not_let_user_delete_doc_for_someone_else(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a", ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, Code, _, _} = test_request:delete(Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5", ?USERY_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:delete(Url ++ "/db/a?rev=1-23202479633c2b380f79507a776743d5",
+ ?USERY_REQ_HEADERS),
?_assertEqual(403, Code).
% _all_docs with include_docs
should_let_admin_fetch_all_docs(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a", ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/b", ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/c", ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/d", ?ADMIN_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
- {ok, 200, _, Body} = test_request:get(Url ++ "/db/_all_docs?include_docs=true", ?ADMIN_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/d",
+ ?ADMIN_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
+ {ok, 200, _, Body} = test_request:get(Url ++ "/db/_all_docs?include_docs=true",
+ ?ADMIN_REQ_HEADERS),
{Json} = jiffy:decode(Body),
?_assertEqual(4, proplists:get_value(<<"total_rows">>, Json)).
should_let_user_fetch_their_own_all_docs(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a", ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/b", ?USERX_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/c", ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/d", ?USERY_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
- {ok, 200, _, Body} = test_request:get(Url ++ "/db/_all_docs?include_docs=true", ?USERX_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/b",
+ ?USERX_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/d",
+ ?USERY_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
+ {ok, 200, _, Body} = test_request:get(Url ++ "/db/_all_docs?include_docs=true",
+ ?USERX_REQ_HEADERS),
{Json} = jiffy:decode(Body),
?_assertEqual(2, length(proplists:get_value(<<"rows">>, Json))).
% TODO ?_assertEqual(2, proplists:get_value(<<"total_rows">>, Json)).
% _changes
should_let_admin_fetch_changes(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a", ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/b", ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/c", ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/d", ?ADMIN_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
- {ok, 200, _, Body} = test_request:get(Url ++ "/db/_changes", ?ADMIN_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/d",
+ ?ADMIN_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
+ {ok, 200, _, Body} = test_request:get(Url ++ "/db/_changes",
+ ?ADMIN_REQ_HEADERS),
{Json} = jiffy:decode(Body),
AmountOfDocs = length(proplists:get_value(<<"results">>, Json)),
?_assertEqual(4, AmountOfDocs).
should_let_user_fetch_their_own_changes(_PortType, Url) ->
- {ok, 201, _, _} = test_request:put(Url ++ "/db/a", ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/b", ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/c", ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
- {ok, 201, _, _} = test_request:put(Url ++ "/db/d", ?ADMIN_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
- {ok, 200, _, Body} = test_request:get(Url ++ "/db/_changes", ?USERX_REQ_HEADERS),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/b",
+ ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/d",
+ ?ADMIN_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
+ {ok, 200, _, Body} = test_request:get(Url ++ "/db/_changes",
+ ?USERX_REQ_HEADERS),
{Json} = jiffy:decode(Body),
AmountOfDocs = length(proplists:get_value(<<"results">>, Json)),
?_assertEqual(2, AmountOfDocs).
[couchdb] 03/06: feat: forbid querying non _users ddocs
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jan pushed a commit to branch access
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 2a5f506ef31ba258a282e30b4cfb19c115ca6976
Author: Jan Lehnardt <ja...@apache.org>
AuthorDate: Sun Aug 25 16:22:59 2019 +0200
feat: forbid querying non _users ddocs
---
src/chttpd/src/chttpd_view.erl | 9 +++++++++
src/couch/src/couch_db.erl | 1 +
src/couch/test/couchdb_access_tests.erl | 23 ++++++++++++++++++++++-
src/couch_mrview/src/couch_mrview_http.erl | 4 +---
4 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/src/chttpd/src/chttpd_view.erl b/src/chttpd/src/chttpd_view.erl
index 3c05c64..4d1b80a 100644
--- a/src/chttpd/src/chttpd_view.erl
+++ b/src/chttpd/src/chttpd_view.erl
@@ -16,6 +16,12 @@
-export([handle_view_req/3, handle_temp_view_req/2]).
+validate_design_access(DDoc) ->
+ is_users_ddoc(DDoc).
+
+is_users_ddoc(#doc{access=[<<"_users">>]}) -> ok;
+is_users_ddoc(_) -> throw({forbidden, <<"per-user ddoc access">>}).
+
multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
Args0 = couch_mrview_http:parse_params(Req, undefined),
{ok, #mrst{views=Views}} = couch_mrview_util:ddoc_to_mrst(Db, DDoc),
@@ -51,6 +57,7 @@ design_doc_view(Req, Db, DDoc, ViewName, Keys) ->
handle_view_req(#httpd{method='POST',
path_parts=[_, _, _, _, ViewName, <<"queries">>]}=Req, Db, DDoc) ->
+ ok = validate_design_access(DDoc),
chttpd:validate_ctype(Req, "application/json"),
Props = couch_httpd:json_body_obj(Req),
case couch_mrview_util:get_view_queries(Props) of
@@ -67,12 +74,14 @@ handle_view_req(#httpd{path_parts=[_, _, _, _, _, <<"queries">>]}=Req,
handle_view_req(#httpd{method='GET',
path_parts=[_, _, _, _, ViewName]}=Req, Db, DDoc) ->
+ ok = validate_design_access(DDoc),
couch_stats:increment_counter([couchdb, httpd, view_reads]),
Keys = chttpd:qs_json_value(Req, "keys", undefined),
design_doc_view(Req, Db, DDoc, ViewName, Keys);
handle_view_req(#httpd{method='POST',
path_parts=[_, _, _, _, ViewName]}=Req, Db, DDoc) ->
+ ok = validate_design_access(DDoc),
chttpd:validate_ctype(Req, "application/json"),
Props = couch_httpd:json_body_obj(Req),
Keys = couch_mrview_util:get_view_keys(Props),
diff --git a/src/couch/src/couch_db.erl b/src/couch/src/couch_db.erl
index 7aeb3d1..a4d0e67 100644
--- a/src/couch/src/couch_db.erl
+++ b/src/couch/src/couch_db.erl
@@ -32,6 +32,7 @@
check_is_member/1,
validate_access/2,
check_access/2,
+ has_access_enabled/1,
name/1,
get_after_doc_read_fun/1,
diff --git a/src/couch/test/couchdb_access_tests.erl b/src/couch/test/couchdb_access_tests.erl
index 8058bd5..52d870c 100644
--- a/src/couch/test/couchdb_access_tests.erl
+++ b/src/couch/test/couchdb_access_tests.erl
@@ -85,7 +85,10 @@ access_test_() ->
fun should_let_user_fetch_their_own_all_docs/2,
fun should_let_admin_fetch_changes/2,
- fun should_let_user_fetch_their_own_changes/2
+ fun should_let_user_fetch_their_own_changes/2,
+
+ fun should_not_allow_admin_access_ddoc_view_request/2,
+ fun should_not_allow_user_access_ddoc_view_request/2
% TODO: create test db with role and not _users in _security.members
% and make sure a user in that group can access while a user not
@@ -266,6 +269,24 @@ should_let_user_fetch_their_own_changes(_PortType, Url) ->
AmountOfDocs = length(proplists:get_value(<<"results">>, Json)),
?_assertEqual(2, AmountOfDocs).
+should_not_allow_admin_access_ddoc_view_request(_PortType, Url) ->
+ DDoc = "{\"a\":1,\"_access\":[\"x\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
+ ?ADMIN_REQ_HEADERS, DDoc),
+ ?_assertEqual(201, Code),
+ {ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
+ ?ADMIN_REQ_HEADERS),
+ ?_assertEqual(403, Code1).
+
+should_not_allow_user_access_ddoc_view_request(_PortType, Url) ->
+ DDoc = "{\"a\":1,\"_access\":[\"x\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
+ ?ADMIN_REQ_HEADERS, DDoc),
+ ?_assertEqual(201, Code),
+ {ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
+ ?USERX_REQ_HEADERS),
+ ?_assertEqual(403, Code1).
+
%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------
diff --git a/src/couch_mrview/src/couch_mrview_http.erl b/src/couch_mrview/src/couch_mrview_http.erl
index 004caef..7c50beb 100644
--- a/src/couch_mrview/src/couch_mrview_http.erl
+++ b/src/couch_mrview/src/couch_mrview_http.erl
@@ -99,10 +99,9 @@ handle_view_changes_req(#httpd{path_parts=[_,<<"_design">>,DDocName,<<"_view_cha
ChangesFun = couch_mrview_changes:handle_view_changes(ChangesArgs, Req, Db, <<"_design/", DDocName/binary>>, ViewName),
couch_httpd_db:handle_changes_req(Req, Db, ChangesArgs, ChangesFun).
-
handle_view_req(#httpd{method='GET',
path_parts=[_, _, DDocName, _, VName, <<"_info">>]}=Req,
- Db, _DDoc) ->
+ Db, DDoc) ->
DbName = couch_db:name(Db),
DDocId = <<"_design/", DDocName/binary >>,
{ok, Info} = couch_mrview:get_view_info(DbName, DDocId, VName),
@@ -273,7 +272,6 @@ get_view_callback(_DbName, _DbName, false) ->
get_view_callback(_, _, _) ->
fun view_cb/2.
-
design_doc_view(Req, Db, DDoc, ViewName, Keys) ->
Args0 = parse_params(Req, Keys),
ETagFun = fun(Sig, Acc0) ->
[couchdb] 06/06: feat: add _users ddocs to _all_docs
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jan pushed a commit to branch access
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit a4fea4870b619b5537813c06ad7657c4afd1a4de
Author: Jan Lehnardt <ja...@apache.org>
AuthorDate: Mon Aug 26 10:09:41 2019 +0200
feat: add _users ddocs to _all_docs
---
src/couch/src/couch_db_updater.erl | 1 +
src/couch/src/couch_doc.erl | 4 +++
src/couch/test/couchdb_access_tests.erl | 25 ++++++++++++++++++
src/couch_mrview/src/couch_mrview.erl | 47 ++++++++++++++++++++++++++++++---
4 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/src/couch/src/couch_db_updater.erl b/src/couch/src/couch_db_updater.erl
index 47f1ff1..245554b 100644
--- a/src/couch/src/couch_db_updater.erl
+++ b/src/couch/src/couch_db_updater.erl
@@ -338,6 +338,7 @@ refresh_validate_doc_funs(#db{name = <<"shards/", _/binary>> = Name} = Db) ->
refresh_validate_doc_funs(Db0) ->
Db = Db0#db{user_ctx=?ADMIN_USER},
{ok, DesignDocs} = couch_db:get_design_docs(Db),
+ % TODO: filter out non-admin ddocs
ProcessDocFuns = lists:flatmap(
fun(DesignDocInfo) ->
{ok, DesignDoc} = couch_db:open_doc_int(
diff --git a/src/couch/src/couch_doc.erl b/src/couch/src/couch_doc.erl
index 76692d3..1ec31e2 100644
--- a/src/couch/src/couch_doc.erl
+++ b/src/couch/src/couch_doc.erl
@@ -399,6 +399,10 @@ is_deleted(Tree) ->
false
end.
+get_access({Props}) ->
+ get_access(couch_doc:from_json_obj({Props}));
+get_access(#doc{access=Access}) ->
+ Access.
get_validate_doc_fun({Props}) ->
get_validate_doc_fun(couch_doc:from_json_obj({Props}));
diff --git a/src/couch/test/couchdb_access_tests.erl b/src/couch/test/couchdb_access_tests.erl
index f985528..fca6bb0 100644
--- a/src/couch/test/couchdb_access_tests.erl
+++ b/src/couch/test/couchdb_access_tests.erl
@@ -92,6 +92,7 @@ access_test_() ->
% _all_docs with include_docs
fun should_let_admin_fetch_all_docs/2,
fun should_let_user_fetch_their_own_all_docs/2,
+ fun should_let_user_fetch_their_own_all_docs_plus_users_ddocs/2,
% _changes
fun should_let_admin_fetch_changes/2,
@@ -283,6 +284,30 @@ should_let_user_fetch_their_own_all_docs(_PortType, Url) ->
?_assertEqual(2, length(proplists:get_value(<<"rows">>, Json))).
% TODO ?_assertEqual(2, proplists:get_value(<<"total_rows">>, Json)).
+should_let_user_fetch_their_own_all_docs_plus_users_ddocs(_PortType, Url) ->
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/_design/foo",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"_users\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/_design/bar",
+ ?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"houdini\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/b",
+ ?USERX_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
+
+ % % TODO: add allowing non-admin users adding non-admin ddocs
+ % {ok, 201, _, _} = test_request:put(Url ++ "/db/_design/x",
+ % ?ADMIN_REQ_HEADERS, "{\"b\":2,\"_access\":[\"x\"]}"),
+
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/c",
+ ?ADMIN_REQ_HEADERS, "{\"c\":3,\"_access\":[\"y\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/d",
+ ?USERY_REQ_HEADERS, "{\"d\":4,\"_access\":[\"y\"]}"),
+ {ok, 200, _, Body} = test_request:get(Url ++ "/db/_all_docs?include_docs=true",
+ ?USERX_REQ_HEADERS),
+ {Json} = jiffy:decode(Body),
+ ?debugFmt("~nHSOIN: ~p~n", [Json]),
+ ?_assertEqual(3, length(proplists:get_value(<<"rows">>, Json))).
+
% _changes
should_let_admin_fetch_changes(_PortType, Url) ->
{ok, 201, _, _} = test_request:put(Url ++ "/db/a",
diff --git a/src/couch_mrview/src/couch_mrview.erl b/src/couch_mrview/src/couch_mrview.erl
index 72fbb92..645041b 100644
--- a/src/couch_mrview/src/couch_mrview.erl
+++ b/src/couch_mrview/src/couch_mrview.erl
@@ -280,23 +280,62 @@ query_changes_access(Db, StartSeq, Fun, Options, Acc) ->
VName = <<"_access_by_seq">>,
query_view(Db, DDoc, VName, Args, Callback, Acc).
+get_design_docs(Db) ->
+ {ok, DDocs} = couch_db:get_design_docs(Db),
+ lists:filter(fun({DDoc}) ->
+ couch_util:get_value(<<"_access">>, DDoc) =:= [<<"_users">>]
+ end, DDocs).
+
query_all_docs_access(Db, Args0, Callback0, Acc) ->
% query our not yest existing, home-grown _access view.
% use query_view for this.
DDoc = access_ddoc(),
UserCtx = couch_db:get_user_ctx(Db),
UserName = UserCtx#user_ctx.name,
- % TODO: add roles
Args1 = prefix_startkey_endkey(UserName, Args0, Args0#mrargs.direction),
Args = Args1#mrargs{reduce=false},
- % filter out the user-prefix from the key, so _all_docs looks normal
- % this isn’t a separate function because I’m binding Callback0 and I don’t
- % know the Erlang equivalent of JS’s fun.bind(this, newarg)
+
+ % get all _users design docs so we can splice them into the result
+ % in the right places
+ DDocs = get_design_docs(Db),
+ couch_log:info("~nget_user_design_docs: DDocs ~p~n", [DDocs]),
+ DDIterator = couch_iter:start(length(DDocs)),
+ % couch_log:info("~nDDocs~p~n", [DDocs]),
+
Callback = fun
({row, Props}, Acc0) ->
+
+ % filter out the user-prefix from the key, so _all_docs looks normal
+ % this isn’t a separate function because I’m binding Callback0 and I
+ % don’t know the Erlang equivalent of JS’s fun.bind(this, newarg)
+
[_User, Key] = proplists:get_value(key, Props),
Row0 = proplists:delete(key, Props),
Row = [{key, Key} | Row0],
+
+ couch_log:info("~nRow~p~n", [Row]),
+ % if new row id is > than next ddocs id, call Callback0 with ddoc
+ % id first, move DDocs iterator one forward
+ DDNextIdx = couch_iter:next(DDIterator),
+ case DDNextIdx of
+ done -> done;
+ N ->
+ {DDNext} = lists:nth(N, DDocs),
+ DDID = couch_util:get_value(<<"_id">>, DDNext),
+ DDRev = couch_util:get_value(<<"_rev">>, DDNext),
+ case Key > DDID of
+ true ->
+ DDRow = [
+ {key, DDID},
+ {id, DDID},
+ {value, DDRev},
+ {doc, {DDNext}}
+ ],
+ Callback0({row, DDRow}, Acc0);
+ _Else
+ -> ok
+ end
+ end,
Callback0({row, Row}, Acc0);
(Row, Acc0) ->
Callback0(Row, Acc0)
[couchdb] 05/06: test: doc updates
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jan pushed a commit to branch access
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit bde3a721b59ebf940c23bd7bcb170e00b98fa51d
Author: Jan Lehnardt <ja...@apache.org>
AuthorDate: Sun Aug 25 16:40:25 2019 +0200
test: doc updates
---
src/couch/test/couchdb_access_tests.erl | 52 ++++++++++++++++++++++++++++++---
1 file changed, 48 insertions(+), 4 deletions(-)
diff --git a/src/couch/test/couchdb_access_tests.erl b/src/couch/test/couchdb_access_tests.erl
index 249f005..f985528 100644
--- a/src/couch/test/couchdb_access_tests.erl
+++ b/src/couch/test/couchdb_access_tests.erl
@@ -64,12 +64,19 @@ after_all(_) ->
access_test_() ->
Tests = [
+ % Doc creation
fun should_not_let_anonymous_user_create_doc/2,
fun should_let_admin_create_doc_with_access/2,
fun should_let_admin_create_doc_without_access/2,
fun should_let_user_create_doc_for_themselves/2,
fun should_not_let_user_create_doc_for_someone_else/2,
+ % Doc updates
+ fun users_with_access_can_update_doc/2,
+ fun users_with_access_can_not_change_access/2,
+ fun users_with_access_can_not_remove_access/2,
+
+ % Doc reads
fun should_let_admin_read_doc_with_access/2,
fun user_with_access_can_read_doc/2,
fun user_without_access_can_not_read_doc/2,
@@ -77,16 +84,20 @@ access_test_() ->
fun admin_with_access_can_read_conflicted_doc/2,
fun user_with_access_can_not_read_conflicted_doc/2,
+ % Doc deletes
fun should_let_admin_delete_doc_with_access/2,
fun should_let_user_delete_doc_for_themselves/2,
fun should_not_let_user_delete_doc_for_someone_else/2,
+ % _all_docs with include_docs
fun should_let_admin_fetch_all_docs/2,
fun should_let_user_fetch_their_own_all_docs/2,
+ % _changes
fun should_let_admin_fetch_changes/2,
fun should_let_user_fetch_their_own_changes/2,
+ % views
fun should_not_allow_admin_access_ddoc_view_request/2,
fun should_not_allow_user_access_ddoc_view_request/2,
fun should_allow_admin_users_access_ddoc_view_request/2,
@@ -139,6 +150,38 @@ should_not_let_user_create_doc_for_someone_else(_PortType, Url) ->
?USERY_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
?_assertEqual(403, Code).
+% Doc updates
+
+users_with_access_can_update_doc(_PortType, Url) ->
+ {ok, _, _, Body} = test_request:put(Url ++ "/db/b",
+ ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {Json} = jiffy:decode(Body),
+ Rev = couch_util:get_value(<<"rev">>, Json),
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/b",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":2,\"_access\":[\"x\"],\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"),
+ ?_assertEqual(201, Code).
+
+users_with_access_can_not_change_access(_PortType, Url) ->
+ {ok, _, _, Body} = test_request:put(Url ++ "/db/b",
+ ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {Json} = jiffy:decode(Body),
+ Rev = couch_util:get_value(<<"rev">>, Json),
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/b",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":2,\"_access\":[\"y\"],\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"),
+ ?_assertEqual(403, Code).
+
+users_with_access_can_not_remove_access(_PortType, Url) ->
+ {ok, _, _, Body} = test_request:put(Url ++ "/db/b",
+ ?USERX_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
+ {Json} = jiffy:decode(Body),
+ Rev = couch_util:get_value(<<"rev">>, Json),
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/b",
+ ?USERX_REQ_HEADERS,
+ "{\"a\":2,\"_rev\":\"" ++ binary_to_list(Rev) ++ "\"}"),
+ ?_assertEqual(403, Code).
+
% Doc reads
should_let_admin_read_doc_with_access(_PortType, Url) ->
{ok, 201, _, _} = test_request:put(Url ++ "/db/a",
@@ -271,11 +314,12 @@ should_let_user_fetch_their_own_changes(_PortType, Url) ->
AmountOfDocs = length(proplists:get_value(<<"results">>, Json)),
?_assertEqual(2, AmountOfDocs).
+% views
should_not_allow_admin_access_ddoc_view_request(_PortType, Url) ->
DDoc = "{\"a\":1,\"_access\":[\"x\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
{ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
?ADMIN_REQ_HEADERS, DDoc),
- ?_assertEqual(201, Code),
+ ?assertEqual(201, Code),
{ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
?ADMIN_REQ_HEADERS),
?_assertEqual(403, Code1).
@@ -284,7 +328,7 @@ should_not_allow_user_access_ddoc_view_request(_PortType, Url) ->
DDoc = "{\"a\":1,\"_access\":[\"x\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
{ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
?ADMIN_REQ_HEADERS, DDoc),
- ?_assertEqual(201, Code),
+ ?assertEqual(201, Code),
{ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
?USERX_REQ_HEADERS),
?_assertEqual(403, Code1).
@@ -293,7 +337,7 @@ should_allow_admin_users_access_ddoc_view_request(_PortType, Url) ->
DDoc = "{\"a\":1,\"_access\":[\"_users\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
{ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
?ADMIN_REQ_HEADERS, DDoc),
- ?_assertEqual(201, Code),
+ ?assertEqual(201, Code),
{ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
?ADMIN_REQ_HEADERS),
?_assertEqual(200, Code1).
@@ -302,7 +346,7 @@ should_allow_user_users_access_ddoc_view_request(_PortType, Url) ->
DDoc = "{\"a\":1,\"_access\":[\"_users\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
{ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
?ADMIN_REQ_HEADERS, DDoc),
- ?_assertEqual(201, Code),
+ ?assertEqual(201, Code),
{ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
?USERX_REQ_HEADERS),
?_assertEqual(200, Code1).
[couchdb] 02/06: feat: conflicted docs are admin-only
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jan pushed a commit to branch access
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 7f26e0440fa456120686b8fe99ad258547b5d4dd
Author: Jan Lehnardt <ja...@apache.org>
AuthorDate: Sun Aug 25 15:07:02 2019 +0200
feat: conflicted docs are admin-only
---
rel/overlay/etc/default.ini | 2 +-
src/couch/src/couch_db.erl | 28 ++++++++++++++++++++++------
src/couch/test/couchdb_access_tests.erl | 25 +++++++++++++++++++++++++
3 files changed, 48 insertions(+), 7 deletions(-)
diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index 3e2e877..e8df095 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -505,7 +505,7 @@ _default = [{db_fragmentation, "70%"}, {view_fragmentation, "60%"}]
; emergency, emerg
; none
;
-level = info
+level = debug
;
; Set the maximum log message length in bytes that will be
; passed through the writer
diff --git a/src/couch/src/couch_db.erl b/src/couch/src/couch_db.erl
index 42a7176..7aeb3d1 100644
--- a/src/couch/src/couch_db.erl
+++ b/src/couch/src/couch_db.erl
@@ -271,6 +271,9 @@ wait_for_compaction(#db{main_pid=Pid}=Db, Timeout) ->
ok
end.
+has_access_enabled(#db{access=false}) -> false;
+has_access_enabled(_) -> true.
+
delete_doc(Db, Id, Revisions) ->
DeletedDocs = [#doc{id=Id, revs=[Rev], deleted=true} || Rev <- Revisions],
{ok, [Result]} = update_docs(Db, DeletedDocs, []),
@@ -279,8 +282,12 @@ delete_doc(Db, Id, Revisions) ->
open_doc(Db, IdOrDocInfo) ->
open_doc(Db, IdOrDocInfo, []).
-open_doc(Db, Id, Options) ->
+open_doc(Db, Id, Options0) ->
increment_stat(Db, [couchdb, database_reads]),
+ Options = case has_access_enabled(Db) of
+ true -> Options0 ++ [conflicts];
+ _Else -> Options0
+ end,
case open_doc_int(Db, Id, Options) of
{ok, #doc{deleted=true}=Doc} ->
case lists:member(deleted, Options) of
@@ -724,12 +731,21 @@ security_error_type(#user_ctx{name=null}) ->
security_error_type(#user_ctx{name=_}) ->
forbidden.
-validate_access(Db, Doc) ->
- validate_access1(check_access(Db, Doc)).
-
-validate_access1(true) -> ok;
-validate_access1(_) -> throw({forbidden, <<"can't touch this">>}).
+validate_access(Db, #doc{meta=Meta}=Doc) ->
+ case proplists:get_value(conflicts, Meta) of
+ undefined -> % no conflicts
+ validate_access1(Db, Doc);
+ _Else -> % only admins can read conflicted docs in _access dbs
+ case is_admin(Db) of
+ true -> ok;
+ _Else2 -> throw({forbidden, <<"document is in conflict">>})
+ end
+ end.
+validate_access1(Db, Doc) ->
+ validate_access2(check_access(Db, Doc)).
+validate_access2(true) -> ok;
+validate_access2(_) -> throw({forbidden, <<"can't touch this">>}).
check_access(Db, #doc{access=Access}=Doc) ->
% couch_log:info("~ncheck da access, Doc: ~p, Db: ~p~n", [Doc, Db]),
diff --git a/src/couch/test/couchdb_access_tests.erl b/src/couch/test/couchdb_access_tests.erl
index e386f60..8058bd5 100644
--- a/src/couch/test/couchdb_access_tests.erl
+++ b/src/couch/test/couchdb_access_tests.erl
@@ -69,17 +69,24 @@ access_test_() ->
fun should_let_admin_create_doc_without_access/2,
fun should_let_user_create_doc_for_themselves/2,
fun should_not_let_user_create_doc_for_someone_else/2,
+
fun should_let_admin_read_doc_with_access/2,
fun user_with_access_can_read_doc/2,
fun user_without_access_can_not_read_doc/2,
fun user_can_not_read_doc_without_access/2,
+ fun admin_with_access_can_read_conflicted_doc/2,
+ fun user_with_access_can_not_read_conflicted_doc/2,
+
fun should_let_admin_delete_doc_with_access/2,
fun should_let_user_delete_doc_for_themselves/2,
fun should_not_let_user_delete_doc_for_someone_else/2,
+
fun should_let_admin_fetch_all_docs/2,
fun should_let_user_fetch_their_own_all_docs/2,
+
fun should_let_admin_fetch_changes/2,
fun should_let_user_fetch_their_own_changes/2
+
% TODO: create test db with role and not _users in _security.members
% and make sure a user in that group can access while a user not
% in that group cant
@@ -142,6 +149,24 @@ user_with_access_can_read_doc(_PortType, Url) ->
?USERX_REQ_HEADERS),
?_assertEqual(200, Code).
+user_with_access_can_not_read_conflicted_doc(_PortType, Url) ->
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"_id\":\"f1\",\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a?new_edits=false",
+ ?ADMIN_REQ_HEADERS, "{\"_id\":\"f1\",\"_rev\":\"7-XYZ\",\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
+ ?USERX_REQ_HEADERS),
+ ?_assertEqual(403, Code).
+
+admin_with_access_can_read_conflicted_doc(_PortType, Url) ->
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS, "{\"_id\":\"a\",\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, 201, _, _} = test_request:put(Url ++ "/db/a?new_edits=false",
+ ?ADMIN_REQ_HEADERS, "{\"_id\":\"a\",\"_rev\":\"7-XYZ\",\"a\":1,\"_access\":[\"x\"]}"),
+ {ok, Code, _, _} = test_request:get(Url ++ "/db/a",
+ ?ADMIN_REQ_HEADERS),
+ ?_assertEqual(200, Code).
+
user_without_access_can_not_read_doc(_PortType, Url) ->
{ok, 201, _, _} = test_request:put(Url ++ "/db/a",
?ADMIN_REQ_HEADERS, "{\"a\":1,\"_access\":[\"x\"]}"),
[couchdb] 04/06: feat: allow querying _users ddocs
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
jan pushed a commit to branch access
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 73acc3cc713c44b63d0a77220519effb8c868172
Author: Jan Lehnardt <ja...@apache.org>
AuthorDate: Sun Aug 25 16:26:36 2019 +0200
feat: allow querying _users ddocs
---
src/couch/test/couchdb_access_tests.erl | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/src/couch/test/couchdb_access_tests.erl b/src/couch/test/couchdb_access_tests.erl
index 52d870c..249f005 100644
--- a/src/couch/test/couchdb_access_tests.erl
+++ b/src/couch/test/couchdb_access_tests.erl
@@ -88,7 +88,9 @@ access_test_() ->
fun should_let_user_fetch_their_own_changes/2,
fun should_not_allow_admin_access_ddoc_view_request/2,
- fun should_not_allow_user_access_ddoc_view_request/2
+ fun should_not_allow_user_access_ddoc_view_request/2,
+ fun should_allow_admin_users_access_ddoc_view_request/2,
+ fun should_allow_user_users_access_ddoc_view_request/2
% TODO: create test db with role and not _users in _security.members
% and make sure a user in that group can access while a user not
@@ -287,6 +289,24 @@ should_not_allow_user_access_ddoc_view_request(_PortType, Url) ->
?USERX_REQ_HEADERS),
?_assertEqual(403, Code1).
+should_allow_admin_users_access_ddoc_view_request(_PortType, Url) ->
+ DDoc = "{\"a\":1,\"_access\":[\"_users\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
+ ?ADMIN_REQ_HEADERS, DDoc),
+ ?_assertEqual(201, Code),
+ {ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
+ ?ADMIN_REQ_HEADERS),
+ ?_assertEqual(200, Code1).
+
+should_allow_user_users_access_ddoc_view_request(_PortType, Url) ->
+ DDoc = "{\"a\":1,\"_access\":[\"_users\"],\"views\":{\"foo\":{\"map\":\"function() {}\"}}}",
+ {ok, Code, _, _} = test_request:put(Url ++ "/db/_design/a",
+ ?ADMIN_REQ_HEADERS, DDoc),
+ ?_assertEqual(201, Code),
+ {ok, Code1, _, _} = test_request:get(Url ++ "/db/_design/a/_view/foo",
+ ?USERX_REQ_HEADERS),
+ ?_assertEqual(200, Code1).
+
%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------