Add new configuration for rabbitmq_web_dispatch.auth_backends with a fallback to the core auth_backends
This commit is contained in:
parent
852f8243a5
commit
b048ed55bb
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
-include_lib("rabbit_common/include/rabbit.hrl").
|
-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_vhost_access/4, check_resource_access/4, check_topic_access/4,
|
||||||
check_user_id/2]).
|
check_user_id/2]).
|
||||||
|
|
||||||
|
@ -33,6 +33,14 @@ check_user_pass_login(Username, Password) ->
|
||||||
check_user_login(Username, AuthProps) ->
|
check_user_login(Username, AuthProps) ->
|
||||||
%% extra auth properties like MQTT client id are in AuthProps
|
%% extra auth properties like MQTT client id are in AuthProps
|
||||||
{ok, Modules} = application:get_env(rabbit, auth_backends),
|
{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
|
try
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun (rabbit_auth_backend_cache=ModN, {refused, _, _, _}) ->
|
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,
|
end,
|
||||||
{IP, _} = cowboy_req:peer(ReqData),
|
{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}} ->
|
{ok, User = #user{username = ResolvedUsername, tags = Tags}} ->
|
||||||
case rabbit_access_control:check_user_loopback(ResolvedUsername, IP) of
|
case rabbit_access_control:check_user_loopback(ResolvedUsername, IP) of
|
||||||
ok ->
|
ok ->
|
||||||
|
@ -359,3 +362,11 @@ log_access_control_result(NotOK) ->
|
||||||
|
|
||||||
is_basic_auth_disabled(#auth_settings{basic_auth_enabled = Enabled}) ->
|
is_basic_auth_disabled(#auth_settings{basic_auth_enabled = Enabled}) ->
|
||||||
not 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