summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordcorbacho <dparracorbacho@piotal.io>2021-12-10 16:23:06 +0100
committermergify-bot <noreply@mergify.com>2021-12-15 14:53:22 +0000
commitfcfb7c2953c996aa326802c34043b65611d88e37 (patch)
tree8dc301a2d07918ec6b109f26006838b0e6f6d319
parent0ccf013e2226d991b3d8f6cf2c711e14d89c8d2a (diff)
downloadrabbitmq-server-git-fcfb7c2953c996aa326802c34043b65611d88e37.tar.gz
Optimise user declare/update/import by reducing the number of operations
User, tags and hashed password can be inserted/updated at once, increasing the performance of the storage backend - mnesia. (cherry picked from commit 08b78aa2d705eb368f7dde70c5a6ee9f95731f72)
-rw-r--r--deps/rabbit/src/rabbit_auth_backend_internal.erl125
1 files changed, 100 insertions, 25 deletions
diff --git a/deps/rabbit/src/rabbit_auth_backend_internal.erl b/deps/rabbit/src/rabbit_auth_backend_internal.erl
index a46beaaf83..06467d9633 100644
--- a/deps/rabbit/src/rabbit_auth_backend_internal.erl
+++ b/deps/rabbit/src/rabbit_auth_backend_internal.erl
@@ -14,12 +14,15 @@
-export([user_login_authentication/2, user_login_authorization/2,
check_vhost_access/3, check_resource_access/4, check_topic_access/4]).
--export([add_user/3, delete_user/2, lookup_user/1, exists/1,
+-export([add_user/3, add_user/4, delete_user/2, lookup_user/1, exists/1,
change_password/3, clear_password/2,
hash_password/2, change_password_hash/2, change_password_hash/3,
set_tags/3, set_permissions/6, clear_permissions/3,
set_topic_permissions/6, clear_topic_permissions/3, clear_topic_permissions/4,
- add_user_sans_validation/3, put_user/2, put_user/3]).
+ add_user_sans_validation/3, put_user/2, put_user/3,
+ change_password_and_tags/4,
+ change_password_hash_and_tags/4,
+ add_user_sans_validation/5]).
-export([set_user_limits/3, clear_user_limits/3, is_over_connection_limit/1,
is_over_channel_limit/1, get_user_limits/0, get_user_limits/1]).
@@ -208,14 +211,45 @@ add_user(Username, Password, ActingUser) ->
validate_and_alternate_credentials(Username, Password, ActingUser,
fun add_user_sans_validation/3).
+-spec add_user(rabbit_types:username(), rabbit_types:password(),
+ rabbit_types:username(), [atom()]) -> 'ok' | {'error', string()}.
+
+add_user(Username, Password, ActingUser, Tags) ->
+ validate_and_alternate_credentials(Username, Password, ActingUser,
+ add_user_sans_validation(Tags)).
+
add_user_sans_validation(Username, Password, ActingUser) ->
+ add_user_sans_validation(Username, Password, ActingUser, []).
+
+add_user_sans_validation(Tags) ->
+ fun(Username, Password, ActingUser) ->
+ add_user_sans_validation(Username, Password, ActingUser, Tags)
+ end.
+
+add_user_sans_validation(Username, Password, ActingUser, Tags) ->
rabbit_log:debug("Asked to create a new user '~s', password length in bytes: ~p", [Username, bit_size(Password)]),
%% 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(),
PasswordHash = hash_password(HashingMod, Password),
- User = internal_user:create_user(Username, PasswordHash, HashingMod),
+ User0 = internal_user:create_user(Username, PasswordHash, HashingMod),
+ ConvertedTags = [rabbit_data_coercion:to_atom(I) || I <- Tags],
+ User = internal_user:set_tags(User0, ConvertedTags),
+ add_user_sans_validation_in(Username, User, ConvertedTags, ActingUser).
+
+add_user_sans_validation(Username, PasswordHash, HashingAlgorithm, Tags, ActingUser) ->
+ rabbit_log:debug("Asked to create a new user '~s' with password hash", [Username]),
+ ConvertedTags = [rabbit_data_coercion:to_atom(I) || I <- Tags],
+ HashingMod = rabbit_password:hashing_mod(),
+ User0 = internal_user:create_user(Username, PasswordHash, HashingMod),
+ User = internal_user:set_tags(
+ internal_user:set_password_hash(User0,
+ PasswordHash, HashingAlgorithm),
+ ConvertedTags),
+ add_user_sans_validation_in(Username, User, ConvertedTags, ActingUser).
+
+add_user_sans_validation_in(Username, User, ConvertedTags, ActingUser) ->
try
R = rabbit_misc:execute_mnesia_transaction(
fun () ->
@@ -229,6 +263,10 @@ add_user_sans_validation(Username, Password, ActingUser) ->
rabbit_log:info("Created user '~s'", [Username]),
rabbit_event:notify(user_created, [{name, Username},
{user_who_performed_action, ActingUser}]),
+ case ConvertedTags of
+ [] -> ok;
+ _ -> notify_user_tags_set(Username, ConvertedTags, ActingUser)
+ end,
R
catch
throw:{error, {user_already_exists, _}} = Error ->
@@ -322,6 +360,41 @@ change_password_sans_validation(Username, Password, ActingUser) ->
erlang:raise(Class, Error, Stacktrace)
end.
+change_password_and_tags(Username, Password, Tags, ActingUser) ->
+ validate_and_alternate_credentials(Username, Password, ActingUser,
+ change_password_and_tags_sans_validation(Tags)).
+
+change_password_and_tags_sans_validation(Tags) ->
+ fun(Username, Password, ActingUser) ->
+ try
+ rabbit_log:debug("Asked to change password of user '~s', new password length in bytes: ~p", [Username, bit_size(Password)]),
+ HashingAlgorithm = rabbit_password:hashing_mod(),
+
+ rabbit_log:debug("Asked to set user tags for user '~s' to ~p", [Username, Tags]),
+
+ ConvertedTags = [rabbit_data_coercion:to_atom(I) || I <- Tags],
+ R = change_password_hash_and_tags(Username,
+ hash_password(rabbit_password:hashing_mod(),
+ Password),
+ HashingAlgorithm,
+ ConvertedTags),
+ rabbit_log:info("Successfully changed password for user '~s'", [Username]),
+ rabbit_event:notify(user_password_changed,
+ [{name, Username},
+ {user_who_performed_action, ActingUser}]),
+
+ notify_user_tags_set(Username, ConvertedTags, ActingUser),
+ R
+ catch
+ throw:{error, {no_such_user, _}} = Error ->
+ rabbit_log:warning("Failed to change password for user '~s': the user does not exist", [Username]),
+ throw(Error);
+ Class:Error:Stacktrace ->
+ rabbit_log:warning("Failed to change password for user '~s': ~p", [Username, Error]),
+ erlang:raise(Class, Error, Stacktrace)
+ end
+ end.
+
-spec clear_password(rabbit_types:username(), rabbit_types:username()) -> 'ok'.
clear_password(Username, ActingUser) ->
@@ -351,6 +424,14 @@ change_password_hash(Username, PasswordHash, HashingAlgorithm) ->
PasswordHash, HashingAlgorithm)
end).
+change_password_hash_and_tags(Username, PasswordHash, HashingAlgorithm, ConvertedTags) ->
+ update_user(Username, fun(User) ->
+ internal_user:set_tags(
+ internal_user:set_password_hash(User,
+ PasswordHash, HashingAlgorithm),
+ ConvertedTags)
+ end).
+
-spec set_tags(rabbit_types:username(), [atom()], rabbit_types:username()) -> 'ok'.
set_tags(Username, Tags, ActingUser) ->
@@ -360,9 +441,7 @@ set_tags(Username, Tags, ActingUser) ->
R = update_user(Username, fun(User) ->
internal_user:set_tags(User, ConvertedTags)
end),
- rabbit_log:info("Successfully set user tags for user '~s' to ~p", [Username, ConvertedTags]),
- rabbit_event:notify(user_tags_set, [{name, Username}, {tags, ConvertedTags},
- {user_who_performed_action, ActingUser}]),
+ notify_user_tags_set(Username, ConvertedTags, ActingUser),
R
catch
throw:{error, {no_such_user, _}} = Error ->
@@ -373,6 +452,11 @@ set_tags(Username, Tags, ActingUser) ->
erlang:raise(Class, Error, Stacktrace)
end .
+notify_user_tags_set(Username, ConvertedTags, ActingUser) ->
+ rabbit_log:info("Successfully set user tags for user '~s' to ~p", [Username, ConvertedTags]),
+ rabbit_event:notify(user_tags_set, [{name, Username}, {tags, ConvertedTags},
+ {user_who_performed_action, ActingUser}]).
+
-spec set_permissions
(rabbit_types:username(), rabbit_types:vhost(), regexp(), regexp(),
regexp(), rabbit_types:username()) ->
@@ -654,7 +738,7 @@ put_user(User, Version, ActingUser) ->
{true, false} ->
update_user_password(PassedCredentialValidation, Username, Password, Tags, ActingUser);
{false, true} ->
- update_user_password_hash(Username, PasswordHash, Tags, User, Version, ActingUser);
+ update_user_password_hash(Username, PasswordHash, Tags, User, Version);
{true, true} ->
throw({error, both_password_and_password_hash_are_provided});
%% clear password, update tags if needed
@@ -679,29 +763,27 @@ put_user(User, Version, ActingUser) ->
end.
update_user_password(_PassedCredentialValidation = true, Username, Password, Tags, ActingUser) ->
- rabbit_auth_backend_internal:change_password(Username, Password, ActingUser),
- rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser);
+ %% change_password, set_tags
+ rabbit_auth_backend_internal:change_password_and_tags(Username, Password, Tags, ActingUser);
update_user_password(_PassedCredentialValidation = false, _Username, _Password, _Tags, _ActingUser) ->
%% we don't log here because
%% rabbit_auth_backend_internal will do it
throw({error, credential_validation_failed}).
-update_user_password_hash(Username, PasswordHash, Tags, User, Version, ActingUser) ->
+update_user_password_hash(Username, PasswordHash, Tags, User, Version) ->
%% when a hash this provided, credential validation
%% is not applied
HashingAlgorithm = hashing_algorithm(User, Version),
Hash = rabbit_misc:b64decode_or_throw(PasswordHash),
- rabbit_auth_backend_internal:change_password_hash(
- Username, Hash, HashingAlgorithm),
- rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser).
+ ConvertedTags = [rabbit_data_coercion:to_atom(I) || I <- Tags],
+ rabbit_auth_backend_internal:change_password_hash_and_tags(
+ Username, Hash, HashingAlgorithm, ConvertedTags).
create_user_with_password(_PassedCredentialValidation = true, Username, Password, Tags, undefined, ActingUser) ->
- rabbit_auth_backend_internal:add_user(Username, Password, ActingUser),
- rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser);
+ rabbit_auth_backend_internal:add_user(Username, Password, ActingUser, Tags);
create_user_with_password(_PassedCredentialValidation = true, Username, Password, Tags, PreconfiguredPermissions, ActingUser) ->
- rabbit_auth_backend_internal:add_user(Username, Password, ActingUser),
- rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser),
+ rabbit_auth_backend_internal:add_user(Username, Password, ActingUser, Tags),
preconfigure_permissions(Username, PreconfiguredPermissions, ActingUser);
create_user_with_password(_PassedCredentialValidation = false, _Username, _Password, _Tags, _, _) ->
%% we don't log here because
@@ -714,14 +796,7 @@ create_user_with_password_hash(Username, PasswordHash, Tags, User, Version, Prec
HashingAlgorithm = hashing_algorithm(User, Version),
Hash = rabbit_misc:b64decode_or_throw(PasswordHash),
- %% first we create a user with dummy credentials and no
- %% validation applied, then we update password hash
- TmpPassword = rabbit_guid:binary(rabbit_guid:gen_secure(), "tmp"),
- rabbit_auth_backend_internal:add_user_sans_validation(Username, TmpPassword, ActingUser),
-
- rabbit_auth_backend_internal:change_password_hash(
- Username, Hash, HashingAlgorithm),
- rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser),
+ rabbit_auth_backend_internal:add_user_sans_validation(Username, Hash, HashingAlgorithm, Tags, ActingUser),
preconfigure_permissions(Username, PreconfiguredPermissions, ActingUser).
preconfigure_permissions(_Username, undefined, _ActingUser) ->