|
10 | 10 | -include_lib("rabbit_common/include/rabbit.hrl").
|
11 | 11 | -include_lib("kernel/include/logger.hrl").
|
12 | 12 |
|
| 13 | +-export([ensure_auth_backends_are_enabled/0]). |
13 | 14 | -export([check_user_pass_login/2, check_user_login/2, check_user_login/3, check_user_loopback/2,
|
14 | 15 | check_vhost_access/4, check_resource_access/4, check_topic_access/4,
|
15 | 16 | check_user_id/2]).
|
|
18 | 19 |
|
19 | 20 | %%----------------------------------------------------------------------------
|
20 | 21 |
|
| 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 | + %% FIXME: The definition of an "enabled plugin" in |
| 116 | + %% `rabbit_plugins' varies from funtion to function. |
| 117 | + %% Sometimes, it means the "rabbitmq-plugin enable |
| 118 | + %% <plugin>" was executed, sometimes it means the plugin |
| 119 | + %% is running. |
| 120 | + %% |
| 121 | + %% This function is a boot step and is executed before |
| 122 | + %% plugin are started. Therefore, we can't rely on |
| 123 | + %% `rabbit_plugins:is_enabled/1' because it uses the |
| 124 | + %% latter definition of "the plugin is running, regardless |
| 125 | + %% of if it is enabled or not". |
| 126 | + %% |
| 127 | + %% Therefore, we use `rabbit_plugins:enabled_plugins/0' |
| 128 | + %% which lists explicitly enabled plugins. Unfortunately, |
| 129 | + %% it won't include the implicitly enabled plugins (i.e, |
| 130 | + %% plugins that are dependencies of explicitly enabled |
| 131 | + %% plugins). |
| 132 | + EnabledPlugins = rabbit_plugins:enabled_plugins(), |
| 133 | + case lists:member(PluginName, EnabledPlugins) of |
| 134 | + true -> |
| 135 | + true; |
| 136 | + false -> |
| 137 | + ?LOG_INFO( |
| 138 | + "The `~ts` auth backend module is configured. " |
| 139 | + "However, the `~ts` plugin must be enabled in " |
| 140 | + "order to use this auth backend. Until then " |
| 141 | + "it will be skipped during " |
| 142 | + "authentication/authorization", |
| 143 | + [Mod, PluginName]), |
| 144 | + false |
| 145 | + end; |
| 146 | + {error, no_provider} -> |
| 147 | + ?LOG_INFO( |
| 148 | + "The `~ts` auth backend module is configured. " |
| 149 | + "However, no plugins available provide this " |
| 150 | + "module. Until then it will be skipped during " |
| 151 | + "authentication/authorization", |
| 152 | + [Mod]), |
| 153 | + false |
| 154 | + end |
| 155 | + end. |
| 156 | + |
21 | 157 | -spec check_user_pass_login
|
22 | 158 | (rabbit_types:username(), rabbit_types:password()) ->
|
23 | 159 | {'ok', rabbit_types:user()} |
|
|
0 commit comments