From 0db6b8d47ea49aeaa124aef84e87d35586beb82d Mon Sep 17 00:00:00 2001 From: firest Date: Sat, 2 Apr 2022 13:54:59 +0800 Subject: [PATCH] test(gateway): integration stomp && exproto test with http authn --- apps/emqx_gateway/test/emqx_coap_SUITE.erl | 18 +- apps/emqx_gateway/test/emqx_exproto_SUITE.erl | 16 + .../test/emqx_gateway_authn_http_SUITE.erl | 296 ++++++++++++------ apps/emqx_gateway/test/emqx_stomp_SUITE.erl | 6 + 4 files changed, 229 insertions(+), 107 deletions(-) diff --git a/apps/emqx_gateway/test/emqx_coap_SUITE.erl b/apps/emqx_gateway/test/emqx_coap_SUITE.erl index 563fa9fa7..e17c20f9d 100644 --- a/apps/emqx_gateway/test/emqx_coap_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_coap_SUITE.erl @@ -106,19 +106,19 @@ t_connection(_) -> t_publish(_) -> Action = fun(Channel, Token) -> - Topic = <<"/abc">>, - Payload = <<"123">>, + Topic = <<"/abc">>, + Payload = <<"123">>, - TopicStr = binary_to_list(Topic), - URI = ?PS_PREFIX ++ TopicStr ++ "?clientid=client1&token=" ++ Token, + TopicStr = binary_to_list(Topic), + URI = ?PS_PREFIX ++ TopicStr ++ "?clientid=client1&token=" ++ Token, - %% Sub topic first - emqx:subscribe(Topic), + %% Sub topic first + emqx:subscribe(Topic), - Req = make_req(post, Payload), - {ok, changed, _} = do_request(Channel, URI, Req), + Req = make_req(post, Payload), + {ok, changed, _} = do_request(Channel, URI, Req), - receive + receive {deliver, Topic, Msg} -> ?assertEqual(Topic, Msg#message.topic), ?assertEqual(Payload, Msg#message.payload) diff --git a/apps/emqx_gateway/test/emqx_exproto_SUITE.erl b/apps/emqx_gateway/test/emqx_exproto_SUITE.erl index 5ca1ae52f..50d69cb0a 100644 --- a/apps/emqx_gateway/test/emqx_exproto_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_exproto_SUITE.erl @@ -40,6 +40,19 @@ -define(TCPOPTS, [binary, {active, false}]). -define(DTLSOPTS, [binary, {active, false}, {protocol, dtls}]). +%%-------------------------------------------------------------------- +-define(CONF_DEFAULT, + <<"\n" + "gateway.exproto {\n" + " server.bind = 9100,\n" + " handler.address = \"http://127.0.0.1:9001\"\n" + " listeners.tcp.default {\n" + " bind = 7993,\n" + " acceptors = 8\n" + " }\n" + "}\n">> +). + %%-------------------------------------------------------------------- %% Setups %%-------------------------------------------------------------------- @@ -84,6 +97,9 @@ listener_confs(Type) -> Default = #{bind => 7993, acceptors => 8}, #{Type => #{'default' => maps:merge(Default, socketopts(Type))}}. +default_config() -> + ?CONF_DEFAULT. + %%-------------------------------------------------------------------- %% Tests cases %%-------------------------------------------------------------------- diff --git a/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl index 7cc88a865..f93995808 100644 --- a/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl @@ -29,31 +29,45 @@ -define(HTTP_PORT, 33333). -define(HTTP_PATH, "/auth"). --define(CREDENTIALS, #{username => <<"admin">>, - password => <<"public">>, - listener => 'tcp:default', - protocol => mqtt - }). - -define(checkMatch(Guard), - (fun (Expr) -> - case (Expr) of - Guard -> ok; - X__V -> - erlang:error({assertMatch, - [{module, ?MODULE}, - {line, ?LINE}, - {expression, (??Expr)}, - {pattern, (??Guard)}, - {value, X__V}]}) - end - end)). + (fun(Expr) -> + case (Expr) of + Guard -> + ok; + X__V -> + erlang:error( + {assertMatch, [ + {module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {pattern, (??Guard)}, + {value, X__V} + ]} + ) + end + end) +). -define(FUNCTOR(Expr), fun() -> Expr end). -define(FUNCTOR(Arg, Expr), fun(Arg) -> Expr end). --define(PROTOCOLS, [coap, lwm2m, 'mqtt-sn'] ). --define(CONFS, [emqx_coap_SUITE, emqx_lwm2m_SUITE, emqx_sn_protocol_SUITE]). --define(CASES, [fun case_coap/0, fun case_lwm2m/0, fun case_emqx_sn/0, fun case_stomp/0]). +-define(PROTOCOLS, [coap, lwm2m, 'mqtt-sn', stomp, exproto]). + +-define(CONFS, [ + emqx_coap_SUITE, + emqx_lwm2m_SUITE, + emqx_sn_protocol_SUITE, + emqx_stomp_SUITE, + emqx_exproto_SUITE +]). + +-define(CASES, [ + fun case_coap/0, + fun case_lwm2m/0, + fun case_emqx_sn/0, + fun case_stomp/0, + fun case_exproto/0 +]). + -define(AUTHNS, [fun set_http_authn/1]). -type auth_controller() :: fun((start | stop) -> ok). @@ -94,19 +108,21 @@ t_authn(_) -> case_coap() -> Login = fun(URI, Checker) -> - Action = fun(Channel) -> - Req = emqx_coap_SUITE:make_req(post), - Checker(emqx_coap_SUITE:do_request(Channel, URI, Req)) - end, - emqx_coap_SUITE:do(Action) - end, + Action = fun(Channel) -> + Req = emqx_coap_SUITE:make_req(post), + Checker(emqx_coap_SUITE:do_request(Channel, URI, Req)) + end, + emqx_coap_SUITE:do(Action) + end, Prefix = emqx_coap_SUITE:mqtt_prefix(), - RightUrl = Prefix ++ - "/connection?clientid=client1&username=admin&password=public", + RightUrl = + Prefix ++ + "/connection?clientid=client1&username=admin&password=public", Login(RightUrl, ?checkMatch({ok, created, _Data})), - LeftUrl = Prefix ++ - "/connection?clientid=client1&username=bad&password=bad", + LeftUrl = + Prefix ++ + "/connection?clientid=client1&username=bad&password=bad", Login(LeftUrl, ?checkMatch({error, bad_request, _Data})), ok. @@ -118,28 +134,33 @@ case_lwm2m() -> Epn = "urn:oma:lwm2m:oma:3", Port = emqx_lwm2m_SUITE:default_port(), Login = fun(URI, Checker) -> - with_resource(?FUNCTOR(gen_udp:open(0, [binary, {active, false}])), - ?FUNCTOR(Socket, gen_udp:close(Socket)), - fun(Socket) -> - Mod:test_send_coap_request( - Socket, - post, - Mod:sprintf(URI, [Port, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<", , , , ">>}, - [], - MsgId), + with_resource( + ?FUNCTOR(gen_udp:open(0, [binary, {active, false}])), + ?FUNCTOR(Socket, gen_udp:close(Socket)), + fun(Socket) -> + Mod:test_send_coap_request( + Socket, + post, + Mod:sprintf(URI, [Port, Epn]), + #coap_content{ + content_format = <<"text/plain">>, + payload = <<", , , , ">> + }, + [], + MsgId + ), - Checker(Mod:test_recv_coap_response(Socket)) - end) - end, + Checker(Mod:test_recv_coap_response(Socket)) + end + ) + end, MakeCheker = fun(Type, Method) -> - fun(Msg) -> - ?assertEqual(Type, emqx_coap_SUITE:get_field(type, Msg)), - ?assertEqual(Method, emqx_coap_SUITE:get_field(method, Msg)) - end - end, + fun(Msg) -> + ?assertEqual(Type, emqx_coap_SUITE:get_field(type, Msg)), + ?assertEqual(Method, emqx_coap_SUITE:get_field(method, Msg)) + end + end, RightUrl = "coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1&imei=admin&password=public", Login(RightUrl, MakeCheker(ack, {ok, created})), @@ -156,23 +177,94 @@ case_lwm2m() -> case_emqx_sn() -> Mod = emqx_sn_protocol_SUITE, Login = fun(Expect) -> - with_resource(?FUNCTOR(gen_udp:open(0, [binary])), - ?FUNCTOR(Socket, gen_udp:close(Socket)), - fun(Socket) -> - Mod:send_connect_msg(Socket, <<"client_id_test1">>), - ?assertEqual(Expect, Mod:receive_response(Socket)) - end) - end, + with_resource( + ?FUNCTOR(gen_udp:open(0, [binary])), + ?FUNCTOR(Socket, gen_udp:close(Socket)), + fun(Socket) -> + Mod:send_connect_msg(Socket, <<"client_id_test1">>), + ?assertEqual(Expect, Mod:receive_response(Socket)) + end + ) + end, Login(<<>>), RawCfg = emqx_conf:get_raw([gateway, mqttsn], #{}), - NewCfg = RawCfg#{<<"clientinfo_override">> => #{<<"username">> => <<"admin">>, - <<"password">> => <<"public">>}}, + NewCfg = RawCfg#{ + <<"clientinfo_override">> => #{ + <<"username">> => <<"admin">>, + <<"password">> => <<"public">> + } + }, emqx_gateway_conf:update_gateway(mqttsn, NewCfg), Login(<<3, ?SN_CONNACK, 0>>), ok. case_stomp() -> + Mod = emqx_stomp_SUITE, + Login = fun(Username, Password, Checker) -> + Fun = fun(Sock) -> + gen_tcp:send( + Sock, + Mod:serialize( + <<"CONNECT">>, + [ + {<<"accept-version">>, Mod:stomp_ver()}, + {<<"host">>, <<"127.0.0.1:61613">>}, + {<<"login">>, Username}, + {<<"passcode">>, Password}, + {<<"heart-beat">>, <<"1000,2000">>} + ] + ) + ), + {ok, Data} = gen_tcp:recv(Sock, 0), + {ok, Frame, _, _} = Mod:parse(Data), + Checker(Frame) + end, + Mod:with_connection(Fun) + end, + Login( + <<"admin">>, + <<"public">>, + ?FUNCTOR( + Frame, + ?assertEqual(<<"CONNECTED">>, Mod:get_field(command, Frame)) + ) + ), + Login(<<"bad">>, <<"bad">>, fun(Frame) -> + ?assertEqual(<<"ERROR">>, Mod:get_field(command, Frame)), + ?assertEqual(<<"Login Failed: not_authorized">>, Mod:get_field(body, Frame)) + end), + + ok. + +case_exproto() -> + Mod = emqx_exproto_SUITE, + SvrMod = emqx_exproto_echo_svr, + Svrs = SvrMod:start(), + Login = fun(Username, Password, Expect) -> + with_resource( + ?FUNCTOR(Mod:open(tcp)), + ?FUNCTOR(Sock, Mod:close(Sock)), + fun(Sock) -> + Client = #{ + proto_name => <<"demo">>, + proto_ver => <<"v0.1">>, + clientid => <<"test_client_1">>, + username => Username + }, + + ConnBin = SvrMod:frame_connect(Client, Password), + + Mod:send(Sock, ConnBin), + {ok, Recv} = Mod:recv(Sock, 5000), + C = ?FUNCTOR(Bin, emqx_json:decode(Bin, [return_maps])), + ?assertEqual(C(Expect), C(Recv)) + end + ) + end, + Login(<<"admin">>, <<"public">>, SvrMod:frame_connack(0)), + Login(<<"bad">>, <<"bad">>, SvrMod:frame_connack(1)), + SvrMod:stop(Svrs), ok. %%------------------------------------------------------------------------------ @@ -181,15 +273,15 @@ case_stomp() -> raw_http_auth_config() -> #{ - mechanism => <<"password_based">>, - enable => <<"true">>, + mechanism => <<"password_based">>, + enable => <<"true">>, - backend => <<"http">>, - method => <<"get">>, - url => <<"http://127.0.0.1:33333/auth">>, - body => #{<<"username">> => ?PH_USERNAME, <<"password">> => ?PH_PASSWORD}, - headers => #{<<"X-Test-Header">> => <<"Test Value">>} - }. + backend => <<"http">>, + method => <<"get">>, + url => <<"http://127.0.0.1:33333/auth">>, + body => #{<<"username">> => ?PH_USERNAME, <<"password">> => ?PH_PASSWORD}, + headers => #{<<"X-Test-Header">> => <<"Test Value">>} + }. set_http_authn(start) -> {ok, _} = emqx_authn_http_test_server:start_link(?HTTP_PORT, ?HTTP_PATH), @@ -197,37 +289,40 @@ set_http_authn(start) -> AuthConfig = raw_http_auth_config(), Set = fun(Protocol) -> - Chain = emqx_authentication:global_chain(Protocol), - emqx_authn_test_lib:delete_authenticators([authentication], Chain), + Chain = emqx_authentication:global_chain(Protocol), + emqx_authn_test_lib:delete_authenticators([authentication], Chain), - {ok, _} = emqx:update_config( - ?PATH, - {create_authenticator, Chain, AuthConfig}), + {ok, _} = emqx:update_config( + ?PATH, + {create_authenticator, Chain, AuthConfig} + ), - {ok, [#{provider := emqx_authn_http}]} = emqx_authentication:list_authenticators(Chain) - end, + {ok, [#{provider := emqx_authn_http}]} = emqx_authentication:list_authenticators(Chain) + end, lists:foreach(Set, ?PROTOCOLS), Handler = fun(Req0, State) -> - ct:pal("Req:~p State:~p~n", [Req0, State]), - case cowboy_req:match_qs([username, password], Req0) of - #{username := <<"admin">>, - password := <<"public">>} -> - Req = cowboy_req:reply(200, Req0); - _ -> - Req = cowboy_req:reply(400, Req0) - end, - {ok, Req, State} - end, + ct:pal("Req:~p State:~p~n", [Req0, State]), + case cowboy_req:match_qs([username, password], Req0) of + #{ + username := <<"admin">>, + password := <<"public">> + } -> + Req = cowboy_req:reply(200, Req0); + _ -> + Req = cowboy_req:reply(400, Req0) + end, + {ok, Req, State} + end, emqx_authn_http_test_server:set_handler(Handler); set_http_authn(stop) -> ok = emqx_authn_http_test_server:stop(). clear_authn() -> Clear = fun(Protocol) -> - Chain = emqx_authentication:global_chain(Protocol), - emqx_authn_test_lib:delete_authenticators([authentication], Chain) - end, + Chain = emqx_authentication:global_chain(Protocol), + emqx_authn_test_lib:delete_authenticators([authentication], Chain) + end, lists:foreach(Clear, ?PROTOCOLS). %%------------------------------------------------------------------------------ @@ -242,11 +337,14 @@ test_gateway_with_auths([{Auth, Gateways} | T]) -> {name, Name} = erlang:fun_info(Auth, name), ct:pal("start auth:~p~n", [Name]), Auth(start), - lists:foreach(fun(Gateway) -> - {name, GwName} = erlang:fun_info(Gateway, name), - ct:pal("start gateway case:~p~n", [GwName]), - Gateway() - end, Gateways), + lists:foreach( + fun(Gateway) -> + {name, GwName} = erlang:fun_info(Gateway, name), + ct:pal("start gateway case:~p~n", [GwName]), + Gateway() + end, + Gateways + ), ct:pal("stop auth:~p~n", [Name]), Auth(stop), test_gateway_with_auths(T); @@ -263,17 +361,19 @@ merge_conf([Conf | T], Acc) -> _ -> merge_conf(T, Acc) end; -merge_conf([ ], Acc) -> +merge_conf([], Acc) -> erlang:list_to_binary("gateway{" ++ string:join(Acc, ",") ++ "}"). with_resource(Init, Close, Fun) -> - Res = case Init() of - {ok, X} -> X; - Other -> Other - end, + Res = + case Init() of + {ok, X} -> X; + Other -> Other + end, try Fun(Res) - catch C:R:S -> + catch + C:R:S -> Close(Res), erlang:raise(C, R, S) end. diff --git a/apps/emqx_gateway/test/emqx_stomp_SUITE.erl b/apps/emqx_gateway/test/emqx_stomp_SUITE.erl index ca61a63a4..06e7ce318 100644 --- a/apps/emqx_gateway/test/emqx_stomp_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_stomp_SUITE.erl @@ -61,6 +61,12 @@ end_per_suite(_Cfg) -> emqx_mgmt_api_test_util:end_suite([emqx_gateway]), ok. +default_config() -> + ?CONF_DEFAULT. + +stomp_ver() -> + ?STOMP_VER. + %%-------------------------------------------------------------------- %% Test Cases %%--------------------------------------------------------------------