summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/rabbitmqctl.1.xml33
-rw-r--r--ebin/rabbit_app.in2
-rw-r--r--include/rabbit.hrl4
-rw-r--r--include/rabbit_auth_backend_spec.hrl3
-rw-r--r--src/rabbit.erl7
-rw-r--r--src/rabbit_access_control.erl27
-rw-r--r--src/rabbit_auth_backend.erl8
-rw-r--r--src/rabbit_auth_backend_internal.erl44
-rw-r--r--src/rabbit_control.erl27
-rw-r--r--src/rabbit_tests.erl20
-rw-r--r--src/rabbit_types.erl4
-rw-r--r--src/rabbit_upgrade_functions.erl12
12 files changed, 80 insertions, 111 deletions
diff --git a/docs/rabbitmqctl.1.xml b/docs/rabbitmqctl.1.xml
index 06dcfff7..a0f03192 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 d06f167e..65a3269a 100644
--- a/ebin/rabbit_app.in
+++ b/ebin/rabbit_app.in
@@ -25,7 +25,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 67e2dfe5..b65f048d 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/include/rabbit_auth_backend_spec.hrl b/include/rabbit_auth_backend_spec.hrl
index e26d44ea..803bb75c 100644
--- a/include/rabbit_auth_backend_spec.hrl
+++ b/include/rabbit_auth_backend_spec.hrl
@@ -22,8 +22,7 @@
{'ok', rabbit_types:user()} |
{'refused', string(), [any()]} |
{'error', any()}).
--spec(check_vhost_access/3 :: (rabbit_types:user(), rabbit_types:vhost(),
- rabbit_access_control:vhost_permission_atom()) ->
+-spec(check_vhost_access/2 :: (rabbit_types:user(), rabbit_types:vhost()) ->
boolean() | {'error', any()}).
-spec(check_resource_access/3 :: (rabbit_types:user(),
rabbit_types:r(atom()),
diff --git a/src/rabbit.erl b/src/rabbit.erl
index 8866a1b7..100cacb0 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_access_control.erl b/src/rabbit_access_control.erl
index 59c00848..c0ae18c0 100644
--- a/src/rabbit_access_control.erl
+++ b/src/rabbit_access_control.erl
@@ -19,16 +19,15 @@
-include("rabbit.hrl").
-export([check_user_pass_login/2, check_user_login/2,
- check_vhost_access/2, check_resource_access/3, list_vhosts/2]).
+ check_vhost_access/2, check_resource_access/3]).
%%----------------------------------------------------------------------------
-ifdef(use_specs).
--export_type([permission_atom/0, vhost_permission_atom/0]).
+-export_type([permission_atom/0]).
-type(permission_atom() :: 'configure' | 'read' | 'write').
--type(vhost_permission_atom() :: 'read' | 'write').
-spec(check_user_pass_login/2 ::
(rabbit_types:username(), rabbit_types:password())
@@ -39,8 +38,6 @@
-spec(check_resource_access/3 ::
(rabbit_types:user(), rabbit_types:r(atom()), permission_atom())
-> 'ok' | rabbit_types:channel_exit()).
--spec(list_vhosts/2 :: (rabbit_types:user(), vhost_permission_atom())
- -> [rabbit_types:vhost()]).
-endif.
@@ -70,7 +67,7 @@ check_vhost_access(User = #user{ username = Username,
check_access(
fun() ->
rabbit_vhost:exists(VHostPath) andalso
- Module:check_vhost_access(User, VHostPath, write)
+ Module:check_vhost_access(User, VHostPath)
end,
"~s failed checking vhost access to ~s for ~s: ~p~n",
[Module, VHostPath, Username],
@@ -104,21 +101,3 @@ check_access(Fun, ErrStr, ErrArgs, RefStr, RefArgs) ->
false ->
rabbit_misc:protocol_error(access_refused, RefStr, RefArgs)
end.
-
-%% Permission = write -> log in
-%% Permission = read -> learn of the existence of (only relevant for
-%% management plugin)
-list_vhosts(User = #user{username = Username, auth_backend = Module},
- Permission) ->
- lists:filter(
- fun(VHost) ->
- case Module:check_vhost_access(User, VHost, Permission) of
- {error, _} = E ->
- rabbit_log:warning("~w failed checking vhost access "
- "to ~s for ~s: ~p~n",
- [Module, VHost, Username, E]),
- false;
- Else ->
- Else
- end
- end, rabbit_vhost:list()).
diff --git a/src/rabbit_auth_backend.erl b/src/rabbit_auth_backend.erl
index 09820c5b..ade158bb 100644
--- a/src/rabbit_auth_backend.erl
+++ b/src/rabbit_auth_backend.erl
@@ -36,17 +36,13 @@ behaviour_info(callbacks) ->
%% Client failed authentication. Log and die.
{check_user_login, 2},
- %% Given #user, vhost path and permission, can a user access a vhost?
- %% Permission is read - learn of the existence of (only relevant for
- %% management plugin)
- %% or write - log in
- %%
+ %% Given #user and vhost, can a user log in to a vhost?
%% Possible responses:
%% true
%% false
%% {error, Error}
%% Something went wrong. Log and die.
- {check_vhost_access, 3},
+ {check_vhost_access, 2},
%% Given #user, resource and permission, can a user access a resource?
%%
diff --git a/src/rabbit_auth_backend_internal.erl b/src/rabbit_auth_backend_internal.erl
index 2a42ff88..6a018bd1 100644
--- a/src/rabbit_auth_backend_internal.erl
+++ b/src/rabbit_auth_backend_internal.erl
@@ -20,10 +20,10 @@
-behaviour(rabbit_auth_backend).
-export([description/0]).
--export([check_user_login/2, check_vhost_access/3, check_resource_access/3]).
+-export([check_user_login/2, check_vhost_access/2, 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,16 +110,13 @@ 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, _) ->
+check_vhost_access(#user{username = Username}, VHost) ->
%% 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
+ virtual_host = VHost}}) of
[] -> false;
[_R] -> true
end
@@ -161,7 +159,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 +220,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 +238,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 355ac549..9eef384a 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 3f4aa54e..f5492cdc 100644
--- a/src/rabbit_tests.erl
+++ b/src/rabbit_tests.erl
@@ -1072,15 +1072,25 @@ test_user_management() ->
control_action(list_permissions, [], [{"-p", "/testhost"}]),
{error, {invalid_regexp, _, _}} =
control_action(set_permissions, ["guest", "+foo", ".*", ".*"]),
+ {error, {no_such_user, _}} =
+ control_action(set_user_tags, ["foo", "bar"]),
%% user creation
ok = control_action(add_user, ["foo", "bar"]),
{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(list_users, []),
+
+ TestTags = fun (Tags) ->
+ Args = ["foo" | [atom_to_list(T) || T <- Tags]],
+ ok = control_action(set_user_tags, Args),
+ {ok, #internal_user{tags = Tags}} =
+ rabbit_auth_backend_internal:lookup_user(<<"foo">>),
+ ok = control_action(list_users, [])
+ end,
+ TestTags([foo, bar, baz]),
+ TestTags([administrator]),
+ TestTags([]),
%% vhost creation
ok = control_action(add_vhost, ["/testhost"]),
@@ -1203,10 +1213,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 1f0f8bbe..a18118e3 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 5e4a1224..c2dd860a 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, [management]}
+ end,
+ [username, password_hash, tags], internal_user).
+
%%--------------------------------------------------------------------
transform(TableName, Fun, FieldList) ->