Add new configuration for rabbitmq_web_dispatch.auth_backends with a fallback to the core auth_backends
(cherry picked from commit b048ed55bb
)
This commit is contained in:
parent
569edb0841
commit
3908e5c42d
|
@ -9,7 +9,7 @@
|
|||
|
||||
-include_lib("rabbit_common/include/rabbit.hrl").
|
||||
|
||||
-export([check_user_pass_login/2, check_user_login/2, check_user_loopback/2,
|
||||
-export([check_user_pass_login/2, check_user_login/2, check_user_login/3, check_user_loopback/2,
|
||||
check_vhost_access/4, check_resource_access/4, check_topic_access/4,
|
||||
check_user_id/2]).
|
||||
|
||||
|
@ -33,6 +33,14 @@ check_user_pass_login(Username, Password) ->
|
|||
check_user_login(Username, AuthProps) ->
|
||||
%% extra auth properties like MQTT client id are in AuthProps
|
||||
{ok, Modules} = application:get_env(rabbit, auth_backends),
|
||||
check_user_login(Username, AuthProps, Modules).
|
||||
|
||||
-spec check_user_login
|
||||
(rabbit_types:username(), [{atom(), any()}], term()) ->
|
||||
{'ok', rabbit_types:user()} |
|
||||
{'refused', rabbit_types:username(), string(), [any()]}.
|
||||
|
||||
check_user_login(Username, AuthProps, Modules) ->
|
||||
try
|
||||
lists:foldl(
|
||||
fun (rabbit_auth_backend_cache=ModN, {refused, _, _, _}) ->
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
% vim:ft=erlang:
|
||||
%% ----------------------------------------------------------------------------
|
||||
%% RabbitMQ Web Dispatch
|
||||
%%
|
||||
%% ----------------------------------------------------------------------------
|
||||
|
||||
%% ===========================================================================
|
||||
%% Auth Backends
|
||||
|
||||
%% Select an authentication backend to use for the management plugin. RabbitMQ provides an
|
||||
%% internal backend in the core.
|
||||
%%
|
||||
%% {web_dispatch.auth_backends, [rabbit_auth_backend_internal]},
|
||||
|
||||
{translation, "rabbitmq_web_dispatch.auth_backends",
|
||||
fun(Conf) ->
|
||||
Settings = cuttlefish_variable:filter_by_prefix("web_dispatch.auth_backends", Conf),
|
||||
BackendModule = fun
|
||||
(internal) -> rabbit_auth_backend_internal;
|
||||
(ldap) -> rabbit_auth_backend_ldap;
|
||||
(http) -> rabbit_auth_backend_http;
|
||||
(oauth) -> rabbit_auth_backend_oauth2;
|
||||
(oauth2) -> rabbit_auth_backend_oauth2;
|
||||
(cache) -> rabbit_auth_backend_cache;
|
||||
(amqp) -> rabbit_auth_backend_amqp;
|
||||
(dummy) -> rabbit_auth_backend_dummy;
|
||||
(Other) when is_atom(Other) -> Other;
|
||||
(_) -> cuttlefish:invalid("Unknown/unsupported auth backend")
|
||||
end,
|
||||
AuthBackends = [{Num, {default, BackendModule(V)}} || {["web_dispatch", "auth_backends", Num], V} <- Settings],
|
||||
AuthNBackends = [{Num, {authn, BackendModule(V)}} || {["web_dispatch", "auth_backends", Num, "authn"], V} <- Settings],
|
||||
AuthZBackends = [{Num, {authz, BackendModule(V)}} || {["web_dispatch", "auth_backends", Num, "authz"], V} <- Settings],
|
||||
Backends = lists:foldl(
|
||||
fun({NumStr, {Type, V}}, Acc) ->
|
||||
Num = case catch list_to_integer(NumStr) of
|
||||
N when is_integer(N) -> N;
|
||||
Err ->
|
||||
cuttlefish:invalid(
|
||||
iolist_to_binary(io_lib:format(
|
||||
"Auth backend position in the chain should be an integer ~p", [Err])))
|
||||
end,
|
||||
NewVal = case dict:find(Num, Acc) of
|
||||
{ok, {AuthN, AuthZ}} ->
|
||||
case {Type, AuthN, AuthZ} of
|
||||
{authn, undefined, _} ->
|
||||
{V, AuthZ};
|
||||
{authz, _, undefined} ->
|
||||
{AuthN, V};
|
||||
_ ->
|
||||
cuttlefish:invalid(
|
||||
iolist_to_binary(
|
||||
io_lib:format(
|
||||
"Auth backend already defined for the ~pth ~p backend",
|
||||
[Num, Type])))
|
||||
end;
|
||||
error ->
|
||||
case Type of
|
||||
authn -> {V, undefined};
|
||||
authz -> {undefined, V};
|
||||
default -> {V, V}
|
||||
end
|
||||
end,
|
||||
dict:store(Num, NewVal, Acc)
|
||||
end,
|
||||
dict:new(),
|
||||
AuthBackends ++ AuthNBackends ++ AuthZBackends),
|
||||
lists:map(
|
||||
fun
|
||||
({Num, {undefined, AuthZ}}) ->
|
||||
cuttlefish:warn(
|
||||
io_lib:format(
|
||||
"Auth backend undefined for the ~pth authz backend. Using ~p",
|
||||
[Num, AuthZ])),
|
||||
{AuthZ, AuthZ};
|
||||
({Num, {AuthN, undefined}}) ->
|
||||
cuttlefish:warn(
|
||||
io_lib:format(
|
||||
"Authz backend undefined for the ~pth authn backend. Using ~p",
|
||||
[Num, AuthN])),
|
||||
{AuthN, AuthN};
|
||||
({_Num, {Auth, Auth}}) -> Auth;
|
||||
({_Num, {AuthN, AuthZ}}) -> {AuthN, AuthZ}
|
||||
end,
|
||||
lists:keysort(1, dict:to_list(Backends)))
|
||||
end}.
|
||||
|
||||
{mapping, "web_dispatch.auth_backends.$num", "rabbitmq_web_dispatch.auth_backends", [
|
||||
{datatype, atom}
|
||||
]}.
|
||||
|
||||
{mapping, "web_dispatch.auth_backends.$num.authn", "rabbitmq_web_dispatch.auth_backends",[
|
||||
{datatype, atom}
|
||||
]}.
|
||||
|
||||
{mapping, "web_dispatch.auth_backends.$num.authz", "rabbitmq_web_dispatch.auth_backends",[
|
||||
{datatype, atom}
|
||||
]}.
|
||||
|
||||
%{mapping, "management.test_config", "rabbitmq_management.test_config",
|
||||
% [{datatype, {enum, [true, false]}}]}.
|
|
@ -141,7 +141,10 @@ is_authorized(ReqData, Context, Username, Password, ErrorMsg, Fun, AuthConfig, R
|
|||
_ -> []
|
||||
end,
|
||||
{IP, _} = cowboy_req:peer(ReqData),
|
||||
case rabbit_access_control:check_user_login(Username, AuthProps) of
|
||||
|
||||
{ok, AuthBackends} = get_auth_backends(),
|
||||
|
||||
case rabbit_access_control:check_user_login(Username, AuthProps, AuthBackends) of
|
||||
{ok, User = #user{username = ResolvedUsername, tags = Tags}} ->
|
||||
case rabbit_access_control:check_user_loopback(ResolvedUsername, IP) of
|
||||
ok ->
|
||||
|
@ -359,3 +362,11 @@ log_access_control_result(NotOK) ->
|
|||
|
||||
is_basic_auth_disabled(#auth_settings{basic_auth_enabled = Enabled}) ->
|
||||
not Enabled.
|
||||
|
||||
get_auth_backends() ->
|
||||
case application:get_env(rabbitmq_web_dispatch, auth_backends) of
|
||||
{ok, Backends} -> {ok, Backends};
|
||||
_ -> rabbit_log:debug("rabbitmq_web_dispatch.auth_backends not configured,
|
||||
falling back to rabbit.auth_backends"),
|
||||
application:get_env(rabbit, auth_backends)
|
||||
end.
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
%% This Source Code Form is subject to the terms of the Mozilla Public
|
||||
%% License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
%%
|
||||
%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
|
||||
%%
|
||||
|
||||
-module(config_schema_SUITE).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
all() ->
|
||||
[
|
||||
run_snippets
|
||||
].
|
||||
|
||||
%% -------------------------------------------------------------------
|
||||
%% Testsuite setup/teardown.
|
||||
%% -------------------------------------------------------------------
|
||||
|
||||
init_per_suite(Config) ->
|
||||
rabbit_ct_helpers:log_environment(),
|
||||
Config1 = rabbit_ct_helpers:run_setup_steps(Config),
|
||||
rabbit_ct_config_schema:init_schemas(rabbitmq_web_dispatch, Config1).
|
||||
|
||||
|
||||
end_per_suite(Config) ->
|
||||
rabbit_ct_helpers:run_teardown_steps(Config).
|
||||
|
||||
init_per_testcase(Testcase, Config) ->
|
||||
rabbit_ct_helpers:testcase_started(Config, Testcase),
|
||||
Config1 = rabbit_ct_helpers:set_config(Config, [
|
||||
{rmq_nodename_suffix, Testcase}
|
||||
]),
|
||||
rabbit_ct_helpers:run_steps(Config1,
|
||||
rabbit_ct_broker_helpers:setup_steps() ++
|
||||
rabbit_ct_client_helpers:setup_steps()).
|
||||
|
||||
end_per_testcase(Testcase, Config) ->
|
||||
Config1 = rabbit_ct_helpers:run_steps(Config,
|
||||
rabbit_ct_client_helpers:teardown_steps() ++
|
||||
rabbit_ct_broker_helpers:teardown_steps()),
|
||||
rabbit_ct_helpers:testcase_finished(Config1, Testcase).
|
||||
|
||||
%% -------------------------------------------------------------------
|
||||
%% Testcases.
|
||||
%% -------------------------------------------------------------------
|
||||
|
||||
run_snippets(Config) ->
|
||||
ok = rabbit_ct_broker_helpers:rpc(Config, 0,
|
||||
?MODULE, run_snippets1, [Config]).
|
||||
|
||||
run_snippets1(Config) ->
|
||||
rabbit_ct_config_schema:run_snippets(Config).
|
64
deps/rabbitmq_web_dispatch/test/config_schema_SUITE_data/rabbitmq_web_dispatch.snippets
vendored
Normal file
64
deps/rabbitmq_web_dispatch/test/config_schema_SUITE_data/rabbitmq_web_dispatch.snippets
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
% vim:ft=erlang:
|
||||
%
|
||||
|
||||
[{internal_auth_backend,
|
||||
"web_dispatch.auth_backends.1 = internal",
|
||||
[{rabbitmq_web_dispatch,[{auth_backends,[rabbit_auth_backend_internal]}]}],
|
||||
[]},
|
||||
{ldap_auth_backend,
|
||||
"web_dispatch.auth_backends.1 = ldap",
|
||||
[{rabbitmq_web_dispatch,[{auth_backends,[rabbit_auth_backend_ldap]}]}],
|
||||
[]},
|
||||
{http_auth_backend,
|
||||
"web_dispatch.auth_backends.1 = http",
|
||||
[{rabbitmq_web_dispatch,[{auth_backends,[rabbit_auth_backend_http]}]}],
|
||||
[]},
|
||||
{oauth2_auth_backend,
|
||||
"web_dispatch.auth_backends.1 = oauth2",
|
||||
[{rabbitmq_web_dispatch,[{auth_backends,[rabbit_auth_backend_oauth2]}]}],
|
||||
[]},
|
||||
{multiple_auth_backends,
|
||||
"web_dispatch.auth_backends.1 = ldap
|
||||
web_dispatch.auth_backends.2 = internal",
|
||||
[{rabbitmq_web_dispatch,
|
||||
[{auth_backends,
|
||||
[rabbit_auth_backend_ldap,rabbit_auth_backend_internal]}]}],
|
||||
[]},
|
||||
{full_name_auth_backend,
|
||||
"web_dispatch.auth_backends.1 = ldap
|
||||
# uses module name instead of a short alias, \"http\"
|
||||
web_dispatch.auth_backends.2 = rabbit_auth_backend_http",
|
||||
[{rabbitmq_web_dispatch,
|
||||
[{auth_backends,[rabbit_auth_backend_ldap,rabbit_auth_backend_http]}]}],
|
||||
[]},
|
||||
{third_party_auth_backend,
|
||||
"web_dispatch.auth_backends.1.authn = internal
|
||||
# uses module name because this backend is from a 3rd party
|
||||
web_dispatch.auth_backends.1.authz = rabbit_auth_backend_ip_range",
|
||||
[{rabbitmq_web_dispatch,
|
||||
[{auth_backends,
|
||||
[{rabbit_auth_backend_internal,rabbit_auth_backend_ip_range}]}]}],
|
||||
[]},
|
||||
{authn_authz_backend,
|
||||
"web_dispatch.auth_backends.1.authn = ldap
|
||||
web_dispatch.auth_backends.1.authz = internal",
|
||||
[{rabbitmq_web_dispatch,
|
||||
[{auth_backends,
|
||||
[{rabbit_auth_backend_ldap,rabbit_auth_backend_internal}]}]}],
|
||||
[]},
|
||||
{authn_authz_multiple_backends,
|
||||
"web_dispatch.auth_backends.1.authn = ldap
|
||||
web_dispatch.auth_backends.1.authz = internal
|
||||
web_dispatch.auth_backends.2 = internal",
|
||||
[{rabbitmq_web_dispatch,
|
||||
[{auth_backends,
|
||||
[{rabbit_auth_backend_ldap,rabbit_auth_backend_internal},
|
||||
rabbit_auth_backend_internal]}]}],
|
||||
[]},
|
||||
{authn_backend_only,
|
||||
"web_dispatch.auth_backends.1.authn = ldap",
|
||||
[{rabbitmq_web_dispatch,
|
||||
[{auth_backends,
|
||||
[{rabbit_auth_backend_ldap,rabbit_auth_backend_ldap}]}]}],
|
||||
[]}
|
||||
].
|
Loading…
Reference in New Issue