Skip to content
This repository was archived by the owner on Nov 17, 2020. It is now read-only.

Commit afb1430

Browse files
Merge pull request #217 from velimir/cache-topic-access
cache topic access (cherry picked from commit 1c9e9d7)
1 parent 7a7d6ea commit afb1430

File tree

2 files changed

+51
-24
lines changed

2 files changed

+51
-24
lines changed

src/rabbit_mqtt_processor.erl

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
-export([info/2, initial_state/2, initial_state/5,
2020
process_frame/2, amqp_pub/2, amqp_callback/2, send_will/1,
21-
close_connection/1]).
21+
close_connection/1, handle_pre_hibernate/0]).
2222

2323
%% for testing purposes
2424
-export([get_vhost_username/1, get_vhost/3, get_vhost_from_user_mapping/2,
@@ -31,6 +31,7 @@
3131
-define(APP, rabbitmq_mqtt).
3232
-define(FRAME_TYPE(Frame, Type),
3333
Frame = #mqtt_frame{ fixed = #mqtt_frame_fixed{ type = Type }}).
34+
-define(MAX_TOPIC_PERMISSION_CACHE_SIZE, 12).
3435

3536
initial_state(Socket, SSLLoginName) ->
3637
RealSocket = rabbit_net:unwrap_socket(Socket),
@@ -903,6 +904,10 @@ close_connection(PState = #proc_state{ connection = Connection,
903904
PState #proc_state{ channels = {undefined, undefined},
904905
connection = undefined }.
905906

907+
handle_pre_hibernate() ->
908+
erase(topic_permission_cache),
909+
ok.
910+
906911
%% NB: check_*: MQTT spec says we should ack normally, ie pretend there
907912
%% was no auth error, but here we are closing the connection with an error. This
908913
%% is what happens anyway if there is an authorization failure at the AMQP 0-9-1 client level.
@@ -929,28 +934,46 @@ check_topic_access(TopicName, Access,
929934
exchange = Exchange,
930935
client_id = ClientId,
931936
mqtt2amqp_fun = Mqtt2AmqpFun }) ->
932-
Resource = #resource{virtual_host = VHost,
933-
kind = topic,
934-
name = Exchange},
935-
RoutingKey = Mqtt2AmqpFun(TopicName),
936-
Context = #{routing_key => RoutingKey,
937-
variable_map => #{
938-
<<"username">> => Username,
939-
<<"vhost">> => VHost,
940-
<<"client_id">> => rabbit_data_coercion:to_binary(ClientId)
941-
}
942-
},
943-
944-
try rabbit_access_control:check_topic_access(User, Resource, Access, Context) of
945-
R -> R
946-
catch
947-
_:{amqp_error, access_refused, Msg, _} ->
948-
rabbit_log:error("operation resulted in an error (access_refused): ~p~n", [Msg]),
949-
{error, access_refused};
950-
_:Error ->
951-
rabbit_log:error("~p~n", [Error]),
952-
{error, access_refused}
953-
end.
937+
Cache =
938+
case get(topic_permission_cache) of
939+
undefined -> [];
940+
Other -> Other
941+
end,
942+
943+
Key = {TopicName, Username, ClientId, VHost, Exchange, Access},
944+
case lists:member(Key, Cache) of
945+
true ->
946+
ok;
947+
false ->
948+
Resource = #resource{virtual_host = VHost,
949+
kind = topic,
950+
name = Exchange},
951+
952+
RoutingKey = Mqtt2AmqpFun(TopicName),
953+
Context = #{routing_key => RoutingKey,
954+
variable_map => #{
955+
<<"username">> => Username,
956+
<<"vhost">> => VHost,
957+
<<"client_id">> => rabbit_data_coercion:to_binary(ClientId)
958+
}
959+
},
960+
961+
try rabbit_access_control:check_topic_access(User, Resource, Access, Context) of
962+
ok ->
963+
CacheTail = lists:sublist(Cache, ?MAX_TOPIC_PERMISSION_CACHE_SIZE - 1),
964+
put(topic_permission_cache, [Key | CacheTail]),
965+
ok;
966+
R ->
967+
R
968+
catch
969+
_:{amqp_error, access_refused, Msg, _} ->
970+
rabbit_log:error("operation resulted in an error (access_refused): ~p~n", [Msg]),
971+
{error, access_refused};
972+
_:Error ->
973+
rabbit_log:error("~p~n", [Error]),
974+
{error, access_refused}
975+
end
976+
end.
954977

955978
info(consumer_tags, #proc_state{consumer_tags = Val}) -> Val;
956979
info(unacked_pubs, #proc_state{unacked_pubs = Val}) -> Val;

src/rabbit_mqtt_reader.erl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
-export([start_link/2]).
2626
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
27-
code_change/3, terminate/2]).
27+
code_change/3, terminate/2, handle_pre_hibernate/1]).
2828

2929
-export([conserve_resources/3, start_keepalive/2]).
3030

@@ -197,6 +197,10 @@ terminate(Reason, State) ->
197197
maybe_emit_stats(State),
198198
do_terminate(Reason, State).
199199

200+
handle_pre_hibernate(State) ->
201+
rabbit_mqtt_processor:handle_pre_hibernate(),
202+
{hibernate, State}.
203+
200204
do_terminate({network_error, {ssl_upgrade_error, closed}, ConnStr}, _State) ->
201205
rabbit_log_connection:error("MQTT detected TLS upgrade error on ~s: connection closed~n",
202206
[ConnStr]);

0 commit comments

Comments
 (0)