diff options
| author | Simon MacMullen <simon@rabbitmq.com> | 2011-06-09 14:15:17 +0100 |
|---|---|---|
| committer | Simon MacMullen <simon@rabbitmq.com> | 2011-06-09 14:15:17 +0100 |
| commit | 802846a4b4a64a3baebddb2322784c2b7a893591 (patch) | |
| tree | b08e7ea63ddf150654052e5d83a0cac083e01300 | |
| parent | 438e76e8f8113b77dce286b4cab03c8736c4f44d (diff) | |
| download | rabbitmq-server-git-802846a4b4a64a3baebddb2322784c2b7a893591.tar.gz | |
First pass at user tags.
| -rw-r--r-- | docs/rabbitmqctl.1.xml | 33 | ||||
| -rw-r--r-- | ebin/rabbit_app.in | 2 | ||||
| -rw-r--r-- | include/rabbit.hrl | 4 | ||||
| -rw-r--r-- | src/rabbit.erl | 7 | ||||
| -rw-r--r-- | src/rabbit_auth_backend_internal.erl | 66 | ||||
| -rw-r--r-- | src/rabbit_control.erl | 27 | ||||
| -rw-r--r-- | src/rabbit_tests.erl | 8 | ||||
| -rw-r--r-- | src/rabbit_types.erl | 4 | ||||
| -rw-r--r-- | src/rabbit_upgrade_functions.erl | 12 |
9 files changed, 77 insertions, 86 deletions
diff --git a/docs/rabbitmqctl.1.xml b/docs/rabbitmqctl.1.xml index 06dcfff76f..a0f031927f 100644 --- a/docs/rabbitmqctl.1.xml +++ b/docs/rabbitmqctl.1.xml @@ -513,17 +513,22 @@ </varlistentry> <varlistentry> - <term><cmdsynopsis><command>set_admin</command> <arg choice="req"><replaceable>username</replaceable></arg></cmdsynopsis></term> + <term><cmdsynopsis><command>set_user_tags</command> <arg choice="req"><replaceable>username</replaceable></arg> <arg choice="req"><replaceable>tag</replaceable> ...</arg></cmdsynopsis></term> <listitem> <variablelist> <varlistentry> <term>username</term> - <listitem><para>The name of the user whose administrative - status is to be set.</para></listitem> + <listitem><para>The name of the user whose tags are to + be set.</para></listitem> + </varlistentry> + <varlistentry> + <term>tag</term> + <listitem><para>Zero, one or more tags to set. Any + existing tags will be removed.</para></listitem> </varlistentry> </variablelist> <para role="example-prefix">For example:</para> - <screen role="example">rabbitmqctl set_admin tonyg</screen> + <screen role="example">rabbitmqctl set_user_tags tonyg administrator</screen> <para role="example"> This command instructs the RabbitMQ broker to ensure the user named <command>tonyg</command> is an administrator. This has no @@ -532,24 +537,10 @@ user logs in via some other means (for example with the management plugin). </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><cmdsynopsis><command>clear_admin</command> <arg choice="req"><replaceable>username</replaceable></arg></cmdsynopsis></term> - <listitem> - <variablelist> - <varlistentry> - <term>username</term> - <listitem><para>The name of the user whose administrative - status is to be cleared.</para></listitem> - </varlistentry> - </variablelist> - <para role="example-prefix">For example:</para> - <screen role="example">rabbitmqctl clear_admin tonyg</screen> + <screen role="example">rabbitmqctl set_user_tags tonyg</screen> <para role="example"> - This command instructs the RabbitMQ broker to ensure the user - named <command>tonyg</command> is not an administrator. + This command instructs the RabbitMQ broker to remove any + tags from the user named <command>tonyg</command>. </para> </listitem> </varlistentry> diff --git a/ebin/rabbit_app.in b/ebin/rabbit_app.in index 7dabb8c346..6d939c59b0 100644 --- a/ebin/rabbit_app.in +++ b/ebin/rabbit_app.in @@ -27,7 +27,7 @@ {queue_index_max_journal_entries, 262144}, {default_user, <<"guest">>}, {default_pass, <<"guest">>}, - {default_user_is_admin, true}, + {default_user_tags, [administrator]}, {default_vhost, <<"/">>}, {default_permissions, [<<".*">>, <<".*">>, <<".*">>]}, {cluster_nodes, []}, diff --git a/include/rabbit.hrl b/include/rabbit.hrl index db4773b8ec..ee6e67b62b 100644 --- a/include/rabbit.hrl +++ b/include/rabbit.hrl @@ -15,12 +15,12 @@ %% -record(user, {username, - is_admin, + tags, auth_backend, %% Module this user came from impl %% Scratch space for that module }). --record(internal_user, {username, password_hash, is_admin}). +-record(internal_user, {username, password_hash, tags}). -record(permission, {configure, write, read}). -record(user_vhost, {username, virtual_host}). -record(user_permission, {user_vhost, permission}). diff --git a/src/rabbit.erl b/src/rabbit.erl index 8866a1b738..100cacb0e8 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -486,16 +486,13 @@ maybe_insert_default_data() -> insert_default_data() -> {ok, DefaultUser} = application:get_env(default_user), {ok, DefaultPass} = application:get_env(default_pass), - {ok, DefaultAdmin} = application:get_env(default_user_is_admin), + {ok, DefaultTags} = application:get_env(default_user_tags), {ok, DefaultVHost} = application:get_env(default_vhost), {ok, [DefaultConfigurePerm, DefaultWritePerm, DefaultReadPerm]} = application:get_env(default_permissions), ok = rabbit_vhost:add(DefaultVHost), ok = rabbit_auth_backend_internal:add_user(DefaultUser, DefaultPass), - case DefaultAdmin of - true -> rabbit_auth_backend_internal:set_admin(DefaultUser); - _ -> ok - end, + ok = rabbit_auth_backend_internal:set_tags(DefaultUser, DefaultTags), ok = rabbit_auth_backend_internal:set_permissions(DefaultUser, DefaultVHost, DefaultConfigurePerm, DefaultWritePerm, diff --git a/src/rabbit_auth_backend_internal.erl b/src/rabbit_auth_backend_internal.erl index 2a42ff8887..96ada60381 100644 --- a/src/rabbit_auth_backend_internal.erl +++ b/src/rabbit_auth_backend_internal.erl @@ -22,8 +22,8 @@ -export([description/0]). -export([check_user_login/2, check_vhost_access/3, check_resource_access/3]). --export([add_user/2, delete_user/1, change_password/2, set_admin/1, - clear_admin/1, list_users/0, lookup_user/1, clear_password/1]). +-export([add_user/2, delete_user/1, change_password/2, set_tags/2, + list_users/0, user_info_keys/0, lookup_user/1, clear_password/1]). -export([make_salt/0, check_password/2, change_password_hash/2, hash_password/1]). -export([set_permissions/5, clear_permissions/2, @@ -50,9 +50,9 @@ rabbit_types:password_hash()) -> 'ok'). -spec(hash_password/1 :: (rabbit_types:password()) -> rabbit_types:password_hash()). --spec(set_admin/1 :: (rabbit_types:username()) -> 'ok'). --spec(clear_admin/1 :: (rabbit_types:username()) -> 'ok'). --spec(list_users/0 :: () -> [{rabbit_types:username(), boolean()}]). +-spec(set_tags/2 :: (rabbit_types:username(), [atom()]) -> 'ok'). +-spec(list_users/0 :: () -> rabbit_types:infos()). +-spec(user_info_keys/0 :: () -> rabbit_types:info_keys()). -spec(lookup_user/1 :: (rabbit_types:username()) -> rabbit_types:ok(rabbit_types:internal_user()) | rabbit_types:error('not_found')). @@ -77,6 +77,7 @@ %%---------------------------------------------------------------------------- -define(PERMS_INFO_KEYS, [configure, write, read]). +-define(USER_INFO_KEYS, [user, tags]). %% Implementation of rabbit_auth_backend @@ -97,10 +98,10 @@ check_user_login(Username, AuthProps) -> internal_check_user_login(Username, Fun) -> Refused = {refused, "user '~s' - invalid credentials", [Username]}, case lookup_user(Username) of - {ok, User = #internal_user{is_admin = IsAdmin}} -> + {ok, User = #internal_user{tags = Tags}} -> case Fun(User) of true -> {ok, #user{username = Username, - is_admin = IsAdmin, + tags = Tags, auth_backend = ?MODULE, impl = User}}; _ -> Refused @@ -109,20 +110,23 @@ internal_check_user_login(Username, Fun) -> Refused end. -check_vhost_access(#user{is_admin = true}, _VHostPath, read) -> - true; - -check_vhost_access(#user{username = Username}, VHostPath, _) -> - %% TODO: use dirty ops instead - rabbit_misc:execute_mnesia_transaction( - fun () -> - case mnesia:read({rabbit_user_permission, - #user_vhost{username = Username, - virtual_host = VHostPath}}) of - [] -> false; - [_R] -> true - end - end). +check_vhost_access(#user{username = Username, tags = Tags}, VHost, Mode) -> + Admin = lists:any(fun(T) -> lists:member(T, [administrator]) end, Tags), + case {Admin, Mode} of + {true, read} -> + true; + _ -> + %% TODO: use dirty ops instead + rabbit_misc:execute_mnesia_transaction( + fun () -> + case mnesia:read({rabbit_user_permission, + #user_vhost{username = Username, + virtual_host = VHost}}) of + [] -> false; + [_R] -> true + end + end) + end. check_resource_access(#user{username = Username}, #resource{virtual_host = VHostPath, name = Name}, @@ -161,7 +165,7 @@ add_user(Username, Password) -> #internal_user{username = Username, password_hash = hash_password(Password), - is_admin = false}, + tags = []}, write); _ -> mnesia:abort({user_already_exists, Username}) @@ -222,16 +226,12 @@ salted_md5(Salt, Cleartext) -> Salted = <<Salt/binary, Cleartext/binary>>, erlang:md5(Salted). -set_admin(Username) -> set_admin(Username, true). - -clear_admin(Username) -> set_admin(Username, false). - -set_admin(Username, IsAdmin) -> +set_tags(Username, Tags) -> R = update_user(Username, fun(User) -> - User#internal_user{is_admin = IsAdmin} + User#internal_user{tags = Tags} end), - rabbit_log:info("Set user admin flag for user ~p to ~p~n", - [Username, IsAdmin]), + rabbit_log:info("Set user tags for user ~p to ~p~n", + [Username, Tags]), R. update_user(Username, Fun) -> @@ -244,10 +244,12 @@ update_user(Username, Fun) -> end)). list_users() -> - [{Username, IsAdmin} || - #internal_user{username = Username, is_admin = IsAdmin} <- + [[{user, Username}, {tags, Tags}] || + #internal_user{username = Username, tags = Tags} <- mnesia:dirty_match_object(rabbit_user, #internal_user{_ = '_'})]. +user_info_keys() -> ?USER_INFO_KEYS. + lookup_user(Username) -> rabbit_misc:dirty_read({rabbit_user, Username}). diff --git a/src/rabbit_control.erl b/src/rabbit_control.erl index 355ac549ed..9eef384a24 100644 --- a/src/rabbit_control.erl +++ b/src/rabbit_control.erl @@ -235,17 +235,17 @@ action(clear_password, Node, Args = [Username], _Opts, Inform) -> Inform("Clearing password for user ~p", [Username]), call(Node, {rabbit_auth_backend_internal, clear_password, Args}); -action(set_admin, Node, [Username], _Opts, Inform) -> - Inform("Setting administrative status for user ~p", [Username]), - call(Node, {rabbit_auth_backend_internal, set_admin, [Username]}); - -action(clear_admin, Node, [Username], _Opts, Inform) -> - Inform("Clearing administrative status for user ~p", [Username]), - call(Node, {rabbit_auth_backend_internal, clear_admin, [Username]}); +action(set_user_tags, Node, [Username | TagsStr], _Opts, Inform) -> + Tags = [list_to_atom(T) || T <- TagsStr], + Inform("Setting tags for user ~p to ~p", [Username, Tags]), + rpc_call(Node, rabbit_auth_backend_internal, set_tags, + [list_to_binary(Username), Tags]); action(list_users, Node, [], _Opts, Inform) -> Inform("Listing users", []), - display_list(call(Node, {rabbit_auth_backend_internal, list_users, []})); + display_info_list( + call(Node, {rabbit_auth_backend_internal, list_users, []}), + rabbit_auth_backend_internal:user_info_keys()); action(add_vhost, Node, Args = [_VHostPath], _Opts, Inform) -> Inform("Creating vhost ~p", Args), @@ -422,17 +422,6 @@ format_info_item([T | _] = Value) format_info_item(Value) -> io_lib:format("~w", [Value]). -display_list(L) when is_list(L) -> - lists:foreach(fun (I) when is_binary(I) -> - io:format("~s~n", [escape(I)]); - (I) when is_tuple(I) -> - display_row([escape(V) - || V <- tuple_to_list(I)]) - end, - lists:sort(L)), - ok; -display_list(Other) -> Other. - display_call_result(Node, MFA) -> case call(Node, MFA) of {badrpc, _} = Res -> throw(Res); diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl index 3f4aa54e7f..b71d17d05b 100644 --- a/src/rabbit_tests.erl +++ b/src/rabbit_tests.erl @@ -1078,8 +1078,8 @@ test_user_management() -> {error, {user_already_exists, _}} = control_action(add_user, ["foo", "bar"]), ok = control_action(change_password, ["foo", "baz"]), - ok = control_action(set_admin, ["foo"]), - ok = control_action(clear_admin, ["foo"]), + ok = control_action(set_tags, ["foo", "administrator"]), + ok = control_action(set_tags, ["foo"]), ok = control_action(list_users, []), %% vhost creation @@ -1203,10 +1203,10 @@ test_spawn() -> user(Username) -> #user{username = Username, - is_admin = true, + tags = [administrator], auth_backend = rabbit_auth_backend_internal, impl = #internal_user{username = Username, - is_admin = true}}. + tags = [administrator]}}. test_statistics_event_receiver(Pid) -> receive diff --git a/src/rabbit_types.erl b/src/rabbit_types.erl index 1f0f8bbeac..a18118e32b 100644 --- a/src/rabbit_types.erl +++ b/src/rabbit_types.erl @@ -139,14 +139,14 @@ -type(user() :: #user{username :: username(), - is_admin :: boolean(), + tags :: [atom()], auth_backend :: atom(), impl :: any()}). -type(internal_user() :: #internal_user{username :: username(), password_hash :: password_hash(), - is_admin :: boolean()}). + tags :: [atom()]}). -type(username() :: binary()). -type(password() :: binary()). diff --git a/src/rabbit_upgrade_functions.erl b/src/rabbit_upgrade_functions.erl index 5e4a122439..18cdc83cfe 100644 --- a/src/rabbit_upgrade_functions.erl +++ b/src/rabbit_upgrade_functions.erl @@ -29,6 +29,7 @@ -rabbit_upgrade({semi_durable_route, mnesia, []}). -rabbit_upgrade({exchange_event_serial, mnesia, []}). -rabbit_upgrade({trace_exchanges, mnesia, []}). +-rabbit_upgrade({user_admin_to_tags, mnesia, [user_to_internal_user]}). %% ------------------------------------------------------------------- @@ -43,6 +44,7 @@ -spec(semi_durable_route/0 :: () -> 'ok'). -spec(exchange_event_serial/0 :: () -> 'ok'). -spec(trace_exchanges/0 :: () -> 'ok'). +-spec(user_admin_to_tags/0 :: () -> 'ok'). -endif. @@ -121,6 +123,16 @@ trace_exchanges() -> VHost <- rabbit_vhost:list()], ok. +user_admin_to_tags() -> + transform( + rabbit_user, + fun({internal_user, Username, PasswordHash, true}) -> + {internal_user, Username, PasswordHash, [administrator]}; + ({internal_user, Username, PasswordHash, false}) -> + {internal_user, Username, PasswordHash, []} + end, + [username, password_hash, tags], internal_user). + %%-------------------------------------------------------------------- transform(TableName, Fun, FieldList) -> |
