Packages

rabbit_common

3.6.10
4.2.1 4.2.0 retired 4.2.0-rc.1 retired 4.1.6 4.1.5 retired 4.1.5-rc.2 retired 4.1.5-rc.1 4.0.3 4.0.3-rc.1 4.0.2 4.0.2-rc.2 4.0.2-rc.1 4.0.1 4.0.0 4.0.0-rc.2 4.0.0-rc.1 3.13.7 3.13.6 3.13.5 3.13.4 3.13.3 3.13.2 3.13.2-rc.1 3.13.1 3.13.0 3.13.0-rc.6 3.13.0-rc.5 3.13.0-rc.4 3.13.0-rc.3 3.13.0-rc.2 3.13.0-rc.1 3.12.14 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.2 3.12.1 3.12.0 3.12.0-rc.4 3.12.0-rc.3 3.12.0-rc.2 3.12.0-rc.1 3.11.28 3.11.27 3.11.26 3.11.25 3.11.24 3.11.23 3.11.22 3.11.21 3.11.20 3.11.19 3.11.18 3.11.17 3.11.16 3.11.15 3.11.14 3.11.13 3.11.12 3.11.11 3.11.10 3.11.9 3.11.8 3.11.7 3.11.6 3.11.5 3.11.4 3.11.3 3.11.2 3.11.1 3.11.0 3.11.0-rc.2 3.11.0-rc.1 3.11.0-1 3.10.25 3.10.24 3.10.23 3.10.22 3.10.21 3.10.20 3.10.19 3.10.18 3.10.17 3.10.16 3.10.15 3.10.14 3.10.13 3.10.12 3.10.11 3.10.10 3.10.9 3.10.8 3.10.7 3.10.6 3.10.5 3.10.4 3.10.3 3.10.2 3.10.1 3.10.0 3.10.0-rc.6 3.10.0-rc.5 3.9.29 3.9.28 3.9.27 3.9.26 3.9.25 3.9.24 3.9.23 3.9.22 3.9.21 3.9.20 3.9.19 3.9.18 3.9.17 3.9.16 3.9.15 3.9.11 3.9.10 3.9.9 3.9.8 3.9.7 3.9.6 3.9.5 3.9.4 3.9.3 3.9.2 3.9.1 3.8.35 3.8.34 3.8.33 3.8.32 3.8.31 3.8.30 3.8.26 3.8.25 3.8.24 3.8.23 3.8.22 3.8.21 3.8.20 3.8.19 3.8.14 3.8.12-rc.3 3.8.12-rc.2 3.8.12-rc.1 3.8.11 3.8.10 3.8.10-rc.6 3.8.10-rc.5 3.8.10-rc.1 3.8.9 3.8.8 3.8.7 3.8.6 3.8.6-rc.2 3.8.6-rc.1 3.8.5 3.8.5-rc.2 3.8.5-rc.1 3.8.4 3.8.4-rc.3 3.8.4-rc.1 3.8.3 3.8.3-rc.2 3.8.3-rc.1 3.8.2 3.8.2-rc.1 3.8.1 3.8.1-rc.1 3.8.0 3.8.0-rc.3 3.8.0-rc.2 3.8.0-rc.1 3.7.28 3.7.27 3.7.27-rc.2 3.7.27-rc.1 3.7.26 3.7.25 3.7.25-rc.1 3.7.24 3.7.24-rc.2 3.7.24-rc.1 3.7.23 3.7.23-rc.1 3.7.22 3.7.22-rc.2 3.7.22-rc.1 3.7.21 3.7.20 3.7.20-rc.2 3.7.20-rc.1 3.7.19 3.7.18 3.7.18-rc.1 3.7.17 3.7.17-rc.3 3.7.17-rc.2 3.7.17-rc.1 retired 3.7.16 retired 3.7.16-rc.4 retired 3.7.16-rc.3 retired 3.7.16-rc.2 retired 3.7.16-rc.1 retired 3.7.16-beta.1 3.7.15 3.7.14 3.7.14-rc.2 3.7.14-rc.1 3.7.13 3.7.13-rc.2 3.7.13-rc.1 3.7.12 3.7.12-rc.2 3.7.12-rc.1 3.7.11 3.7.11-rc.2 3.7.11-rc.1 3.7.10-rc.4 3.7.10-rc.3 3.7.10-rc.2 3.7.10-rc.1 3.7.9 3.7.9-rc.3 3.7.9-rc.2 3.7.8 3.7.8-rc.4 3.7.8-rc.3 3.7.8-rc.2 3.7.8-rc.1 3.7.7 3.7.7-rc.2 3.7.7-rc.1 3.7.6 3.7.6-rc.2 3.7.6-rc.1 3.7.5 3.7.5-rc.1 3.7.4 3.7.4-rc.4 3.7.4-rc.3 3.7.4-rc.2 3.7.4-rc.1 3.7.3 3.7.3-rc.2 3.7.3-rc.1 3.7.2 3.7.1 3.7.0-rc.2 3.7.0-alpha.544 3.7.0-alpha.542 3.6.16 3.6.16-rc.1 3.6.15 3.6.15-rc.1 3.6.14 3.6.13 3.6.12 3.6.11 3.6.10 3.6.9 3.6.8 3.6.7 3.6.7-pre.1 3.5.6 3.5.0 3.4.0 3.3.5 3.0.2 0.0.0-rc.1

Modules shared by rabbitmq-server and rabbitmq-erlang-client

Current section

Files

Jump to
rabbit_common src rabbit_auth_backend_internal.erl
Raw

src/rabbit_auth_backend_internal.erl

%% The contents of this file are subject to the Mozilla Public License
%% Version 1.1 (the "License"); you may not use this file except in
%% compliance with the License. You may obtain a copy of the License
%% at http://www.mozilla.org/MPL/
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and
%% limitations under the License.
%%
%% The Original Code is RabbitMQ.
%%
%% The Initial Developer of the Original Code is GoPivotal, Inc.
%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved.
%%
-module(rabbit_auth_backend_internal).
-include("rabbit.hrl").
-behaviour(rabbit_authn_backend).
-behaviour(rabbit_authz_backend).
-export([user_login_authentication/2, user_login_authorization/1,
check_vhost_access/3, check_resource_access/3]).
-export([add_user/2, delete_user/1, lookup_user/1,
change_password/2, clear_password/1,
hash_password/2, change_password_hash/2, change_password_hash/3,
set_tags/2, set_permissions/5, clear_permissions/2,
add_user_sans_validation/2]).
-export([user_info_keys/0, perms_info_keys/0,
user_perms_info_keys/0, vhost_perms_info_keys/0,
user_vhost_perms_info_keys/0,
list_users/0, list_users/2, list_permissions/0,
list_user_permissions/1, list_user_permissions/3,
list_vhost_permissions/1, list_vhost_permissions/3,
list_user_vhost_permissions/2]).
%% for testing
-export([hashing_module_for_user/1]).
%%----------------------------------------------------------------------------
-type regexp() :: binary().
-spec add_user(rabbit_types:username(), rabbit_types:password()) -> 'ok' | {'error', string()}.
-spec delete_user(rabbit_types:username()) -> 'ok'.
-spec lookup_user
(rabbit_types:username()) ->
rabbit_types:ok(rabbit_types:internal_user()) |
rabbit_types:error('not_found').
-spec change_password
(rabbit_types:username(), rabbit_types:password()) -> 'ok'.
-spec clear_password(rabbit_types:username()) -> 'ok'.
-spec hash_password
(module(), rabbit_types:password()) -> rabbit_types:password_hash().
-spec change_password_hash
(rabbit_types:username(), rabbit_types:password_hash()) -> 'ok'.
-spec set_tags(rabbit_types:username(), [atom()]) -> 'ok'.
-spec set_permissions
(rabbit_types:username(), rabbit_types:vhost(), regexp(), regexp(),
regexp()) ->
'ok'.
-spec clear_permissions
(rabbit_types:username(), rabbit_types:vhost()) -> 'ok'.
-spec user_info_keys() -> rabbit_types:info_keys().
-spec perms_info_keys() -> rabbit_types:info_keys().
-spec user_perms_info_keys() -> rabbit_types:info_keys().
-spec vhost_perms_info_keys() -> rabbit_types:info_keys().
-spec user_vhost_perms_info_keys() -> rabbit_types:info_keys().
-spec list_users() -> [rabbit_types:infos()].
-spec list_users(reference(), pid()) -> 'ok'.
-spec list_permissions() -> [rabbit_types:infos()].
-spec list_user_permissions
(rabbit_types:username()) -> [rabbit_types:infos()].
-spec list_user_permissions
(rabbit_types:username(), reference(), pid()) -> 'ok'.
-spec list_vhost_permissions
(rabbit_types:vhost()) -> [rabbit_types:infos()].
-spec list_vhost_permissions
(rabbit_types:vhost(), reference(), pid()) -> 'ok'.
-spec list_user_vhost_permissions
(rabbit_types:username(), rabbit_types:vhost()) -> [rabbit_types:infos()].
%%----------------------------------------------------------------------------
%% Implementation of rabbit_auth_backend
%% Returns a password hashing module for the user record provided. If
%% there is no information in the record, we consider it to be legacy
%% (inserted by a version older than 3.6.0) and fall back to MD5, the
%% now obsolete hashing function.
hashing_module_for_user(#internal_user{
hashing_algorithm = ModOrUndefined}) ->
rabbit_password:hashing_mod(ModOrUndefined).
user_login_authentication(Username, []) ->
internal_check_user_login(Username, fun(_) -> true end);
user_login_authentication(Username, AuthProps) ->
case lists:keyfind(password, 1, AuthProps) of
{password, Cleartext} ->
internal_check_user_login(
Username,
fun (#internal_user{
password_hash = <<Salt:4/binary, Hash/binary>>
} = U) ->
Hash =:= rabbit_password:salted_hash(
hashing_module_for_user(U), Salt, Cleartext);
(#internal_user{}) ->
false
end);
false -> exit({unknown_auth_props, Username, AuthProps})
end.
user_login_authorization(Username) ->
case user_login_authentication(Username, []) of
{ok, #auth_user{impl = Impl, tags = Tags}} -> {ok, Impl, Tags};
Else -> Else
end.
internal_check_user_login(Username, Fun) ->
Refused = {refused, "user '~s' - invalid credentials", [Username]},
case lookup_user(Username) of
{ok, User = #internal_user{tags = Tags}} ->
case Fun(User) of
true -> {ok, #auth_user{username = Username,
tags = Tags,
impl = none}};
_ -> Refused
end;
{error, not_found} ->
Refused
end.
check_vhost_access(#auth_user{username = Username}, VHostPath, _Sock) ->
case mnesia:dirty_read({rabbit_user_permission,
#user_vhost{username = Username,
virtual_host = VHostPath}}) of
[] -> false;
[_R] -> true
end.
check_resource_access(#auth_user{username = Username},
#resource{virtual_host = VHostPath, name = Name},
Permission) ->
case mnesia:dirty_read({rabbit_user_permission,
#user_vhost{username = Username,
virtual_host = VHostPath}}) of
[] ->
false;
[#user_permission{permission = P}] ->
PermRegexp = case element(permission_index(Permission), P) of
%% <<"^$">> breaks Emacs' erlang mode
<<"">> -> <<$^, $$>>;
RE -> RE
end,
case re:run(Name, PermRegexp, [{capture, none}]) of
match -> true;
nomatch -> false
end
end.
permission_index(configure) -> #permission.configure;
permission_index(write) -> #permission.write;
permission_index(read) -> #permission.read.
%%----------------------------------------------------------------------------
%% Manipulation of the user database
validate_credentials(Username, Password) ->
rabbit_credential_validation:validate(Username, Password).
validate_and_alternate_credentials(Username, Password, Fun) ->
case validate_credentials(Username, Password) of
ok ->
Fun(Username, Password);
{error, Err} ->
rabbit_log:error("Credential validation for '~s' failed!~n", [Username]),
{error, Err}
end.
add_user(Username, Password) ->
validate_and_alternate_credentials(Username, Password, fun add_user_sans_validation/2).
add_user_sans_validation(Username, Password) ->
rabbit_log:info("Creating user '~s'~n", [Username]),
%% hash_password will pick the hashing function configured for us
%% but we also need to store a hint as part of the record, so we
%% retrieve it here one more time
HashingMod = rabbit_password:hashing_mod(),
User = #internal_user{username = Username,
password_hash = hash_password(HashingMod, Password),
tags = [],
hashing_algorithm = HashingMod},
R = rabbit_misc:execute_mnesia_transaction(
fun () ->
case mnesia:wread({rabbit_user, Username}) of
[] ->
ok = mnesia:write(rabbit_user, User, write);
_ ->
mnesia:abort({user_already_exists, Username})
end
end),
rabbit_event:notify(user_created, [{name, Username}]),
R.
delete_user(Username) ->
rabbit_log:info("Deleting user '~s'~n", [Username]),
R = rabbit_misc:execute_mnesia_transaction(
rabbit_misc:with_user(
Username,
fun () ->
ok = mnesia:delete({rabbit_user, Username}),
[ok = mnesia:delete_object(
rabbit_user_permission, R, write) ||
R <- mnesia:match_object(
rabbit_user_permission,
#user_permission{user_vhost = #user_vhost{
username = Username,
virtual_host = '_'},
permission = '_'},
write)],
ok
end)),
rabbit_event:notify(user_deleted, [{name, Username}]),
R.
lookup_user(Username) ->
rabbit_misc:dirty_read({rabbit_user, Username}).
change_password(Username, Password) ->
validate_and_alternate_credentials(Username, Password, fun change_password_sans_validation/2).
change_password_sans_validation(Username, Password) ->
rabbit_log:info("Changing password for '~s'~n", [Username]),
HashingAlgorithm = rabbit_password:hashing_mod(),
R = change_password_hash(Username,
hash_password(rabbit_password:hashing_mod(),
Password),
HashingAlgorithm),
rabbit_event:notify(user_password_changed, [{name, Username}]),
R.
clear_password(Username) ->
rabbit_log:info("Clearing password for '~s'~n", [Username]),
R = change_password_hash(Username, <<"">>),
rabbit_event:notify(user_password_cleared, [{name, Username}]),
R.
hash_password(HashingMod, Cleartext) ->
rabbit_password:hash(HashingMod, Cleartext).
change_password_hash(Username, PasswordHash) ->
change_password_hash(Username, PasswordHash, rabbit_password:hashing_mod()).
change_password_hash(Username, PasswordHash, HashingAlgorithm) ->
update_user(Username, fun(User) ->
User#internal_user{
password_hash = PasswordHash,
hashing_algorithm = HashingAlgorithm }
end).
set_tags(Username, Tags) ->
rabbit_log:info("Setting user tags for user '~s' to ~p~n",
[Username, Tags]),
R = update_user(Username, fun(User) ->
User#internal_user{tags = Tags}
end),
rabbit_event:notify(user_tags_set, [{name, Username}, {tags, Tags}]),
R.
set_permissions(Username, VHostPath, ConfigurePerm, WritePerm, ReadPerm) ->
rabbit_log:info("Setting permissions for "
"'~s' in '~s' to '~s', '~s', '~s'~n",
[Username, VHostPath, ConfigurePerm, WritePerm, ReadPerm]),
lists:map(
fun (RegexpBin) ->
Regexp = binary_to_list(RegexpBin),
case re:compile(Regexp) of
{ok, _} -> ok;
{error, Reason} -> throw({error, {invalid_regexp,
Regexp, Reason}})
end
end, [ConfigurePerm, WritePerm, ReadPerm]),
R = rabbit_misc:execute_mnesia_transaction(
rabbit_misc:with_user_and_vhost(
Username, VHostPath,
fun () -> ok = mnesia:write(
rabbit_user_permission,
#user_permission{user_vhost = #user_vhost{
username = Username,
virtual_host = VHostPath},
permission = #permission{
configure = ConfigurePerm,
write = WritePerm,
read = ReadPerm}},
write)
end)),
rabbit_event:notify(permission_created, [{user, Username},
{vhost, VHostPath},
{configure, ConfigurePerm},
{write, WritePerm},
{read, ReadPerm}]),
R.
clear_permissions(Username, VHostPath) ->
R = rabbit_misc:execute_mnesia_transaction(
rabbit_misc:with_user_and_vhost(
Username, VHostPath,
fun () ->
ok = mnesia:delete({rabbit_user_permission,
#user_vhost{username = Username,
virtual_host = VHostPath}})
end)),
rabbit_event:notify(permission_deleted, [{user, Username},
{vhost, VHostPath}]),
R.
update_user(Username, Fun) ->
rabbit_misc:execute_mnesia_transaction(
rabbit_misc:with_user(
Username,
fun () ->
{ok, User} = lookup_user(Username),
ok = mnesia:write(rabbit_user, Fun(User), write)
end)).
%%----------------------------------------------------------------------------
%% Listing
-define(PERMS_INFO_KEYS, [configure, write, read]).
-define(USER_INFO_KEYS, [user, tags]).
user_info_keys() -> ?USER_INFO_KEYS.
perms_info_keys() -> [user, vhost | ?PERMS_INFO_KEYS].
vhost_perms_info_keys() -> [user | ?PERMS_INFO_KEYS].
user_perms_info_keys() -> [vhost | ?PERMS_INFO_KEYS].
user_vhost_perms_info_keys() -> ?PERMS_INFO_KEYS.
list_users() ->
[extract_internal_user_params(U) ||
U <- mnesia:dirty_match_object(rabbit_user, #internal_user{_ = '_'})].
list_users(Ref, AggregatorPid) ->
rabbit_control_misc:emitting_map(
AggregatorPid, Ref,
fun(U) -> extract_internal_user_params(U) end,
mnesia:dirty_match_object(rabbit_user, #internal_user{_ = '_'})).
list_permissions() ->
list_permissions(perms_info_keys(), match_user_vhost('_', '_')).
list_permissions(Keys, QueryThunk) ->
[extract_user_permission_params(Keys, U) ||
%% TODO: use dirty ops instead
U <- rabbit_misc:execute_mnesia_transaction(QueryThunk)].
list_permissions(Keys, QueryThunk, Ref, AggregatorPid) ->
rabbit_control_misc:emitting_map(
AggregatorPid, Ref, fun(U) -> extract_user_permission_params(Keys, U) end,
%% TODO: use dirty ops instead
rabbit_misc:execute_mnesia_transaction(QueryThunk)).
filter_props(Keys, Props) -> [T || T = {K, _} <- Props, lists:member(K, Keys)].
list_user_permissions(Username) ->
list_permissions(
user_perms_info_keys(),
rabbit_misc:with_user(Username, match_user_vhost(Username, '_'))).
list_user_permissions(Username, Ref, AggregatorPid) ->
list_permissions(
user_perms_info_keys(),
rabbit_misc:with_user(Username, match_user_vhost(Username, '_')),
Ref, AggregatorPid).
list_vhost_permissions(VHostPath) ->
list_permissions(
vhost_perms_info_keys(),
rabbit_vhost:with(VHostPath, match_user_vhost('_', VHostPath))).
list_vhost_permissions(VHostPath, Ref, AggregatorPid) ->
list_permissions(
vhost_perms_info_keys(),
rabbit_vhost:with(VHostPath, match_user_vhost('_', VHostPath)),
Ref, AggregatorPid).
list_user_vhost_permissions(Username, VHostPath) ->
list_permissions(
user_vhost_perms_info_keys(),
rabbit_misc:with_user_and_vhost(
Username, VHostPath, match_user_vhost(Username, VHostPath))).
extract_user_permission_params(Keys, #user_permission{
user_vhost =
#user_vhost{username = Username,
virtual_host = VHostPath},
permission = #permission{
configure = ConfigurePerm,
write = WritePerm,
read = ReadPerm}}) ->
filter_props(Keys, [{user, Username},
{vhost, VHostPath},
{configure, ConfigurePerm},
{write, WritePerm},
{read, ReadPerm}]).
extract_internal_user_params(#internal_user{username = Username, tags = Tags}) ->
[{user, Username}, {tags, Tags}].
match_user_vhost(Username, VHostPath) ->
fun () -> mnesia:match_object(
rabbit_user_permission,
#user_permission{user_vhost = #user_vhost{
username = Username,
virtual_host = VHostPath},
permission = '_'},
read)
end.