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 2020/01/04 17:42:13 UTC

[couchdb] 01/02: Allow to set the user db security object to readonly

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

jan pushed a commit to branch feature/user-db-security-obj-readonly
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 4e83bc5a04780e6686004959ca88450eb7d59da8
Author: Alexis Côté <al...@hotmail.com>
AuthorDate: Fri Dec 21 23:36:57 2018 -0500

    Allow to set the user db security object to readonly
    
    - Add the default config
    - Deny update on _security if the database is the user db and if the config is to false
    - Add unit test
---
 rel/overlay/etc/default.ini                     |  3 +++
 src/chttpd/src/chttpd_db.erl                    | 11 +++++++++++
 src/chttpd/test/eunit/chttpd_security_tests.erl | 24 +++++++++++++++++++++++-
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index a0c2617..7bfbbe9 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -80,6 +80,9 @@ default_engine = couch
 ; document. Default is 24 hours.
 ;index_lag_warn_seconds = 86400
 
+; Allow edits on the _security object in the user db. By default, it's disabled.
+users_db_security_editable = false
+
 [couchdb_engines]
 ; The keys in this section are the filename extension that
 ; the specified engine module will use. This is important so
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index 1787e39..6a3df6d 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -781,6 +781,8 @@ db_req(#httpd{path_parts=[_,<<"_revs_diff">>]}=Req, _Db) ->
 
 db_req(#httpd{method='PUT',path_parts=[_,<<"_security">>],user_ctx=Ctx}=Req,
         Db) ->
+    DbName = ?b2l(couch_db:name(Db)),
+    validate_security_can_be_edited(DbName),
     SecObj = chttpd:json_body(Req),
     case fabric:set_security(Db, SecObj, [{user_ctx, Ctx}]) of
         ok ->
@@ -1886,6 +1888,15 @@ extract_header_rev(Req, ExplicitRev) ->
         throw({bad_request, "Document rev and etag have different values"})
     end.
 
+validate_security_can_be_edited(DbName) ->
+    UserDbName = config:get("chttpd_auth", "authentication_db", "_users"),
+    CanEditUserSecurityObject = config:get("couchdb","users_db_security_editable","false"),
+    case {DbName,CanEditUserSecurityObject} of
+        {UserDbName,"false"} ->
+            Msg = "You can't edit the security object of the user database.",
+            throw({forbidden, Msg});
+        {_,_} -> ok
+    end.
 
 validate_attachment_names(Doc) ->
     lists:foreach(fun(Att) ->
diff --git a/src/chttpd/test/eunit/chttpd_security_tests.erl b/src/chttpd/test/eunit/chttpd_security_tests.erl
index 955b4ff..0bea9db 100644
--- a/src/chttpd/test/eunit/chttpd_security_tests.erl
+++ b/src/chttpd/test/eunit/chttpd_security_tests.erl
@@ -137,7 +137,8 @@ security_object_validate_test_() ->
                     fun should_return_ok_for_sec_obj_with_roles_and_names/1,
                     fun should_return_error_for_sec_obj_with_incorrect_roles_and_names/1,
                     fun should_return_error_for_sec_obj_with_incorrect_roles/1,
-                    fun should_return_error_for_sec_obj_with_incorrect_names/1
+                    fun should_return_error_for_sec_obj_with_incorrect_names/1,
+                    fun should_return_error_for_sec_obj_in_user_db/1
                 ]
             }
         }
@@ -382,3 +383,24 @@ should_return_error_for_sec_obj_with_incorrect_names([Url,_UsersUrl]) ->
             {<<"reason">>,<<"no_majority">>}
         ]}, ResultJson)
     ].
+
+should_return_error_for_sec_obj_in_user_db([_,_UsersUrl]) ->
+    SecurityUrl = lists:concat([_UsersUrl, "/_security"]),
+    SecurityProperties = [
+        {<<"admins">>, {[{<<"names">>,[<<?TEST_ADMIN>>]},
+            {<<"roles">>,[<<?TEST_ADMIN>>]}]}},
+        {<<"members">>,{[{<<"names">>,[<<?TEST_MEMBER>>]},
+            {<<"roles">>,[<<?TEST_MEMBER>>]}]}}
+    ],
+
+    Body = jiffy:encode({SecurityProperties}),
+    {ok, Status, _, RespBody} = test_request:put(SecurityUrl,
+        [?CONTENT_JSON, ?AUTH], Body),
+    ResultJson = ?JSON_DECODE(RespBody),
+    [
+        ?_assertEqual(403, Status),
+        ?_assertEqual({[
+            {<<"error">>,<<"forbidden">>},
+            {<<"reason">>,<<"You can't edit the security object of the user database.">>}
+        ]}, ResultJson)
+    ].