fix(emqx_gateway): return 404 for unknown client id

This commit is contained in:
Stefan Strigler 2023-07-06 15:26:15 +02:00
parent 3bc419ee64
commit d65d690c17
4 changed files with 102 additions and 19 deletions

View File

@ -57,7 +57,8 @@
qs2ms/2, qs2ms/2,
run_fuzzy_filter/2, run_fuzzy_filter/2,
format_channel_info/1, format_channel_info/1,
format_channel_info/2 format_channel_info/2,
client_info_mountpoint/1
]). ]).
-define(TAGS, [<<"Gateway Clients">>]). -define(TAGS, [<<"Gateway Clients">>]).
@ -177,8 +178,12 @@ clients_insta(delete, #{
} }
}) -> }) ->
with_gateway(Name0, fun(GwName, _) -> with_gateway(Name0, fun(GwName, _) ->
_ = emqx_gateway_http:kickout_client(GwName, ClientId), case emqx_gateway_http:kickout_client(GwName, ClientId) of
{error, not_found} ->
return_http_error(404, "Client not found");
_ ->
{204} {204}
end
end). end).
%% List the established subscriptions with mountpoint %% List the established subscriptions with mountpoint
@ -234,8 +239,13 @@ subscriptions(delete, #{
} }
}) -> }) ->
with_gateway(Name0, fun(GwName, _) -> with_gateway(Name0, fun(GwName, _) ->
case lookup_topic(GwName, ClientId, Topic) of
{ok, _} ->
_ = emqx_gateway_http:client_unsubscribe(GwName, ClientId, Topic), _ = emqx_gateway_http:client_unsubscribe(GwName, ClientId, Topic),
{204} {204};
{error, not_found} ->
return_http_error(404, "Resource not found")
end
end). end).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
@ -260,6 +270,34 @@ extra_sub_props(Props) ->
#{subid => maps:get(<<"subid">>, Props, undefined)} #{subid => maps:get(<<"subid">>, Props, undefined)}
). ).
lookup_topic(GwName, ClientId, Topic) ->
Mountpoints = emqx_gateway_http:lookup_client(
GwName,
ClientId,
{?MODULE, client_info_mountpoint}
),
case emqx_gateway_http:list_client_subscriptions(GwName, ClientId) of
{ok, Subscriptions} ->
case
[
S
|| S = #{topic := Topic0} <- Subscriptions,
Mountpoint <- Mountpoints,
Topic0 == emqx_mountpoint:mount(Mountpoint, Topic)
]
of
[] ->
{error, not_found};
Filtered ->
{ok, Filtered}
end;
Error ->
Error
end.
client_info_mountpoint({_, #{clientinfo := #{mountpoint := Mountpoint}}, _}) ->
Mountpoint.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% QueryString to MatchSpec %% QueryString to MatchSpec

View File

@ -586,6 +586,47 @@ t_listeners_authn_data_mgmt(_) ->
ok. ok.
t_clients(_) ->
GwConf = #{
name => <<"mqttsn">>,
gateway_id => 1,
broadcast => true,
predefined => [#{id => 1, topic => <<"t/a">>}],
enable_qos3 => true,
listeners => [
#{name => <<"def">>, type => <<"udp">>, bind => <<"1884">>}
]
},
init_gw("mqttsn", GwConf),
Path = "/gateways/mqttsn/clients",
MyClient = Path ++ "/my_client",
MyClientSubscriptions = MyClient ++ "/subscriptions",
{200, NoClients} = request(get, Path),
?assertMatch(#{data := []}, NoClients),
ClientSocket = emqx_gateway_test_utils:sn_client_connect(<<"my_client">>),
{200, _} = request(get, MyClient),
{200, Clients} = request(get, Path),
?assertMatch(#{data := [#{clientid := <<"my_client">>}]}, Clients),
{201, _} = request(post, MyClientSubscriptions, #{topic => <<"test/topic">>}),
{200, Subscriptions} = request(get, MyClientSubscriptions),
?assertMatch([#{topic := <<"test/topic">>}], Subscriptions),
{204, _} = request(delete, MyClientSubscriptions ++ "/test%2Ftopic"),
{200, []} = request(get, MyClientSubscriptions),
{404, _} = request(delete, MyClientSubscriptions ++ "/test%2Ftopic"),
{204, _} = request(delete, MyClient),
{404, _} = request(delete, MyClient),
{404, _} = request(get, MyClient),
{404, _} = request(get, MyClientSubscriptions),
{404, _} = request(post, MyClientSubscriptions, #{topic => <<"foo">>}),
{404, _} = request(delete, MyClientSubscriptions ++ "/topic"),
{200, NoClients2} = request(get, Path),
?assertMatch(#{data := []}, NoClients2),
emqx_gateway_test_utils:sn_client_disconnect(ClientSocket),
ok.
t_authn_fuzzy_search(_) -> t_authn_fuzzy_search(_) ->
init_gw("stomp"), init_gw("stomp"),
AuthConf = #{ AuthConf = #{

View File

@ -54,6 +54,8 @@ end).
"}\n" "}\n"
). ).
-import(emqx_gateway_test_utils, [sn_client_connect/1, sn_client_disconnect/1]).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Setup %% Setup
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
@ -303,17 +305,3 @@ acc_print(Acc) ->
after 200 -> after 200 ->
Acc Acc
end. end.
sn_client_connect(ClientId) ->
{ok, Socket} = gen_udp:open(0, [binary]),
_ = emqx_sn_protocol_SUITE:send_connect_msg(Socket, ClientId),
?assertEqual(
<<3, 16#05, 0>>,
emqx_sn_protocol_SUITE:receive_response(Socket)
),
Socket.
sn_client_disconnect(Socket) ->
_ = emqx_sn_protocol_SUITE:send_disconnect_msg(Socket, undefined),
gen_udp:close(Socket),
ok.

View File

@ -19,6 +19,8 @@
-compile(export_all). -compile(export_all).
-compile(nowarn_export_all). -compile(nowarn_export_all).
-include_lib("eunit/include/eunit.hrl").
assert_confs(Expected0, Effected) -> assert_confs(Expected0, Effected) ->
Expected = maybe_unconvert_listeners(Expected0), Expected = maybe_unconvert_listeners(Expected0),
case do_assert_confs(root, Expected, Effected) of case do_assert_confs(root, Expected, Effected) of
@ -181,3 +183,17 @@ url(Path, Qs) ->
auth(Headers) -> auth(Headers) ->
[emqx_mgmt_api_test_util:auth_header_() | Headers]. [emqx_mgmt_api_test_util:auth_header_() | Headers].
sn_client_connect(ClientId) ->
{ok, Socket} = gen_udp:open(0, [binary]),
_ = emqx_sn_protocol_SUITE:send_connect_msg(Socket, ClientId),
?assertEqual(
<<3, 16#05, 0>>,
emqx_sn_protocol_SUITE:receive_response(Socket)
),
Socket.
sn_client_disconnect(Socket) ->
_ = emqx_sn_protocol_SUITE:send_disconnect_msg(Socket, undefined),
gen_udp:close(Socket),
ok.