From 60ba567fac9f15966034a6dc4b1ecdf250e1ebb5 Mon Sep 17 00:00:00 2001 From: Robert Newson Date: Fri, 21 Jun 2013 11:01:13 +0100 Subject: [PATCH] Add a configurable whitelist of public user properties By default no user properties are public and attempts to view a users document other than your own will return a 404. If the public_fields setting of the users_db config section is set to a list of field names, however, you will see that subset of fields for any user. --- etc/couchdb/default.ini.tpl.in | 2 ++ share/www/script/test/users_db_security.js | 29 ++++++++++++++++++++++ src/couchdb/couch_users_db.erl | 13 +++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/etc/couchdb/default.ini.tpl.in b/etc/couchdb/default.ini.tpl.in index 736d9cd07cb..5eb7ebca77a 100644 --- a/etc/couchdb/default.ini.tpl.in +++ b/etc/couchdb/default.ini.tpl.in @@ -67,6 +67,8 @@ timeout = 600 ; number of seconds before automatic logout auth_cache_size = 50 ; size is number of cache entries allow_persistent_cookies = false ; set to true to allow persistent cookies iterations = 10 ; iterations for password hashing +; comma-separated list of public fields, 404 if empty +; public_fields = [cors] credentials = false diff --git a/share/www/script/test/users_db_security.js b/share/www/script/test/users_db_security.js index d439fcbfae0..e85364a64c0 100644 --- a/share/www/script/test/users_db_security.js +++ b/share/www/script/test/users_db_security.js @@ -256,6 +256,35 @@ couchTests.users_db_security = function(debug) { // log in one last time so run_on_modified_server can clean up the admin account TEquals(true, CouchDB.login("jan", "apple").ok); }); + + run_on_modified_server([ + { + section: "couch_httpd_auth", + key: "iterations", + value: "1" + }, + { + section: "couch_httpd_auth", + key: "public_fields", + value: "name,type" + }, + { + section: "admins", + key: "jan", + value: "apple" + } + ], function() { + var res = usersDb.open("org.couchdb.user:jchris"); + TEquals("jchris", res.name); + TEquals("user", res.type); + TEquals(undefined, res.roles); + TEquals(undefined, res.salt); + TEquals(undefined, res.password_scheme); + TEquals(undefined, res.derived_key); + + // log in one last time so run_on_modified_server can clean up the admin account + TEquals(true, CouchDB.login("jan", "apple").ok); + }); }; usersDb.deleteDb(); diff --git a/src/couchdb/couch_users_db.erl b/src/couchdb/couch_users_db.erl index de76142b172..2352466c16f 100644 --- a/src/couchdb/couch_users_db.erl +++ b/src/couchdb/couch_users_db.erl @@ -101,10 +101,21 @@ after_doc_read(Doc, #db{user_ctx = UserCtx} = Db) -> _ when Name =:= DocName -> Doc; _ -> - throw(not_found) + Doc1 = strip_non_public_fields(Doc), + case Doc1 of + #doc{body={[]}} -> + throw(not_found); + _ -> + Doc1 + end end. get_doc_name(#doc{id= <<"org.couchdb.user:", Name/binary>>}) -> Name; get_doc_name(_) -> undefined. + +strip_non_public_fields(#doc{body={Props}}=Doc) -> + Public = re:split(couch_config:get("couch_httpd_auth", "public_fields", ""), + "\\s*,\\s*", [{return, binary}]), + Doc#doc{body={[{K, V} || {K, V} <- Props, lists:member(K, Public)]}}.