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

rnewson pushed a commit to branch decouple_offline_hash_strength_from_online
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 1f33d6a0bd849d6e0cbfd3955426bcc2bfe8bc37
Author: Robert Newson <[email protected]>
AuthorDate: Mon Oct 23 18:32:22 2023 +0100

    remove all password derivation fields before adding back the new ones
---
 src/couch/src/couch_users_db.erl | 48 +++++++++++++++++++++++++++-------------
 1 file changed, 33 insertions(+), 15 deletions(-)

diff --git a/src/couch/src/couch_users_db.erl b/src/couch/src/couch_users_db.erl
index a32591d99..e3b914969 100644
--- a/src/couch/src/couch_users_db.erl
+++ b/src/couch/src/couch_users_db.erl
@@ -27,7 +27,6 @@
 -define(PRESERVE_SALT, <<"preserve_salt">>).
 -define(ITERATIONS, <<"iterations">>).
 -define(SALT, <<"salt">>).
--define(replace(L, K, V), lists:keystore(K, 1, L, {K, V})).
 -define(REQUIREMENT_ERROR, "Password does not conform to requirements.").
 -define(PASSWORD_SERVER_ERROR, "Server cannot hash passwords at this time.").
 
@@ -90,12 +89,14 @@ save_doc(#doc{body = {Body}} = Doc) ->
         {ClearPassword, "simple"} ->
             ok = validate_password(ClearPassword),
             PasswordSha = couch_passwords:simple(ClearPassword, Salt),
-            Body0 = ?replace(Body, ?PASSWORD_SCHEME, ?SIMPLE),
-            Body1 = ?replace(Body0, ?SALT, Salt),
-            Body2 = ?replace(Body1, ?PASSWORD_SHA, PasswordSha),
-            Body3 = proplists:delete(?PRESERVE_SALT, Body2),
-            Body4 = proplists:delete(?PASSWORD, Body3),
-            Doc#doc{body = {Body4}};
+            Body0 = remove_password_fields(Body),
+            Body1 = [
+                {?PASSWORD_SCHEME, ?SIMPLE},
+                {?SALT, Salt},
+                {?PASSWORD_SHA, PasswordSha}
+                | Body0
+            ],
+            Doc#doc{body = {Body1}};
         {ClearPassword, "pbkdf2"} ->
             ok = validate_password(ClearPassword),
             PRF = chttpd_util:get_chttpd_auth_config("pbkdf2_prf", "sha256"),
@@ -105,19 +106,36 @@ save_doc(#doc{body = {Body}} = Doc) ->
             DerivedKey = couch_passwords:pbkdf2(
                 list_to_existing_atom(PRF), ClearPassword, Salt, Iterations
             ),
-            Body0 = ?replace(Body, ?PASSWORD_SCHEME, ?PBKDF2),
-            Body1 = ?replace(Body0, ?PBKDF2_PRF, ?l2b(PRF)),
-            Body2 = ?replace(Body1, ?ITERATIONS, Iterations),
-            Body3 = ?replace(Body2, ?DERIVED_KEY, DerivedKey),
-            Body4 = ?replace(Body3, ?SALT, Salt),
-            Body5 = proplists:delete(?PRESERVE_SALT, Body4),
-            Body6 = proplists:delete(?PASSWORD, Body5),
-            Doc#doc{body = {Body6}};
+            Body0 = remove_password_fields(Body),
+            Body1 = [
+                {?PASSWORD_SCHEME, ?PBKDF2},
+                {?PBKDF2_PRF, ?l2b(PRF)},
+                {?SALT, Salt},
+                {?ITERATIONS, Iterations},
+                {?DERIVED_KEY, DerivedKey}
+                | Body0
+            ],
+            Doc#doc{body = {Body1}};
         {_ClearPassword, Scheme} ->
             couch_log:error("[couch_httpd_auth] password_scheme value of '~p' 
is invalid.", [Scheme]),
             throw({forbidden, ?PASSWORD_SERVER_ERROR})
     end.
 
+remove_password_fields(Props) ->
+    lists:filter(fun not_password_field/1, Props).
+
+not_password_field({Key, _Value}) ->
+    not lists:member(Key, [
+        ?DERIVED_KEY,
+        ?ITERATIONS,
+        ?PASSWORD,
+        ?PASSWORD_SCHEME,
+        ?PASSWORD_SHA,
+        ?PRESERVE_SALT,
+        ?PBKDF2_PRF,
+        ?SALT
+    ]).
+
 % Validate if a new password matches all RegExp in the password_regexp setting.
 % Throws if not.
 % In this function the [couch_httpd_auth] password_regexp config is parsed.

Reply via email to