summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lehnardt <jan@apache.org>2017-10-25 21:36:37 +0200
committerJan Lehnardt <jan@apache.org>2017-10-27 09:04:04 +0200
commit42adcc1a0849f65f9ef4d55aafe11b3aa59512a9 (patch)
tree821d14ee0d0709dff84cbd17ca5d136efaa38bfc
parent9695b73f398ffa1eb69b0d57ccf7c57a3b676e56 (diff)
downloadcouchdb-42adcc1a0849f65f9ef4d55aafe11b3aa59512a9.tar.gz
faet: reject user docs with duplicate keys
-rw-r--r--src/chttpd/src/chttpd_auth_cache.erl52
-rw-r--r--src/couch/src/couch_users_db.erl22
2 files changed, 64 insertions, 10 deletions
diff --git a/src/chttpd/src/chttpd_auth_cache.erl b/src/chttpd/src/chttpd_auth_cache.erl
index 4d85b165b..48a6ed4aa 100644
--- a/src/chttpd/src/chttpd_auth_cache.erl
+++ b/src/chttpd/src/chttpd_auth_cache.erl
@@ -218,15 +218,47 @@ maybe_validate_user_creds(nil) ->
% throws if UserCreds includes a _conflicts member
% returns UserCreds otherwise
maybe_validate_user_creds(UserCreds) ->
- AllowConflictedUserDocs = config:get_boolean("chttpd_auth", "allow_conflicted_user_docs", false),
- case {couch_util:get_value(<<"_conflicts">>, UserCreds), AllowConflictedUserDocs} of
- {undefined, _} ->
- {ok, UserCreds, nil};
+ ok = validate_conflicts(UserCreds),
+ ok = validate_dupes(UserCreds),
+ {ok, UserCreds, nil}.
+
+
+validate_conflicts(UserCreds) ->
+ AllowConflictedUserDocs = config:get_boolean("chttpd_auth",
+ "allow_conflicted_user_docs", false),
+ Conflicts = couch_util:get_value(<<"_conflicts">>, UserCreds, false),
+ Throw = {unauthorized,
+ <<"User document conflicts must be resolved before the document",
+ " is used for authentication purposes.">>},
+ case {Conflicts, AllowConflictedUserDocs} of
+ {false, _} ->
+ ok;
{_, true} ->
- {ok, UserCreds, nil};
- {_ConflictList, false} ->
- throw({unauthorized,
- <<"User document conflicts must be resolved before the document",
- " is used for authentication purposes.">>
- })
+ ok;
+ {_, false} ->
+ throw(Throw)
+ end.
+
+
+validate_dupes(UserCreds) ->
+ AllowDupedUserDocs = config:get_boolean("chttpd_auth",
+ "allow_user_docs_with_duplicate_keys", false),
+ Dupes = has_dupes(UserCreds),
+ Throw = {unauthorized,
+ <<"User document duplicate keys must be removed before the document",
+ " is used for authentication purposes.">>},
+ case {Dupes, AllowDupedUserDocs} of
+ {false, _} ->
+ ok;
+ {_, true} ->
+ ok;
+ {_, false} ->
+ throw(Throw)
+ end.
+
+
+has_dupes(UserCreds) ->
+ case couch_users_db:is_valid_doc_body(UserCreds) of
+ true -> false;
+ _ -> true
end.
diff --git a/src/couch/src/couch_users_db.erl b/src/couch/src/couch_users_db.erl
index c7b41f1fc..75d6b6924 100644
--- a/src/couch/src/couch_users_db.erl
+++ b/src/couch/src/couch_users_db.erl
@@ -13,6 +13,7 @@
-module(couch_users_db).
-export([before_doc_update/2, after_doc_read/2, strip_non_public_fields/1]).
+-export([is_valid_doc_body/1]).
-include_lib("couch/include/couch_db.hrl").
@@ -40,6 +41,12 @@
% Else
% -> save_doc
before_doc_update(Doc, Db) ->
+ case is_valid_doc_body(Doc#doc.body) of
+ true ->
+ ok;
+ false ->
+ throw({bad_request, "User docs must not contain duplicate fields."})
+ end,
#user_ctx{name=Name} = couch_db:get_user_ctx(Db),
DocName = get_doc_name(Doc),
case (catch couch_db:check_is_admin(Db)) of
@@ -51,6 +58,21 @@ before_doc_update(Doc, Db) ->
throw(not_found)
end.
+% Make sure that _users db docs do not contain repeated
+% field names.
+is_valid_doc_body({Props}) ->
+ {Keys, Values} = lists:unzip(Props),
+ case length(Keys) == length(lists:usort(Keys)) of
+ true ->
+ lists:all(fun is_valid_doc_body/1, Values);
+ false ->
+ false
+ end;
+is_valid_doc_body(Values) when is_list(Values)->
+ lists:all(fun is_valid_doc_body/1, Values);
+is_valid_doc_body(_) ->
+ true.
+
% If newDoc.password == null || newDoc.password == undefined:
% ->
% noop