Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions deps/rabbit/src/rabbit.erl
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@
{requires, pre_boot},
{enables, external_infrastructure}]}).

-rabbit_boot_step({auth_backend_plugins_check,
[{description, "check configured auth plugins are enabled"},
{mfa, {rabbit_access_control,
ensure_auth_backends_are_enabled,
[]}},
{requires, pre_boot},
{enables, external_infrastructure}]}).

%% rabbit_alarm currently starts memory and disk space monitors
-rabbit_boot_step({rabbit_alarm,
[{description, "alarm handler"},
Expand Down
136 changes: 136 additions & 0 deletions deps/rabbit/src/rabbit_access_control.erl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
-include_lib("rabbit_common/include/rabbit.hrl").
-include_lib("kernel/include/logger.hrl").

-export([ensure_auth_backends_are_enabled/0]).
-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]).
Expand All @@ -18,6 +19,141 @@

%%----------------------------------------------------------------------------

-spec ensure_auth_backends_are_enabled() -> Ret when
Ret :: ok | {error, Reason},
Reason :: string().

ensure_auth_backends_are_enabled() ->
{ok, AuthBackends} = application:get_env(rabbit, auth_backends),
ValidAuthBackends = filter_valid_auth_backend_configuration(
AuthBackends, []),
case ValidAuthBackends of
AuthBackends ->
ok;
[_ | _] ->
%% Some auth backend modules were filtered out because their
%% corresponding plugin is either unavailable or disabled. We
%% update the application environment variable so that
%% authentication and authorization do not try to use them.
?LOG_WARNING(
"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:~n~p", [ValidAuthBackends]),
ok = application:set_env(rabbit, auth_backends, ValidAuthBackends),
ok;
[] ->
%% None of the auth backend modules are usable. Log an error and
%% abort the boot of RabbitMQ.
?LOG_ERROR(
"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."),
{error,
"Authentication/authorization backends require plugins to be "
"enabled; see logs for details"}
end.

filter_valid_auth_backend_configuration(
[Mod | Rest], ValidAuthBackends)
when is_atom(Mod) ->
case is_auth_backend_module_enabled(Mod) of
true ->
ValidAuthBackends1 = [Mod | ValidAuthBackends],
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends1);
false ->
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends)
end;
filter_valid_auth_backend_configuration(
[{ModN, ModZ} = Mod | Rest], ValidAuthBackends)
when is_atom(ModN) andalso is_atom(ModZ) ->
%% Both auth backend modules must be usable to keep the entire pair.
IsModNEnabled = is_auth_backend_module_enabled(ModN),
IsModZEnabled = is_auth_backend_module_enabled(ModZ),
case IsModNEnabled andalso IsModZEnabled of
true ->
ValidAuthBackends1 = [Mod | ValidAuthBackends],
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends1);
false ->
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends)
end;
filter_valid_auth_backend_configuration(
[{ModN, ModZs} | Rest], ValidAuthBackends)
when is_atom(ModN) andalso is_list(ModZs) ->
%% The authentication backend module and at least on of the authorization
%% backend module must be usable to keep the entire pair.
%%
%% The list of authorization backend modules may be shorter than the
%% configured one after the filtering.
IsModNEnabled = is_auth_backend_module_enabled(ModN),
EnabledModZs = lists:filter(fun is_auth_backend_module_enabled/1, ModZs),
case IsModNEnabled andalso EnabledModZs =/= [] of
true ->
Mod1 = {ModN, EnabledModZs},
ValidAuthBackends1 = [Mod1 | ValidAuthBackends],
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends1);
false ->
filter_valid_auth_backend_configuration(Rest, ValidAuthBackends)
end;
filter_valid_auth_backend_configuration([], ValidAuthBackends) ->
lists:reverse(ValidAuthBackends).

is_auth_backend_module_enabled(Mod) when is_atom(Mod) ->
%% We check if the module is provided by the core of RabbitMQ or a plugin,
%% and if that plugin is enabled.
{ok, Modules} = application:get_key(rabbit, modules),
case lists:member(Mod, Modules) of
true ->
true;
false ->
%% The module is not provided by RabbitMQ core. Let's query
%% plugins then.
case rabbit_plugins:which_plugin(Mod) of
{ok, PluginName} ->
%% FIXME: The definition of an "enabled plugin" in
%% `rabbit_plugins' varies from funtion to function.
%% Sometimes, it means the "rabbitmq-plugin enable
%% <plugin>" was executed, sometimes it means the plugin
%% is running.
%%
%% This function is a boot step and is executed before
%% plugin are started. Therefore, we can't rely on
%% `rabbit_plugins:is_enabled/1' because it uses the
%% latter definition of "the plugin is running, regardless
%% of if it is enabled or not".
%%
%% Therefore, we use `rabbit_plugins:enabled_plugins/0'
%% which lists explicitly enabled plugins. Unfortunately,
%% it won't include the implicitly enabled plugins (i.e,
%% plugins that are dependencies of explicitly enabled
%% plugins).
EnabledPlugins = rabbit_plugins:enabled_plugins(),
case lists:member(PluginName, EnabledPlugins) of
true ->
true;
false ->
?LOG_INFO(
"The `~ts` auth backend module is configured. "
"However, the `~ts` plugin must be enabled in "
"order to use this auth backend. Until then "
"it will be skipped during "
"authentication/authorization",
[Mod, PluginName]),
false
end;
{error, no_provider} ->
?LOG_INFO(
"The `~ts` auth backend module is configured. "
"However, no plugins available provide this "
"module. Until then it will be skipped during "
"authentication/authorization",
[Mod]),
false
end
end.

-spec check_user_pass_login
(rabbit_types:username(), rabbit_types:password()) ->
{'ok', rabbit_types:user()} |
Expand Down
68 changes: 63 additions & 5 deletions deps/rabbit/src/rabbit_plugins.erl
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
-module(rabbit_plugins).
-include_lib("rabbit_common/include/rabbit.hrl").
-include_lib("kernel/include/logger.hrl").
-export([setup/0, active/0, read_enabled/1, list/1, list/2, dependencies/3, running_plugins/0]).
-export([setup/0, active/0, read_enabled/1, list/0, list/1, list/2, dependencies/3, running_plugins/0]).
-export([ensure/1]).
-export([validate_plugins/1, format_invalid_plugins/1]).
-export([is_strictly_plugin/1, strictly_plugins/2, strictly_plugins/1]).
-export([plugins_dir/0, plugin_names/1, plugins_expand_dir/0, enabled_plugins_file/0]).
-export([is_enabled/1, is_enabled_on_node/2]).
-export([is_enabled/1, is_enabled_on_node/2, enabled_plugins/0]).
-export([which_plugin/1]).

% Export for testing purpose.
-export([is_version_supported/2, validate_plugins/2]).
Expand Down Expand Up @@ -130,7 +131,7 @@ setup() ->
-spec active() -> [plugin_name()].

active() ->
InstalledPlugins = plugin_names(list(plugins_dir())),
InstalledPlugins = plugin_names(list()),
[App || {App, _, _} <- rabbit_misc:which_applications(),
lists:member(App, InstalledPlugins)].

Expand All @@ -157,6 +158,13 @@ is_enabled_on_node(Name, Node) ->
_Class:_Reason:_Stacktrace -> false
end.

-spec list() -> [#plugin{}].
%% @doc Get the list of plugins from the configured plugin path.

list() ->
PluginsPath = plugins_dir(),
list(PluginsPath).

%% @doc Get the list of plugins which are ready to be enabled.

-spec list(string()) -> [#plugin{}].
Expand Down Expand Up @@ -228,7 +236,7 @@ strictly_plugins(Plugins, AllPlugins) ->
-spec strictly_plugins([plugin_name()]) -> [plugin_name()].

strictly_plugins(Plugins) ->
AllPlugins = list(plugins_dir()),
AllPlugins = list(),
lists:filter(
fun(Name) ->
is_strictly_plugin(lists:keyfind(Name, #plugin.name, AllPlugins))
Expand Down Expand Up @@ -279,11 +287,61 @@ running_plugins() ->
ActivePlugins = active(),
{ok, [{App, Vsn} || {App, _ , Vsn} <- rabbit_misc:which_applications(), lists:member(App, ActivePlugins)]}.

-spec which_plugin(Module) -> Ret when
Module :: module(),
Ret :: {ok, PluginName} | {error, Reason},
PluginName :: atom(),
Reason :: no_provider.
%% @doc Returns the name of the plugin that provides the given module.
%%
%% If no plugin provides the module, `{error, no_provider}' is returned.
%%
%% The returned plugin might not be enabled, thus using the given module might
%% not work until the plugin is enabled.
%%
%% @returns An `{ok, PluginName}' tuple with the name of the plugin providing
%% the module, or `{error, no_provider}'.

which_plugin(Module) ->
Plugins = list(),
which_plugin(Plugins, Module).

which_plugin([#plugin{name = Name} | Rest], Module) ->
%% Get the list of modules belonging to this plugin.
ModulesKey = case application:get_key(Name, modules) of
{ok, _} = Ret ->
Ret;
undefined ->
%% The plugin application might not be loaded. Load
%% it temporarily and try again.
case application:load(Name) of
ok ->
Ret = application:get_key(Name, modules),
_ = application:unload(Name),
Ret;
{error, _Reason} ->
undefined
end
end,
case ModulesKey of
{ok, Modules} ->
case lists:member(Module, Modules) of
true ->
{ok, Name};
false ->
which_plugin(Rest, Module)
end;
undefined ->
which_plugin(Rest, Module)
end;
which_plugin([], _Module) ->
{error, no_provider}.

%%----------------------------------------------------------------------------

prepare_plugins(Enabled) ->
ExpandDir = plugins_expand_dir(),
AllPlugins = list(plugins_dir()),
AllPlugins = list(),
Wanted = dependencies(false, Enabled, AllPlugins),
WantedPlugins = lookup_plugins(Wanted, AllPlugins),
{ValidPlugins, Problems} = validate_plugins(WantedPlugins),
Expand Down
Loading
Loading