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 2022/08/06 14:10:47 UTC

[couchdb] 01/21: feat(access): add access handling to chttpd

This is an automated email from the ASF dual-hosted git repository.

jan pushed a commit to branch feat/access-2022
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit b8dd8f4a5cded407b49d8202867421fc011f0c57
Author: Jan Lehnardt <ja...@apache.org>
AuthorDate: Fri Jun 24 15:24:22 2022 +0200

    feat(access): add access handling to chttpd
---
 src/chttpd/src/chttpd.erl      |  2 ++
 src/chttpd/src/chttpd_db.erl   | 21 ++++++++++++++++-----
 src/chttpd/src/chttpd_view.erl | 15 +++++++++++++++
 3 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl
index 93b610719..51922c8d9 100644
--- a/src/chttpd/src/chttpd.erl
+++ b/src/chttpd/src/chttpd.erl
@@ -1031,6 +1031,8 @@ error_info({bad_request, Error, Reason}) ->
     {400, couch_util:to_binary(Error), couch_util:to_binary(Reason)};
 error_info({query_parse_error, Reason}) ->
     {400, <<"query_parse_error">>, Reason};
+error_info(access) ->
+    {403, <<"forbidden">>, <<"access">>};
 error_info(database_does_not_exist) ->
     {404, <<"not_found">>, <<"Database does not exist.">>};
 error_info(not_found) ->
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index c41c82347..2cce54b55 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -1037,16 +1037,18 @@ view_cb(Msg, Acc) ->
     couch_mrview_http:view_cb(Msg, Acc).
 
 db_doc_req(#httpd{method = 'DELETE'} = Req, Db, DocId) ->
-    % check for the existence of the doc to handle the 404 case.
-    couch_doc_open(Db, DocId, nil, []),
-    case chttpd:qs_value(Req, "rev") of
+    % fetch the old doc revision, so we can compare access control
+    % in send_update_doc() later.
+    Doc0 = couch_doc_open(Db, DocId, nil, [{user_ctx, Req#httpd.user_ctx}]),
+    Revs = chttpd:qs_value(Req, "rev"),
+    case Revs of
         undefined ->
             Body = {[{<<"_deleted">>, true}]};
         Rev ->
             Body = {[{<<"_rev">>, ?l2b(Rev)}, {<<"_deleted">>, true}]}
     end,
-    Doc = couch_doc_from_req(Req, Db, DocId, Body),
-    send_updated_doc(Req, Db, DocId, Doc);
+    Doc = Doc0#doc{revs=Revs,body=Body,deleted=true},
+    send_updated_doc(Req, Db, DocId, couch_doc_from_req(Req, Db, DocId, Doc));
 db_doc_req(#httpd{method = 'GET', mochi_req = MochiReq} = Req, Db, DocId) ->
     #doc_query_args{
         rev = Rev0,
@@ -1496,6 +1498,8 @@ receive_request_data(Req, LenLeft) when LenLeft > 0 ->
 receive_request_data(_Req, _) ->
     throw(<<"expected more data">>).
 
+update_doc_result_to_json({#doc{id=Id,revs=Rev}, access}) ->
+    update_doc_result_to_json({{Id, Rev}, access});
 update_doc_result_to_json({error, _} = Error) ->
     {_Code, Err, Msg} = chttpd:error_info(Error),
     {[
@@ -2050,6 +2054,7 @@ parse_shards_opt(Req) ->
     [
         {n, parse_shards_opt("n", Req, config:get_integer("cluster", "n", 3))},
         {q, parse_shards_opt("q", Req, config:get_integer("cluster", "q", 2))},
+        {access, parse_shards_opt_access(chttpd:qs_value(Req, "access", false))},
         {placement,
             parse_shards_opt(
                 "placement", Req, config:get("cluster", "placement")
@@ -2086,6 +2091,12 @@ parse_shards_opt(Param, Req, Default) ->
         false -> throw({bad_request, Err})
     end.
 
+parse_shards_opt_access(Value) when is_boolean(Value) ->
+    Value;
+parse_shards_opt_access(_Value) ->
+    Err = ?l2b(["The `access` value should be a boolean."]),
+    throw({bad_request, Err}).
+
 parse_engine_opt(Req) ->
     case chttpd:qs_value(Req, "engine") of
         undefined ->
diff --git a/src/chttpd/src/chttpd_view.erl b/src/chttpd/src/chttpd_view.erl
index 1d721d189..f74088dbc 100644
--- a/src/chttpd/src/chttpd_view.erl
+++ b/src/chttpd/src/chttpd_view.erl
@@ -69,6 +69,21 @@ fabric_query_view(Db, Req, DDoc, ViewName, Args) ->
     Max = chttpd:chunked_response_buffer_size(),
     VAcc = #vacc{db = Db, req = Req, threshold = Max},
     Options = [{user_ctx, Req#httpd.user_ctx}],
+%    {ok, Resp} = fabric:query_view(Db, Options, DDoc, ViewName,
+%            fun view_cb/2, VAcc, Args),
+%    {ok, Resp#vacc.resp}.
+%    % TODO: This might just be a debugging leftover, we might be able
+%    %       to undo this by just returning {ok, Resp#vacc.resp}
+%    %       However, this *might* be here because we need to handle
+%    %       errors here now, because access might tell us to.
+%    case fabric:query_view(Db, Options, DDoc, ViewName,
+%            fun view_cb/2, VAcc, Args) of
+%        {ok, Resp} ->
+%            {ok, Resp#vacc.resp};
+%        {error, Error} ->
+%            throw(Error)
+%    end.
+
     {ok, Resp} = fabric:query_view(
         Db,
         Options,