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

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

commit cfee5236bcdbf0591ceed7116d5ee9bf383c8257
Author: Robert Newson <rnew...@apache.org>
AuthorDate: Fri Jul 21 12:50:37 2023 +0100

    send cookie on successful basic auth
---
 src/couch/src/couch_httpd_auth.erl    | 15 +++++++++++++--
 src/docs/src/api/server/authn.rst     |  7 +++++++
 test/elixir/test/cookie_auth_test.exs | 17 +++++++++++++++++
 3 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/src/couch/src/couch_httpd_auth.erl 
b/src/couch/src/couch_httpd_auth.erl
index 652fb3996..2b00cd96b 100644
--- a/src/couch/src/couch_httpd_auth.erl
+++ b/src/couch/src/couch_httpd_auth.erl
@@ -114,12 +114,23 @@ default_authentication_handler(Req, AuthModule) ->
                     Password = ?l2b(Pass),
                     case authenticate(Password, UserProps) of
                         true ->
-                            Req#httpd{
+                            Req0 = Req#httpd{
                                 user_ctx = #user_ctx{
                                     name = UserName,
                                     roles = couch_util:get_value(<<"roles">>, 
UserProps, [])
                                 }
-                            };
+                            },
+                            case chttpd_util:get_chttpd_auth_config("secret") 
of
+                                undefined ->
+                                    Req0;
+                                SecretStr ->
+                                    Secret = ?l2b(SecretStr),
+                                    UserSalt = 
couch_util:get_value(<<"salt">>, UserProps, <<"">>),
+                                    FullSecret = <<Secret/binary, 
UserSalt/binary>>,
+                                    Req0#httpd{
+                                        auth = {FullSecret, true}
+                                    }
+                            end;
                         false ->
                             authentication_warning(Req, UserName),
                             throw({unauthorized, <<"Name or password is 
incorrect.">>})
diff --git a/src/docs/src/api/server/authn.rst 
b/src/docs/src/api/server/authn.rst
index 7744d12fd..789eec277 100644
--- a/src/docs/src/api/server/authn.rst
+++ b/src/docs/src/api/server/authn.rst
@@ -27,6 +27,13 @@ Interfaces for obtaining session and authorization data.
 Basic Authentication
 ====================
 
+.. versionchanged:: 3.4 In order to aid transition to stronger password hashing
+    without causing a performance penalty, CouchDB will send a Set-Cookie 
header
+    when a request authenticates successfully with Basic authentication. All 
browsers
+    and many http libraries will automatically send this cookie on subsequent 
requests.
+    The cost of verifying the cookie is significantly less than PBKDF2 with a 
high
+    iteration count, for example.
+
 `Basic authentication`_ (:rfc:`2617`) is a quick and simple way to authenticate
 with CouchDB. The main drawback is the need to send user credentials with each
 request which may be insecure and could hurt operation performance (since
diff --git a/test/elixir/test/cookie_auth_test.exs 
b/test/elixir/test/cookie_auth_test.exs
index 6e42963f0..cb28c1ea8 100644
--- a/test/elixir/test/cookie_auth_test.exs
+++ b/test/elixir/test/cookie_auth_test.exs
@@ -389,6 +389,23 @@ defmodule CookieAuthTest do
       &test_change_admin_fun/0
     )
 
+    # performing a successful basic authentication will
+    # create a session cookie
+    resp = Couch.get(
+      "/_all_dbs",
+      headers: [authorization: "Basic #{:base64.encode("jan:apple")}"])
+    assert resp.status_code == 200
+
+    # extract cookie value
+    cookie = resp.headers[:"set-cookie"]
+    [token | _] = String.split(cookie, ";")
+
+    resp = Couch.get(
+      "/_session",
+      headers: [cookie: token])
+    assert resp.status_code == 200
+    assert resp.body["info"]["authenticated"] == "cookie"
+
     # log in one last time so run_on_modified_server can clean up the admin 
account
     login("jan", "apple")
   end

Reply via email to