You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2026/10/03 19:56:57 UTC
(couchdb) branch short-handler-names created (now bbc1c4023)
This is an automated email from the ASF dual-hosted git repository.
nickva pushed a change to branch short-handler-names
in repository https://gitbox.apache.org/repos/asf/couchdb.git
at bbc1c4023 Use short names for authentication_handlers
This branch includes the following new commits:
new bbc1c4023 Use short names for authentication_handlers
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(couchdb) 01/01: Use short names for authentication_handlers
Posted by va...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
nickva pushed a commit to branch short-handler-names
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit bbc1c40237fe5e7edd00e14d8a8276987eabce18
Author: Nick Vatamaniuc <va...@gmail.com>
AuthorDate: Sat Oct 3 15:52:40 2026 -0400
Use short names for authentication_handlers
Move away from erlang terms and use simpler names them. For compatibility we
still accept existing tuple forms. Entries that are not one of these are
ignored.
Co-Authored-By: Jan Lehnardt <ja...@apache.org>
Co-Authored-By: Robert Newson <rn...@apache.org>
---
rel/overlay/etc/default.ini | 8 ++--
src/chttpd/src/chttpd.erl | 46 ++++++++++---------
src/chttpd/test/eunit/chttpd_auth_tests.erl | 2 +-
src/chttpd/test/eunit/chttpd_util_test.erl | 3 +-
src/couch/src/couch_httpd.erl | 64 ++++++++++++++++++---------
src/couch/src/couch_httpd_auth.erl | 4 --
src/couch/src/couch_util.erl | 5 ++-
src/docs/src/api/server/authn.rst | 8 ++--
src/docs/src/api/server/configuration.rst | 4 +-
src/docs/src/config/http.rst | 14 +++---
test/elixir/test/auth_cache_test.exs | 2 +-
test/elixir/test/config/test-config.ini | 2 +-
test/elixir/test/jwt_roles_claim_test.exs | 6 +--
test/elixir/test/security_validation_test.exs | 2 +-
14 files changed, 95 insertions(+), 75 deletions(-)
diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index a6f882fb8..4d3602582 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -263,11 +263,11 @@ bind_address = 127.0.0.1
;buffer_response = false
; authentication handlers
-;authentication_handlers = {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, default_authentication_handler}
+;authentication_handlers = cookie, default
; uncomment the next line to enable proxy authentication
-;authentication_handlers = {chttpd_auth, proxy_authentication_handler}, {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, default_authentication_handler}
+;authentication_handlers = proxy, cookie, default
; uncomment the next line to enable JWT authentication
-;authentication_handlers = {chttpd_auth, jwt_authentication_handler}, {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, default_authentication_handler}
+;authentication_handlers = jwt, cookie, default
; prevent non-admins from accessing /_all_dbs and /_dbs_info
;admin_only_all_dbs = true
@@ -400,7 +400,7 @@ bind_address = 127.0.0.1
[httpd]
port = {{backend_port}}
bind_address = 127.0.0.1
-;authentication_handlers = {couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, default_authentication_handler}
+;authentication_handlers = cookie, default
; Options for the MochiWeb HTTP server.
;server_options = [{backlog, 128}, {acceptor_pool_size, 16}]
diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl
index a078df2af..7f2b345fc 100644
--- a/src/chttpd/src/chttpd.erl
+++ b/src/chttpd/src/chttpd.erl
@@ -648,31 +648,35 @@ extract_cookie(#httpd{mochi_req = MochiReq}) ->
%% erlfmt-ignore
set_auth_handlers() ->
- AuthenticationDefault = "{chttpd_auth, cookie_authentication_handler},
- {chttpd_auth, default_authentication_handler}",
- AuthenticationSrcs = couch_httpd:make_fun_spec_strs(
- config:get("chttpd", "authentication_handlers", AuthenticationDefault)),
- AuthHandlers = lists:map(
- fun(A) -> {auth_handler_name(A), couch_httpd:make_arity_1_fun(A)} end, AuthenticationSrcs),
- AuthenticationFuns = AuthHandlers ++ [
+ AuthenticationHandlers0 = config:get("chttpd", "authentication_handlers", "cookie, default"),
+ AuthenticationHandlers1 = couch_httpd:authentication_handler_match(AuthenticationHandlers0),
+ AuthenticationHandlers2 = lists:filtermap(fun authentication_handler_map/1, AuthenticationHandlers1),
+ AuthenticationFuns = AuthenticationHandlers2 ++ [
fun chttpd_auth:party_mode_handler/1 %% must be last
],
ok = application:set_env(chttpd, auth_handlers, AuthenticationFuns).
-% SpecStr is a string like "{my_module, my_fun}"
-% Takes the first token of the function name in front '_' as auth handler name
-% e.g.
-% chttpd_auth:default_authentication_handler: default
-% chttpd_auth_cookie_authentication_handler: cookie
-% couch_http_auth:proxy_authentication_handler: proxy
-%
-% couch_http:auth_handler_name can't be used here, since it assumes the name
-% of the auth handler to be the 6th token split by [\\W_]
-% - this only works for modules with exactly two underscores in their name
-% - is not very robust (a space after the ',' is assumed)
-auth_handler_name(SpecStr) ->
- {ok, {_, Fun}} = couch_util:parse_term(SpecStr),
- hd(binary:split(atom_to_binary(Fun, latin1), <<"_">>)).
+% aliases
+authentication_handler_map("cookie") ->
+ {true, {~"cookie", fun chttpd_auth:cookie_authentication_handler/1}};
+authentication_handler_map("default") ->
+ {true, {~"default", fun chttpd_auth:default_authentication_handler/1}};
+authentication_handler_map("jwt") ->
+ {true, {~"jwt", fun chttpd_auth:jwt_authentication_handler/1}};
+authentication_handler_map("proxy") ->
+ {true, {~"proxy", fun chttpd_auth:proxy_authentication_handler/1}};
+% deprecated
+authentication_handler_map("{chttpd_auth,jwt_authentication_handler}") ->
+ {true, {~"jwt", fun chttpd_auth:jwt_authentication_handler/1}};
+authentication_handler_map("{chttpd_auth,cookie_authentication_handler}") ->
+ {true, {~"cookie", fun chttpd_auth:cookie_authentication_handler/1}};
+authentication_handler_map("{chttpd_auth,default_authentication_handler}") ->
+ {true, {~"default", fun chttpd_auth:default_authentication_handler/1}};
+authentication_handler_map("{chttpd_auth,proxy_authentication_handler}") ->
+ {true, {~"proxy", fun chttpd_auth:proxy_authentication_handler/1}};
+% reject everything else
+authentication_handler_map(_) ->
+ false.
authenticate_request(Req) ->
{ok, AuthenticationFuns} = application:get_env(chttpd, auth_handlers),
diff --git a/src/chttpd/test/eunit/chttpd_auth_tests.erl b/src/chttpd/test/eunit/chttpd_auth_tests.erl
index 6745bb31c..81291564b 100644
--- a/src/chttpd/test/eunit/chttpd_auth_tests.erl
+++ b/src/chttpd/test/eunit/chttpd_auth_tests.erl
@@ -28,7 +28,7 @@ teardown(_Url) ->
ok.
setup_proxy_auth() ->
- {StartCtx, ProxyCfgFile} = start_couch_with_cfg("{chttpd_auth, proxy_authentication_handler}"),
+ {StartCtx, ProxyCfgFile} = start_couch_with_cfg("proxy"),
config:set("chttpd", "require_valid_user", "false", false),
config:set("chttpd_auth", "hash_algorithms", ?WORKING_HASHES, false),
config:set("chttpd_auth", "proxy_use_secret", "true", false),
diff --git a/src/chttpd/test/eunit/chttpd_util_test.erl b/src/chttpd/test/eunit/chttpd_util_test.erl
index c649393a1..dc06e1075 100644
--- a/src/chttpd/test/eunit/chttpd_util_test.erl
+++ b/src/chttpd/test/eunit/chttpd_util_test.erl
@@ -26,8 +26,7 @@ setup() ->
ok = config:set(
"httpd",
"authentication_handlers",
- "{couch_httpd_auth, cookie_authentication_handler}, "
- "{couch_httpd_auth, default_authentication_handler}",
+ "cookie, default",
Persist
),
ok = config:set("chttpd", "require_valid_user", "false", Persist),
diff --git a/src/couch/src/couch_httpd.erl b/src/couch/src/couch_httpd.erl
index 0a9e39e7a..8e9bb1107 100644
--- a/src/couch/src/couch_httpd.erl
+++ b/src/couch/src/couch_httpd.erl
@@ -21,7 +21,6 @@
-export([header_value/2, header_value/3, qs_value/2, qs_value/3, qs/1, qs_json_value/3]).
-export([path/1, absolute_uri/2, body_length/1]).
-export([verify_is_server_admin/1, unquote/1, quote/1, recv/2, recv_chunked/4, error_info/1]).
--export([make_fun_spec_strs/1]).
-export([make_arity_1_fun/1, make_arity_2_fun/1, make_arity_3_fun/1]).
-export([parse_form/1, json_body/1, json_body_obj/1, body/1]).
-export([doc_etag/1, doc_etag/3, make_etag/1, etag_match/2, etag_respond/3, etag_maybe/2]).
@@ -47,15 +46,13 @@
-export([set_auth_handlers/0]).
-export([maybe_decompress/2]).
-export([peer/1]).
+-export([authentication_handler_match/1]).
-define(HANDLER_NAME_IN_MODULE_POS, 6).
-define(MAX_DRAIN_BYTES, 1048576).
-define(MAX_DRAIN_TIME_MSEC, 1000).
-define(DEFAULT_SOCKET_OPTIONS, "[{sndbuf, 262144}]").
--define(DEFAULT_AUTHENTICATION_HANDLERS,
- "{couch_httpd_auth, cookie_authentication_handler}, "
- "{couch_httpd_auth, default_authentication_handler}"
-).
+-define(DEFAULT_AUTHENTICATION_HANDLERS, "cookie, default").
start_link() ->
start_link(http).
@@ -186,26 +183,48 @@ stop() ->
catch mochiweb_http:stop(https).
set_auth_handlers() ->
- AuthenticationSrcs = make_fun_spec_strs(
- config:get(
- "httpd",
- "authentication_handlers",
- ?DEFAULT_AUTHENTICATION_HANDLERS
- )
+ AuthenticationHandlers0 = config:get(
+ "httpd", "authentication_handlers", ?DEFAULT_AUTHENTICATION_HANDLERS
),
- AuthHandlers = lists:map(
- fun(A) -> {auth_handler_name(A), make_arity_1_fun(A)} end, AuthenticationSrcs
+ AuthenticationHandlers1 = authentication_handler_match(AuthenticationHandlers0),
+ AuthenticationHandlers2 = lists:filtermap(
+ fun authentication_handler_map/1, AuthenticationHandlers1
),
AuthenticationFuns =
- AuthHandlers ++
+ AuthenticationHandlers2 ++
[
%% must be last
fun couch_httpd_auth:party_mode_handler/1
],
ok = application:set_env(couch, auth_handlers, AuthenticationFuns).
-auth_handler_name(SpecStr) ->
- lists:nth(?HANDLER_NAME_IN_MODULE_POS, re:split(SpecStr, "[\\W_]", [])).
+authentication_handler_match(Str) ->
+ case
+ re:run(couch_util:remove_whitespace(Str), "({[a-z0-9_]+,[a-z0-9_]+}|[a-z0-9_]+)", [
+ global, {capture, first, list}
+ ])
+ of
+ {match, Matches} ->
+ [M || [M] <- Matches];
+ nomatch ->
+ []
+ end.
+
+% aliases
+authentication_handler_map("cookie") ->
+ {true, {~"cookie", fun couch_httpd_auth:cookie_authentication_handler/1}};
+authentication_handler_map("default") ->
+ {true, {~"default", fun couch_httpd_auth:default_authentication_handler/1}};
+% deprecated or tests
+authentication_handler_map("{couch_httpd_auth,cookie_authentication_handler}") ->
+ {true, {~"cookie", fun couch_httpd_auth:cookie_authentication_handler/1}};
+authentication_handler_map("{couch_httpd_auth,default_authentication_handler}") ->
+ {true, {~"default", fun couch_httpd_auth:default_authentication_handler/1}};
+authentication_handler_map("{couch_httpd_auth,special_test_authentication_handler}") ->
+ {true, {~"special_test", fun couch_httpd_auth:special_test_authentication_handler/1}};
+% reject everything else
+authentication_handler_map(_) ->
+ false.
get_httpd_handlers() ->
{ok, HttpdGlobalHandlers} = application:get_env(couch, httpd_global_handlers),
@@ -267,10 +286,6 @@ make_arity_3_fun(SpecStr) ->
fun(Arg1, Arg2, Arg3) -> Mod:Fun(Arg1, Arg2, Arg3) end
end.
-% SpecStr is "{my_module, my_fun}, {my_module2, my_fun2}"
-make_fun_spec_strs(SpecStr) ->
- re:split(SpecStr, "(?<=})\\s*,\\s*(?={)", [{return, list}]).
-
handle_request(MochiReq) ->
Body = proplists:get_value(body, MochiReq:get(opts)),
erlang:put(mochiweb_request_body, Body),
@@ -1538,4 +1553,13 @@ should_accept_code_and_message(DontLogFlag) ->
?_assertEqual(ok, log_response(500, {json, {[{error, undef}]}}))}
]}.
+authentication_handler_match_test() ->
+ ?assertEqual("", authentication_handler_match("")),
+ ?assertEqual(["foo", "bar"], authentication_handler_match(" foo , bar ")),
+ ?assertEqual(["foo", "bar"], authentication_handler_match("foo,bar")),
+ ?assertEqual(["{foo,bar}"], authentication_handler_match("{foo,bar}")),
+ ?assertEqual(["{foo,bar}"], authentication_handler_match("{foo, bar}")),
+ ?assertEqual(["foo", "{foo,bar}", "bar"], authentication_handler_match("foo, {foo, bar}, bar")),
+ ?assertEqual(["{foo,bar}", "baz"], authentication_handler_match("{foo , bar}, baz")).
+
-endif.
diff --git a/src/couch/src/couch_httpd_auth.erl b/src/couch/src/couch_httpd_auth.erl
index 9c5136402..d2244b9d4 100644
--- a/src/couch/src/couch_httpd_auth.erl
+++ b/src/couch/src/couch_httpd_auth.erl
@@ -23,7 +23,6 @@
special_test_authentication_handler/1
]).
-export([cookie_authentication_handler/1, cookie_authentication_handler/2]).
--export([null_authentication_handler/1]).
-export([proxy_authentication_handler/1, proxy_authentification_handler/1]).
-export([cookie_auth_header/2]).
-export([handle_session_req/1, handle_session_req/2]).
@@ -152,9 +151,6 @@ default_authentication_handler(Req, AuthModule) ->
end
end.
-null_authentication_handler(Req) ->
- Req#httpd{user_ctx = ?ADMIN_USER}.
-
%% @doc proxy auth handler.
%
% This handler allows creation of a userCtx object from a user authenticated remotly.
diff --git a/src/couch/src/couch_util.erl b/src/couch/src/couch_util.erl
index 8ee165666..42bfeca26 100644
--- a/src/couch/src/couch_util.erl
+++ b/src/couch/src/couch_util.erl
@@ -15,7 +15,7 @@
-export([priv_dir/0, normpath/1, fold_files/5]).
-export([should_flush/0, should_flush/1, to_existing_atom/1]).
-export([rand32/0, implode/2]).
--export([abs_pathname/1, abs_pathname/2, trim/1, drop_dot_couch_ext/1]).
+-export([abs_pathname/1, abs_pathname/2, trim/1, remove_whitespace/1, drop_dot_couch_ext/1]).
-export([encodeBase64Url/1, decodeBase64Url/1]).
-export([validate_utf8/1, to_hex/1, to_hex_bin/1, parse_term/1, dict_find/3]).
-export([get_nested_json_value/2, json_user_ctx/1]).
@@ -350,6 +350,9 @@ trim(String) ->
String2 = lists:dropwhile(fun is_whitespace/1, String),
lists:reverse(lists:dropwhile(fun is_whitespace/1, lists:reverse(String2))).
+remove_whitespace(Str) ->
+ re:replace(Str, "\\s+", "", [global, {return, list}]).
+
drop_dot_couch_ext(DbName) when is_binary(DbName) ->
PrefixLen = size(DbName) - 6,
case DbName of
diff --git a/src/docs/src/api/server/authn.rst b/src/docs/src/api/server/authn.rst
index 7b89a87bd..354dbdebc 100644
--- a/src/docs/src/api/server/authn.rst
+++ b/src/docs/src/api/server/authn.rst
@@ -283,13 +283,13 @@ Proxy Authentication
.. note::
To use this authentication method make sure that the
- ``{chttpd_auth, proxy_authentication_handler}`` value is added to the
+ ``proxy`` value is added to the
list of the active :config:option:`chttpd/authentication_handlers`:
.. code-block:: ini
[chttpd]
- authentication_handlers = {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, proxy_authentication_handler}, {chttpd_auth, default_authentication_handler}
+ authentication_handlers = cookie, proxy, default
`Proxy authentication` is very useful in case your application already uses
some external authentication service and you don't want to duplicate users and
@@ -372,13 +372,13 @@ JWT Authentication
.. note::
To use this authentication method, make sure that the
- ``{chttpd_auth, jwt_authentication_handler}`` value is added to the
+ ``jwt`` value is added to the
list of the active :config:option:`chttpd/authentication_handlers`:
.. code-block:: ini
[chttpd]
- authentication_handlers = {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, jwt_authentication_handler}, {chttpd_auth, default_authentication_handler}
+ authentication_handlers = cookie, jwt, default
``JWT authentication`` enables CouchDB to use externally-generated JWT tokens
instead of defining users or roles in the ``_users`` database.
diff --git a/src/docs/src/api/server/configuration.rst b/src/docs/src/api/server/configuration.rst
index d05bdd8af..b938c422d 100644
--- a/src/docs/src/api/server/configuration.rst
+++ b/src/docs/src/api/server/configuration.rst
@@ -88,7 +88,7 @@ interact with the local node's configuration.
"secure_rewrites": "true"
},
"httpd": {
- "authentication_handlers": "{couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, default_authentication_handler}",
+ "authentication_handlers": "cookie, default",
"bind_address": "192.168.0.2",
"max_connections": "2048",
"port": "5984",
@@ -156,7 +156,7 @@ interact with the local node's configuration.
Server: CouchDB (Erlang/OTP)
{
- "authentication_handlers": "{couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, default_authentication_handler}",
+ "authentication_handlers": "cookie, default",
"bind_address": "127.0.0.1",
"default_handler": "{couch_httpd_db, handle_request}",
"port": "5984"
diff --git a/src/docs/src/config/http.rst b/src/docs/src/config/http.rst
index 8f2114982..e1db07851 100644
--- a/src/docs/src/config/http.rst
+++ b/src/docs/src/config/http.rst
@@ -81,17 +81,15 @@ HTTP Server Options
.. config:option:: authentication_handlers :: Authentication handlers
List of authentication handlers used by CouchDB. You may
- extend them via third-party plugins or remove some of them if you won't
- let users to use one of provided methods::
+ remove some of them if you won't let users to use one of provided methods::
[chttpd]
- authentication_handlers = {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, default_authentication_handler}
+ authentication_handlers = cookie, default
- - ``{chttpd_auth, cookie_authentication_handler}``: used for Cookie auth;
- - ``{chttpd_auth, proxy_authentication_handler}``: used for Proxy auth;
- - ``{chttpd_auth, jwt_authentication_handler}``: used for JWT auth;
- - ``{chttpd_auth, default_authentication_handler}``: used for Basic auth;
- - ``{couch_httpd_auth, null_authentication_handler}``: disables auth, breaks CouchDB.
+ - ``cookie``: used for Cookie auth;
+ - ``proxy``: used for Proxy auth;
+ - ``jwt``: used for JWT auth;
+ - ``default``: used for Basic auth.
.. config:option:: buffer_response :: Buffered response
diff --git a/test/elixir/test/auth_cache_test.exs b/test/elixir/test/auth_cache_test.exs
index 8b7c29c71..62d08ad9b 100644
--- a/test/elixir/test/auth_cache_test.exs
+++ b/test/elixir/test/auth_cache_test.exs
@@ -22,7 +22,7 @@ defmodule AuthCacheTest do
%{
:section => "httpd",
:key => "authentication_handlers",
- :value => "{couch_httpd_auth, default_authentication_handler}"
+ :value => "default"
},
%{
:section => "chttpd_auth",
diff --git a/test/elixir/test/config/test-config.ini b/test/elixir/test/config/test-config.ini
index 423cc492c..9baf53a70 100644
--- a/test/elixir/test/config/test-config.ini
+++ b/test/elixir/test/config/test-config.ini
@@ -2,7 +2,7 @@
level = warn
[chttpd]
-authentication_handlers = {chttpd_auth, jwt_authentication_handler}, {chttpd_auth, proxy_authentication_handler}, {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, default_authentication_handler}
+authentication_handlers = jwt, proxy, cookie, default
[dreyfus]
name = clouseau@127.0.0.1
diff --git a/test/elixir/test/jwt_roles_claim_test.exs b/test/elixir/test/jwt_roles_claim_test.exs
index ec3c7e53e..c3ff93e8a 100644
--- a/test/elixir/test/jwt_roles_claim_test.exs
+++ b/test/elixir/test/jwt_roles_claim_test.exs
@@ -5,11 +5,7 @@ defmodule JwtRolesClaimTest do
%{
:section => "chttpd",
:key => "authentication_handlers",
- :value => [
- "{chttpd_auth, jwt_authentication_handler}, ",
- "{chttpd_auth, cookie_authentication_handler}, ",
- "{chttpd_auth, default_authentication_handler})"
- ] |> Enum.join
+ :value => "jwt, cookie, default"
},
%{
:section => "jwt_keys",
diff --git a/test/elixir/test/security_validation_test.exs b/test/elixir/test/security_validation_test.exs
index 8834e17f5..7120a4a69 100644
--- a/test/elixir/test/security_validation_test.exs
+++ b/test/elixir/test/security_validation_test.exs
@@ -61,7 +61,7 @@ defmodule SecurityValidationTest do
configs = [
{"chttpd", "authentication_handlers",
- "{couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, default_authentication_handler}"},
+ "cookie, default"},
{"chttpd_auth", "authentication_db", auth_db_name}
]