diff options
| author | Alexandru Scvortov <alexandru@rabbitmq.com> | 2010-10-11 17:31:18 +0100 |
|---|---|---|
| committer | Alexandru Scvortov <alexandru@rabbitmq.com> | 2010-10-11 17:31:18 +0100 |
| commit | d833af71241f8e9fe0d831f6290a179f6ec8862a (patch) | |
| tree | 5f48b1e48dc009b6d220ae3feeb6a04642af1f5b | |
| parent | b7c33555ccd990a3f95b8cfe096449863d225c95 (diff) | |
| download | rabbitmq-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.erl | 6 | ||||
| -rw-r--r-- | src/rabbit_channel.erl | 52 |
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, |
