summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon MacMullen <simon@rabbitmq.com>2014-02-24 14:46:43 +0000
committerSimon MacMullen <simon@rabbitmq.com>2014-02-24 14:46:43 +0000
commitc1ccbf1e0ac7d3014b04a75a5d7954ef2d3554e2 (patch)
treec20b458920440ac8f270f03ba847ea4ecf2865b2
parentd053e071af734877847e81445e1b34b36b95cd51 (diff)
parent7ac4a1820b7564459e182ae90b2b74229dad4296 (diff)
downloadrabbitmq-server-bug25603.tar.gz
Merge in defaultbug25603
-rw-r--r--ebin/rabbit_app.in1
-rw-r--r--src/rabbit_access_control.erl13
-rw-r--r--src/rabbit_net.erl17
-rw-r--r--src/rabbit_reader.erl47
4 files changed, 57 insertions, 21 deletions
diff --git a/ebin/rabbit_app.in b/ebin/rabbit_app.in
index 29f06e79..7360208a 100644
--- a/ebin/rabbit_app.in
+++ b/ebin/rabbit_app.in
@@ -34,6 +34,7 @@
{default_user_tags, [administrator]},
{default_vhost, <<"/">>},
{default_permissions, [<<".*">>, <<".*">>, <<".*">>]},
+ {loopback_users, [<<"guest">>]},
{cluster_nodes, {[], disc}},
{server_properties, []},
{collect_statistics, none},
diff --git a/src/rabbit_access_control.erl b/src/rabbit_access_control.erl
index 19171659..4bb1aed1 100644
--- a/src/rabbit_access_control.erl
+++ b/src/rabbit_access_control.erl
@@ -18,7 +18,7 @@
-include("rabbit.hrl").
--export([check_user_pass_login/2, check_user_login/2,
+-export([check_user_pass_login/2, check_user_login/2, check_user_loopback/2,
check_vhost_access/2, check_resource_access/3]).
%%----------------------------------------------------------------------------
@@ -35,6 +35,9 @@
-spec(check_user_login/2 ::
(rabbit_types:username(), [{atom(), any()}])
-> {'ok', rabbit_types:user()} | {'refused', string(), [any()]}).
+-spec(check_user_loopback/2 :: (rabbit_types:username(),
+ rabbit_net:socket() | inet:ip_address())
+ -> 'ok' | 'not_allowed').
-spec(check_vhost_access/2 ::
(rabbit_types:user(), rabbit_types:vhost())
-> 'ok' | rabbit_types:channel_exit()).
@@ -77,6 +80,14 @@ try_login(Module, Username, AuthProps) ->
Else -> Else
end.
+check_user_loopback(Username, SockOrAddr) ->
+ {ok, Users} = application:get_env(rabbit, loopback_users),
+ case rabbit_net:is_loopback(SockOrAddr)
+ orelse not lists:member(Username, Users) of
+ true -> ok;
+ false -> not_allowed
+ end.
+
check_vhost_access(User = #user{ username = Username,
auth_backend = Module }, VHostPath) ->
check_access(
diff --git a/src/rabbit_net.erl b/src/rabbit_net.erl
index 401b8ab1..658474e4 100644
--- a/src/rabbit_net.erl
+++ b/src/rabbit_net.erl
@@ -20,7 +20,7 @@
-export([is_ssl/1, ssl_info/1, controlling_process/2, getstat/2,
recv/1, sync_recv/2, async_recv/3, port_command/2, getopts/2,
setopts/2, send/2, close/1, fast_close/1, sockname/1, peername/1,
- peercert/1, connection_string/2, socket_ends/2]).
+ peercert/1, connection_string/2, socket_ends/2, is_loopback/1]).
%%---------------------------------------------------------------------------
@@ -77,6 +77,7 @@
(socket(), 'inbound' | 'outbound')
-> ok_val_or_error({host_or_ip(), rabbit_networking:ip_port(),
host_or_ip(), rabbit_networking:ip_port()})).
+-spec(is_loopback/1 :: (socket() | inet:ip_address()) -> boolean()).
-endif.
@@ -229,3 +230,17 @@ rdns(Addr) ->
sock_funs(inbound) -> {fun peername/1, fun sockname/1};
sock_funs(outbound) -> {fun sockname/1, fun peername/1}.
+
+is_loopback(Sock) when is_port(Sock) ; ?IS_SSL(Sock) ->
+ case sockname(Sock) of
+ {ok, {Addr, _Port}} -> is_loopback(Addr);
+ {error, _} -> false
+ end;
+%% We could parse the results of inet:getifaddrs() instead. But that
+%% would be more complex and less maybe Windows-compatible...
+is_loopback({127,_,_,_}) -> true;
+is_loopback({0,0,0,0,0,0,0,1}) -> true;
+is_loopback({0,0,0,0,0,65535,AB,CD}) -> is_loopback(ipv4(AB, CD));
+is_loopback(_) -> false.
+
+ipv4(AB, CD) -> {AB bsr 8, AB band 255, CD bsr 8, CD band 255}.
diff --git a/src/rabbit_reader.erl b/src/rabbit_reader.erl
index 3304a50b..4a194829 100644
--- a/src/rabbit_reader.erl
+++ b/src/rabbit_reader.erl
@@ -1023,29 +1023,12 @@ auth_mechanisms_binary(Sock) ->
auth_phase(Response,
State = #v1{connection = Connection =
#connection{protocol = Protocol,
- capabilities = Capabilities,
auth_mechanism = {Name, AuthMechanism},
auth_state = AuthState},
sock = Sock}) ->
case AuthMechanism:handle_response(Response, AuthState) of
{refused, Msg, Args} ->
- AmqpError = rabbit_misc:amqp_error(
- access_refused, "~s login refused: ~s",
- [Name, io_lib:format(Msg, Args)], none),
- case rabbit_misc:table_lookup(Capabilities,
- <<"authentication_failure_close">>) of
- {bool, true} ->
- SafeMsg = io_lib:format(
- "Login was refused using authentication "
- "mechanism ~s. For details see the broker "
- "logfile.", [Name]),
- AmqpError1 = AmqpError#amqp_error{explanation = SafeMsg},
- {0, CloseMethod} = rabbit_binary_generator:map_exception(
- 0, AmqpError1, Protocol),
- ok = send_on_channel0(State#v1.sock, CloseMethod, Protocol);
- _ -> ok
- end,
- rabbit_misc:protocol_error(AmqpError);
+ auth_fail(Msg, Args, Name, State);
{protocol_error, Msg, Args} ->
rabbit_misc:protocol_error(syntax_error, Msg, Args);
{challenge, Challenge, AuthState1} ->
@@ -1053,7 +1036,12 @@ auth_phase(Response,
ok = send_on_channel0(Sock, Secure, Protocol),
State#v1{connection = Connection#connection{
auth_state = AuthState1}};
- {ok, User} ->
+ {ok, User = #user{username = Username}} ->
+ case rabbit_access_control:check_user_loopback(Username, Sock) of
+ ok -> ok;
+ not_allowed -> auth_fail("user '~s' can only connect via "
+ "localhost", [Username], Name, State)
+ end,
Tune = #'connection.tune'{frame_max = get_env(frame_max),
channel_max = get_env(channel_max),
heartbeat = get_env(heartbeat)},
@@ -1063,6 +1051,27 @@ auth_phase(Response,
auth_state = none}}
end.
+auth_fail(Msg, Args, AuthName,
+ State = #v1{connection = #connection{protocol = Protocol,
+ capabilities = Capabilities}}) ->
+ AmqpError = rabbit_misc:amqp_error(
+ access_refused, "~s login refused: ~s",
+ [AuthName, io_lib:format(Msg, Args)], none),
+ case rabbit_misc:table_lookup(Capabilities,
+ <<"authentication_failure_close">>) of
+ {bool, true} ->
+ SafeMsg = io_lib:format(
+ "Login was refused using authentication "
+ "mechanism ~s. For details see the broker "
+ "logfile.", [AuthName]),
+ AmqpError1 = AmqpError#amqp_error{explanation = SafeMsg},
+ {0, CloseMethod} = rabbit_binary_generator:map_exception(
+ 0, AmqpError1, Protocol),
+ ok = send_on_channel0(State#v1.sock, CloseMethod, Protocol);
+ _ -> ok
+ end,
+ rabbit_misc:protocol_error(AmqpError).
+
%%--------------------------------------------------------------------------
infos(Items, State) -> [{Item, i(Item, State)} || Item <- Items].