summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandru Scvortov <alexandru@rabbitmq.com>2010-10-11 17:31:18 +0100
committerAlexandru Scvortov <alexandru@rabbitmq.com>2010-10-11 17:31:18 +0100
commitd833af71241f8e9fe0d831f6290a179f6ec8862a (patch)
tree5f48b1e48dc009b6d220ae3feeb6a04642af1f5b
parentb7c33555ccd990a3f95b8cfe096449863d225c95 (diff)
downloadrabbitmq-server-git-d833af71241f8e9fe0d831f6290a179f6ec8862a.tar.gz
allow exchange.declare on the default exchange
The only operations permitted for the default exchange are exchange.declare and basic.publish. Both can be restricted via permissions.
-rw-r--r--src/rabbit_access_control.erl6
-rw-r--r--src/rabbit_channel.erl52
2 files changed, 35 insertions, 23 deletions
diff --git a/src/rabbit_access_control.erl b/src/rabbit_access_control.erl
index a2cc6759d9..73fd6f0e51 100644
--- a/src/rabbit_access_control.erl
+++ b/src/rabbit_access_control.erl
@@ -180,12 +180,6 @@ check_resource_access(Username,
R#resource{name = <<"amq.default">>},
Permission);
check_resource_access(Username,
- R = #resource{kind = exchange, name = <<"amq.default">>},
- Permission)
- when Permission =/= write ->
- rabbit_misc:protocol_error(access_refused,
- "default exchange is publish-only", []);
-check_resource_access(Username,
R = #resource{virtual_host = VHostPath, name = Name},
Permission) ->
Res = case mnesia:dirty_read({rabbit_user_permission,
diff --git a/src/rabbit_channel.erl b/src/rabbit_channel.erl
index fe36cef923..e8f19f3709 100644
--- a/src/rabbit_channel.erl
+++ b/src/rabbit_channel.erl
@@ -340,13 +340,24 @@ clear_permission_cache() ->
erase(permission_cache),
ok.
-check_configure_permitted(Resource, #ch{username = Username}) ->
+check_configure_permitted(Resource, Action, #ch{username = Username}) ->
+ DE = is_default_exchange(Resource),
+ if DE andalso Action =/= 'exchange.declare' ->
+ rabbit_misc:protocol_error(
+ access_refused, "cannot ~p the default exchange", [Action]);
+ true -> ok
+ end,
check_resource_access(Username, Resource, configure).
-check_write_permitted(Resource, #ch{username = Username}) ->
+check_write_permitted(Resource, _Action, #ch{username = Username}) ->
check_resource_access(Username, Resource, write).
-check_read_permitted(Resource, #ch{username = Username}) ->
+check_read_permitted(Resource, Action, #ch{username = Username}) ->
+ case is_default_exchange(Resource) of
+ true -> rabbit_misc:protocol_error(
+ access_refused, "cannot ~p the default exchange", [Action]);
+ false -> ok
+ end,
check_resource_access(Username, Resource, read).
expand_queue_name_shortcut(<<>>, #ch{most_recently_declared_queue = <<>>}) ->
@@ -368,6 +379,11 @@ expand_routing_key_shortcut(<<>>, <<>>,
expand_routing_key_shortcut(_QueueNameBin, RoutingKey, _State) ->
RoutingKey.
+is_default_exchange(#resource{kind = exchange, name = N}) ->
+ N =:= <<"">> orelse N =:= <<"amq.default">>;
+is_default_exchange(_) ->
+ false.
+
%% check that an exchange/queue name does not contain the reserved
%% "amq." prefix.
%%
@@ -428,7 +444,7 @@ handle_method(#'basic.publish'{exchange = ExchangeNameBin,
transaction_id = TxnKey,
writer_pid = WriterPid}) ->
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
- check_write_permitted(ExchangeName, State),
+ check_write_permitted(ExchangeName, 'basic.publish', State),
Exchange = rabbit_exchange:lookup_or_die(ExchangeName),
%% We decode the content's properties here because we're almost
%% certain to want to look at delivery-mode and priority.
@@ -481,7 +497,7 @@ handle_method(#'basic.get'{queue = QueueNameBin,
reader_pid = ReaderPid,
next_tag = DeliveryTag}) ->
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
- check_read_permitted(QueueName, State),
+ check_read_permitted(QueueName, 'basic.get', State),
case rabbit_amqqueue:with_exclusive_access_or_die(
QueueName, ReaderPid,
fun (Q) -> rabbit_amqqueue:basic_get(Q, self(), NoAck) end) of
@@ -521,7 +537,7 @@ handle_method(#'basic.consume'{queue = QueueNameBin,
case dict:find(ConsumerTag, ConsumerMapping) of
error ->
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
- check_read_permitted(QueueName, State),
+ check_read_permitted(QueueName, 'basic.consume', State),
ActualConsumerTag =
case ConsumerTag of
<<>> -> rabbit_guid:binstring_guid("amq.ctag");
@@ -681,7 +697,7 @@ handle_method(#'exchange.declare'{exchange = ExchangeNameBin,
_, State = #ch{virtual_host = VHostPath}) ->
CheckedType = rabbit_exchange:check_type(TypeNameBin),
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
- check_configure_permitted(ExchangeName, State),
+ check_configure_permitted(ExchangeName, 'exchange.declare', State),
X = case rabbit_exchange:lookup(ExchangeName) of
{ok, FoundX} -> FoundX;
{error, not_found} ->
@@ -689,8 +705,10 @@ handle_method(#'exchange.declare'{exchange = ExchangeNameBin,
case rabbit_misc:r_arg(VHostPath, exchange, Args,
<<"alternate-exchange">>) of
undefined -> ok;
- AName -> check_read_permitted(ExchangeName, State),
- check_write_permitted(AName, State),
+ AName -> check_read_permitted(ExchangeName,
+ 'exchange.declare', State),
+ check_write_permitted(AName,
+ 'exchange.declare', State),
ok
end,
rabbit_exchange:declare(ExchangeName,
@@ -708,7 +726,7 @@ handle_method(#'exchange.declare'{exchange = ExchangeNameBin,
nowait = NoWait},
_, State = #ch{virtual_host = VHostPath}) ->
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
- check_configure_permitted(ExchangeName, State),
+ check_configure_permitted(ExchangeName, 'exchange.declare', State),
_ = rabbit_exchange:lookup_or_die(ExchangeName),
return_ok(State, NoWait, #'exchange.declare_ok'{});
@@ -717,7 +735,7 @@ handle_method(#'exchange.delete'{exchange = ExchangeNameBin,
nowait = NoWait},
_, State = #ch{virtual_host = VHostPath}) ->
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
- check_configure_permitted(ExchangeName, State),
+ check_configure_permitted(ExchangeName, 'exchange.delete', State),
case rabbit_exchange:delete(ExchangeName, IfUnused) of
{error, not_found} ->
rabbit_misc:not_found(ExchangeName);
@@ -747,7 +765,7 @@ handle_method(#'queue.declare'{queue = QueueNameBin,
Other -> check_name('queue', Other)
end,
QueueName = rabbit_misc:r(VHostPath, queue, ActualNameBin),
- check_configure_permitted(QueueName, State),
+ check_configure_permitted(QueueName, 'queue.declare', State),
case rabbit_amqqueue:with(
QueueName,
fun (Q) -> ok = rabbit_amqqueue:assert_equivalence(
@@ -784,7 +802,7 @@ handle_method(#'queue.declare'{queue = QueueNameBin,
_, State = #ch{virtual_host = VHostPath,
reader_pid = ReaderPid}) ->
QueueName = rabbit_misc:r(VHostPath, queue, QueueNameBin),
- check_configure_permitted(QueueName, State),
+ check_configure_permitted(QueueName, 'queue.declare', State),
{{ok, MessageCount, ConsumerCount}, #amqqueue{} = Q} =
rabbit_amqqueue:with_or_die(
QueueName, fun (Q) -> {rabbit_amqqueue:stat(Q), Q} end),
@@ -798,7 +816,7 @@ handle_method(#'queue.delete'{queue = QueueNameBin,
nowait = NoWait},
_, State = #ch{reader_pid = ReaderPid}) ->
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
- check_configure_permitted(QueueName, State),
+ check_configure_permitted(QueueName, 'queue.delete', State),
case rabbit_amqqueue:with_exclusive_access_or_die(
QueueName, ReaderPid,
fun (Q) -> rabbit_amqqueue:delete(Q, IfUnused, IfEmpty) end) of
@@ -834,7 +852,7 @@ handle_method(#'queue.purge'{queue = QueueNameBin,
nowait = NoWait},
_, State = #ch{reader_pid = ReaderPid}) ->
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
- check_read_permitted(QueueName, State),
+ check_read_permitted(QueueName, 'queue.purge', State),
{ok, PurgedMessageCount} = rabbit_amqqueue:with_exclusive_access_or_die(
QueueName, ReaderPid,
fun (Q) -> rabbit_amqqueue:purge(Q) end),
@@ -902,11 +920,11 @@ binding_action(Fun, ExchangeNameBin, QueueNameBin, RoutingKey, Arguments,
%% FIXME: don't allow binding to internal exchanges -
%% including the one named "" !
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
- check_write_permitted(QueueName, State),
+ check_write_permitted(QueueName, 'queue.bind', State),
ActualRoutingKey = expand_routing_key_shortcut(QueueNameBin, RoutingKey,
State),
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
- check_read_permitted(ExchangeName, State),
+ check_read_permitted(ExchangeName, 'queue.bind', State),
case Fun(#binding{exchange_name = ExchangeName,
queue_name = QueueName,
key = ActualRoutingKey,