Skip to content

Commit f886f30

Browse files
committed
rabbit_access_control: Check configured auth backends are enabled at boot time
[Why] If a user configures an auth backend module, but doesn't enabled the plugin that provides it, it will get a crash and a stacktrace when authentication is performed. The error is not helpful to understand what the problem is. [How] We add a boot step that go through the configured auth backends and query the core of RabbitMQ and the plugins. If an auth backend is provided by a plugin, the plugin must be enabled to consider the auth backend to be valid. In the end, at least one auth backend must be valid, otherwise the boot is aborted. If only some of the configured auth backends were filtered out, but there are still some valid auth backends, we store the filtered list in the application environment variable so that authentication/authorization doesn't try to use them later. We also report invalid auth backends in the logs: * Info message for a single invalid auth backend: [info] <0.213.0> The `rabbit_auth_backend_ldap` auth backend module is configured. However, the `rabbitmq_auth_backend_ldap` plugin must be enabled in order to use this auth backend. Until then it will be skipped during authentication/authorization * Warning message when some auth backends were filtered out: [warning] <0.213.0> Some configured backends were dropped because their corresponding plugins are disabled. Please look at the info messages above to learn which plugin(s) should be enabled. Here is the list of auth backends kept after filering: [warning] <0.213.0> [rabbit_auth_backend_internal] * Error message when no auth backends are valid: [error] <0.213.0> None of the configured auth backends are usable because their corresponding plugins were not enabled. Please look at the info messages above to learn which plugin(s) should be enabled. Fixes #13783.
1 parent b4687fc commit f886f30

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed

deps/rabbit/src/rabbit.erl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@
5252
{requires, pre_boot},
5353
{enables, external_infrastructure}]}).
5454

55+
-rabbit_boot_step({auth_backend_plugins_check,
56+
[{description, "check configured auth plugins are enabled"},
57+
{mfa, {rabbit_access_control,
58+
ensure_auth_backends_are_enabled,
59+
[]}},
60+
{requires, pre_boot},
61+
{enables, external_infrastructure}]}).
62+
5563
%% rabbit_alarm currently starts memory and disk space monitors
5664
-rabbit_boot_step({rabbit_alarm,
5765
[{description, "alarm handler"},

deps/rabbit/src/rabbit_access_control.erl

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
-include_lib("rabbit_common/include/rabbit.hrl").
1111
-include_lib("kernel/include/logger.hrl").
1212

13+
-export([ensure_auth_backends_are_enabled/0]).
1314
-export([check_user_pass_login/2, check_user_login/2, check_user_login/3, check_user_loopback/2,
1415
check_vhost_access/4, check_resource_access/4, check_topic_access/4,
1516
check_user_id/2]).
@@ -18,6 +19,123 @@
1819

1920
%%----------------------------------------------------------------------------
2021

22+
-spec ensure_auth_backends_are_enabled() -> Ret when
23+
Ret :: ok | {error, Reason},
24+
Reason :: string().
25+
26+
ensure_auth_backends_are_enabled() ->
27+
{ok, AuthBackends} = application:get_env(rabbit, auth_backends),
28+
ValidAuthBackends = filter_valid_auth_backend_configuration(
29+
AuthBackends, []),
30+
case ValidAuthBackends of
31+
AuthBackends ->
32+
ok;
33+
[_ | _] ->
34+
%% Some auth backend modules were filtered out because their
35+
%% corresponding plugin is either unavailable or disabled. We
36+
%% update the application environment variable so that
37+
%% authentication and authorization do not try to use them.
38+
?LOG_WARNING(
39+
"Some configured backends were dropped because their "
40+
"corresponding plugins are disabled. Please look at the "
41+
"info messages above to learn which plugin(s) should be "
42+
"enabled. Here is the list of auth backends kept after "
43+
"filering:~n~p", [ValidAuthBackends]),
44+
ok = application:set_env(rabbit, auth_backends, ValidAuthBackends),
45+
ok;
46+
[] ->
47+
%% None of the auth backend modules are usable. Log an error and
48+
%% abort the boot of RabbitMQ.
49+
?LOG_ERROR(
50+
"None of the configured auth backends are usable because "
51+
"their corresponding plugins were not enabled. Please look "
52+
"at the info messages above to learn which plugin(s) should "
53+
"be enabled."),
54+
{error,
55+
"Authentication/authorization backends require plugins to be "
56+
"enabled; see logs for details"}
57+
end.
58+
59+
filter_valid_auth_backend_configuration(
60+
[Mod | Rest], ValidAuthBackends)
61+
when is_atom(Mod) ->
62+
case is_auth_backend_module_enabled(Mod) of
63+
true ->
64+
ValidAuthBackends1 = [Mod | ValidAuthBackends],
65+
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends1);
66+
false ->
67+
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends)
68+
end;
69+
filter_valid_auth_backend_configuration(
70+
[{ModN, ModZ} = Mod | Rest], ValidAuthBackends)
71+
when is_atom(ModN) andalso is_atom(ModZ) ->
72+
%% Both auth backend modules must be usable to keep the entire pair.
73+
IsModNEnabled = is_auth_backend_module_enabled(ModN),
74+
IsModZEnabled = is_auth_backend_module_enabled(ModZ),
75+
case IsModNEnabled andalso IsModZEnabled of
76+
true ->
77+
ValidAuthBackends1 = [Mod | ValidAuthBackends],
78+
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends1);
79+
false ->
80+
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends)
81+
end;
82+
filter_valid_auth_backend_configuration(
83+
[{ModN, ModZs} | Rest], ValidAuthBackends)
84+
when is_atom(ModN) andalso is_list(ModZs) ->
85+
%% The authentication backend module and at least on of the authorization
86+
%% backend module must be usable to keep the entire pair.
87+
%%
88+
%% The list of authorization backend modules may be shorter than the
89+
%% configured one after the filtering.
90+
IsModNEnabled = is_auth_backend_module_enabled(ModN),
91+
EnabledModZs = lists:filter(fun is_auth_backend_module_enabled/1, ModZs),
92+
case IsModNEnabled andalso EnabledModZs =/= [] of
93+
true ->
94+
Mod1 = {ModN, EnabledModZs},
95+
ValidAuthBackends1 = [Mod1 | ValidAuthBackends],
96+
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends1);
97+
false ->
98+
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends)
99+
end;
100+
filter_valid_auth_backend_configuration([], ValidAuthBackends) ->
101+
lists:reverse(ValidAuthBackends).
102+
103+
is_auth_backend_module_enabled(Mod) when is_atom(Mod) ->
104+
%% We check if the module is provided by the core of RabbitMQ or a plugin,
105+
%% and if that plugin is enabled.
106+
{ok, Modules} = application:get_key(rabbit, modules),
107+
case lists:member(Mod, Modules) of
108+
true ->
109+
true;
110+
false ->
111+
%% The module is not provided by RabbitMQ core. Let's query
112+
%% plugins then.
113+
case rabbit_plugins:which_plugin(Mod) of
114+
{ok, PluginName} ->
115+
case rabbit_plugins:is_enabled(PluginName) of
116+
true ->
117+
true;
118+
false ->
119+
?LOG_INFO(
120+
"The `~ts` auth backend module is configured. "
121+
"However, the `~ts` plugin must be enabled in "
122+
"order to use this auth backend. Until then "
123+
"it will be skipped during "
124+
"authentication/authorization",
125+
[Mod, PluginName]),
126+
false
127+
end;
128+
{error, no_provider} ->
129+
?LOG_INFO(
130+
"The `~ts` auth backend module is configured. "
131+
"However, no plugins available provide this "
132+
"module. Until then it will be skipped during "
133+
"authentication/authorization",
134+
[Mod]),
135+
false
136+
end
137+
end.
138+
21139
-spec check_user_pass_login
22140
(rabbit_types:username(), rabbit_types:password()) ->
23141
{'ok', rabbit_types:user()} |

0 commit comments

Comments
 (0)