From 0fbf813ebf7dc5337e3b0d5d690f3f6a906b0977 Mon Sep 17 00:00:00 2001 From: HuangDan Date: Tue, 28 Aug 2018 19:55:23 +0800 Subject: [PATCH 1/4] Add mqtt connect tests cases --- etc/emqx.conf | 2 +- test/emqx_client_SUITE.erl | 7 +++++-- test/emqx_ct_broker_helpers.erl | 35 +++++++++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/etc/emqx.conf b/etc/emqx.conf index 4703f5083..31c5a11ed 100644 --- a/etc/emqx.conf +++ b/etc/emqx.conf @@ -1066,7 +1066,7 @@ listener.ssl.external.certfile = {{ platform_etc_dir }}/certs/cert.pem ## Most of it was copied from Mozilla’s Server Side TLS article ## ## Value: Ciphers -## listener.ssl.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA +listener.ssl.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA ## SSL parameter renegotiation is a feature that allows a client and a server ## to renegotiate the parameters of the SSL connection on the fly. diff --git a/test/emqx_client_SUITE.erl b/test/emqx_client_SUITE.erl index 7b2d5aaae..458c21d68 100644 --- a/test/emqx_client_SUITE.erl +++ b/test/emqx_client_SUITE.erl @@ -23,9 +23,9 @@ -include_lib("eunit/include/eunit.hrl"). -all() -> []. +all() -> [{group, connect}]. -groups() -> []. +groups() -> [{connect, [start]}]. init_per_suite(Config) -> Config. @@ -39,3 +39,6 @@ init_per_group(_Group, Config) -> end_per_group(_Group, _Config) -> ok. +start(_Config) -> + {ok, ClientPid, _} = emqx_client:start_link(). + diff --git a/test/emqx_ct_broker_helpers.erl b/test/emqx_ct_broker_helpers.erl index a62297a49..038ac0dc6 100644 --- a/test/emqx_ct_broker_helpers.erl +++ b/test/emqx_ct_broker_helpers.erl @@ -29,6 +29,31 @@ {cacertfile, "certs/cacert.pem"}, {certfile, "certs/client-cert.pem"}]). +-define(CIPHERS, [{ciphers, + ["ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-GCM-SHA384", + "ECDHE-ECDSA-AES256-SHA384", + "ECDHE-RSA-AES256-SHA384","ECDHE-ECDSA-DES-CBC3-SHA", + "ECDH-ECDSA-AES256-GCM-SHA384", + "ECDH-RSA-AES256-GCM-SHA384", + "ECDH-ECDSA-AES256-SHA384","ECDH-RSA-AES256-SHA384", + "DHE-DSS-AES256-GCM-SHA384","DHE-DSS-AES256-SHA256", + "AES256-GCM-SHA384","AES256-SHA256", + "ECDHE-ECDSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES128-GCM-SHA256", + "ECDHE-ECDSA-AES128-SHA256", + "ECDHE-RSA-AES128-SHA256", + "ECDH-ECDSA-AES128-GCM-SHA256", + "ECDH-RSA-AES128-GCM-SHA256", + "ECDH-ECDSA-AES128-SHA256","ECDH-RSA-AES128-SHA256", + "DHE-DSS-AES128-GCM-SHA256","DHE-DSS-AES128-SHA256", + "AES128-GCM-SHA256","AES128-SHA256", + "ECDHE-ECDSA-AES256-SHA","ECDHE-RSA-AES256-SHA", + "DHE-DSS-AES256-SHA","ECDH-ECDSA-AES256-SHA", + "ECDH-RSA-AES256-SHA","AES256-SHA", + "ECDHE-ECDSA-AES128-SHA","ECDHE-RSA-AES128-SHA", + "DHE-DSS-AES128-SHA","ECDH-ECDSA-AES128-SHA", + "ECDH-RSA-AES128-SHA","AES128-SHA"]}]). run_setup_steps() -> NewConfig = generate_config(), @@ -71,7 +96,7 @@ change_opts(SslType) -> lists:foldl(fun({Protocol, Port, Opts} = Listener, Acc) -> case Protocol of ssl -> - SslOpts = proplists:get_value(sslopts, Opts), + SslOpts = proplists:get_value(ssl_options, Opts), Keyfile = local_path(["etc/certs", "key.pem"]), Certfile = local_path(["etc/certs", "cert.pem"]), TupleList1 = lists:keyreplace(keyfile, 1, SslOpts, {keyfile, Keyfile}), @@ -89,13 +114,15 @@ change_opts(SslType) -> (_) -> true end, TupleList2) end, - [{Protocol, Port, lists:keyreplace(sslopts, 1, Opts, {sslopts, TupleList3})} | Acc]; + [{Protocol, Port, lists:keyreplace(ssl_options, 1, Opts, {ssl_options, TupleList3})} | Acc]; _ -> [Listener | Acc] end end, [], Listeners), application:set_env(?APP, listeners, NewListeners). -client_ssl() -> - [{Key, local_path(["etc", File])} || {Key, File} <- ?MQTT_SSL_CLIENT]. +client_ssl_twoway() -> + [{Key, local_path(["etc", File])} || {Key, File} <- ?MQTT_SSL_CLIENT] ++ ?CIPHERS. +client_ssl() -> + ?CIPHERS ++ [{reuse_sessions, true}]. From 37c1570e94f34c96f319746ea6127135274b02bc Mon Sep 17 00:00:00 2001 From: HuangDan Date: Tue, 28 Aug 2018 20:05:56 +0800 Subject: [PATCH 2/4] Add mqtt connect tests cases --- test/emqx_SUITE.erl | 136 ++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/test/emqx_SUITE.erl b/test/emqx_SUITE.erl index 752c40f5c..ed5c04ad8 100644 --- a/test/emqx_SUITE.erl +++ b/test/emqx_SUITE.erl @@ -25,21 +25,34 @@ -include_lib("common_test/include/ct.hrl"). +-include("emqx_mqtt.hrl"). + +-record(ssl_socket, {tcp, ssl}). + +-type(socket() :: inet:socket() | #ssl_socket{}). + -define(CLIENT, ?CONNECT_PACKET(#mqtt_packet_connect{ client_id = <<"mqtt_client">>, username = <<"admin">>, password = <<"public">>})). + +-define(CLIENT2, ?CONNECT_PACKET(#mqtt_packet_connect{ + username = <<"admin">>, + clean_start = false, + password = <<"public">>})). all() -> - [{group, connect}, - {group, cleanSession}]. + [{group, connect}%, + % {group, cleanSession} + ]. groups() -> [{connect, [non_parallel_tests], - [mqtt_connect, -% mqtt_connect_with_tcp, - mqtt_connect_with_ssl_oneway, - mqtt_connect_with_ssl_twoway%, - % mqtt_connect_with_ws + [ + % mqtt_connect, + % mqtt_connect_with_tcp, + % mqtt_connect_with_ssl_oneway, + % mqtt_connect_with_ssl_twoway%, + mqtt_connect_with_ws%, ]}, {cleanSession, [sequence], [cleanSession_validate] @@ -48,7 +61,6 @@ groups() -> init_per_suite(Config) -> emqx_ct_broker_helpers:run_setup_steps(), - % ct:log("Apps:~p", [Apps]), Config. end_per_suite(_Config) -> @@ -65,76 +77,65 @@ mqtt_connect(_) -> ?assertEqual(<<32,2,0,0>>, connect_broker_(<<16,12,0,4,77,81,84,84,4,2,0,90,0,0>>, 4)). connect_broker_(Packet, RecvSize) -> - {ok, Sock} = gen_tcp:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}]), - gen_tcp:send(Sock, Packet), + {ok, Sock} = emqx_client_sock:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}], 3000), + emqx_client_sock:send(Sock, Packet), {ok, Data} = gen_tcp:recv(Sock, RecvSize, 3000), - gen_tcp:close(Sock), + emqx_client_sock:close(Sock), Data. -%% mqtt_connect_with_tcp(_) -> -%% %% Issue #599 -%% %% Empty clientId and clean_session = false -%% {ok, Sock} = gen_tcp:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}]), -%% Packet = raw_send_serialise(?CLIENT), -%% gen_tcp:send(Sock, Packet), -%% {ok, Data} = gen_tcp:recv(Sock, 0), -%% % {ok, ?CONNACK_PACKET(?CONNACK_ACCEPT), _} = raw_recv_pase(Data), -%% gen_tcp:close(Sock). +mqtt_connect_with_tcp(_) -> + %% Issue #599 + %% Empty clientId and clean_session = false + {ok, Sock} = emqx_client_sock:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}], 3000), + Packet = raw_send_serialise(?CLIENT2), + emqx_client_sock:send(Sock, Packet), + {ok, Data} = gen_tcp:recv(Sock, 0), + {ok, ?CONNACK_PACKET(?CONNACK_INVALID_ID), _} = raw_recv_pase(Data), + emqx_client_sock:close(Sock). mqtt_connect_with_ssl_oneway(_) -> - emqx:stop(), + emqx:shutdown(), emqx_ct_broker_helpers:change_opts(ssl_oneway), emqx:start(), - timer:sleep(5000), - {ok, SslOneWay} = emqttc:start_link([{host, "localhost"}, - {port, 8883}, - {logger, debug}, - {client_id, <<"ssloneway">>}, ssl]), - timer:sleep(100), - emqttc:subscribe(SslOneWay, <<"topic">>, qos1), - {ok, Pub} = emqttc:start_link([{host, "localhost"}, - {client_id, <<"pub">>}]), - emqttc:publish(Pub, <<"topic">>, <<"SSL oneWay test">>, [{qos, 1}]), - timer:sleep(100), - receive {publish, _Topic, RM} -> - ?assertEqual(<<"SSL oneWay test">>, RM) - after 1000 -> false - end, - timer:sleep(100), - emqttc:disconnect(SslOneWay), - emqttc:disconnect(Pub). + ClientSsl = emqx_ct_broker_helpers:client_ssl(), + {ok, #ssl_socket{tcp = Sock, ssl = SslSock}} + = emqx_client_sock:connect("127.0.0.1", 8883, [{ssl_opts, ClientSsl}], 3000), +%% Packet = raw_send_serialise(?CLIENT), +%% ssl:send(SslSock, Packet), +%% receive Data -> +%% ct:log("Data:~p~n", [Data]) +%% after 30000 -> +%% ok +%% end, + ssl:close(SslSock). mqtt_connect_with_ssl_twoway(_Config) -> - emqx:stop(), + emqx:shutdown(), emqx_ct_broker_helpers:change_opts(ssl_twoway), emqx:start(), - timer:sleep(3000), - ClientSSl = emqx_ct_broker_helpers:client_ssl(), - {ok, SslTwoWay} = emqttc:start_link([{host, "localhost"}, - {port, 8883}, - {client_id, <<"ssltwoway">>}, - {ssl, ClientSSl}]), - {ok, Sub} = emqttc:start_link([{host, "localhost"}, - {client_id, <<"sub">>}]), - emqttc:subscribe(Sub, <<"topic">>, qos1), - emqttc:publish(SslTwoWay, <<"topic">>, <<"ssl client pub message">>, [{qos, 1}]), - timer:sleep(10), - receive {publish, _Topic, RM} -> - ?assertEqual(<<"ssl client pub message">>, RM) - after 1000 -> false + ClientSsl = emqx_ct_broker_helpers:client_ssl_twoway(), + {ok, #ssl_socket{tcp = _Sock1, ssl = SslSock} = Sock} + = emqx_client_sock:connect("127.0.0.1", 8883, [{ssl_opts, ClientSsl}], 3000), + Packet = raw_send_serialise(?CLIENT), + emqx_client_sock:setopts(Sock, [{active, once}]), + emqx_client_sock:send(Sock, Packet), + timer:sleep(500), + receive {ssl, _, Data}-> + {ok, ?CONNACK_PACKET(?CONNACK_ACCEPT), _} = raw_recv_pase(Data) + after 1000 -> + ok end, - emqttc:disconnect(SslTwoWay), - emqttc:disconnect(Sub). + emqx_client_sock:close(Sock). -%% mqtt_connect_with_ws(_Config) -> -%% WS = rfc6455_client:new("ws://127.0.0.1:8083" ++ "/mqtt", self()), -%% {ok, _} = rfc6455_client:open(WS), -%% Packet = raw_send_serialise(?CLIENT), -%% ok = rfc6455_client:send_binary(WS, Packet), -%% {binary, P} = rfc6455_client:recv(WS), -%% % {ok, ?CONNACK_PACKET(?CONNACK_ACCEPT), _} = raw_recv_pase(P), -%% {close, _} = rfc6455_client:close(WS), -%% ok. +mqtt_connect_with_ws(_Config) -> + WS = rfc6455_client:new("ws://127.0.0.1:8083" ++ "/mqtt", self()), + {ok, _} = rfc6455_client:open(WS), + Packet = raw_send_serialise(?CLIENT), + ok = rfc6455_client:send_binary(WS, Packet), + {binary, P} = rfc6455_client:recv(WS), + ct:log(":~p", [P]), + {close, _} = rfc6455_client:close(WS), + ok. cleanSession_validate(_) -> {ok, C1} = emqttc:start_link([{host, "localhost"}, @@ -163,8 +164,9 @@ cleanSession_validate(_) -> emqttc:disconnect(C11). raw_send_serialise(Packet) -> - emqttc_serialiser:serialise(Packet). + emqx_frame:serialize(Packet). raw_recv_pase(P) -> - emqttc_parser:parse(P, emqttc_parser:new()). + emqx_frame:parse(P, {none, #{max_packet_size => ?MAX_PACKET_SIZE, + version => ?MQTT_PROTO_V4} }). From 9b06589eab6c386b50392686eb9fe149c51a2e2f Mon Sep 17 00:00:00 2001 From: HuangDan Date: Wed, 29 Aug 2018 13:49:54 +0800 Subject: [PATCH 3/4] Add SUBSCRIBER/PUBLISH Packet test cases --- test/emqx_SUITE.erl | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/test/emqx_SUITE.erl b/test/emqx_SUITE.erl index ed5c04ad8..952fc6cb9 100644 --- a/test/emqx_SUITE.erl +++ b/test/emqx_SUITE.erl @@ -40,6 +40,17 @@ username = <<"admin">>, clean_start = false, password = <<"public">>})). + +-define(SUBCODE, [0]). + +-define(PACKETID, 1). + +-define(PUBQOS, 1). + +-define(SUBPACKET, ?SUBSCRIBE_PACKET(?PACKETID, [{<<"sub/topic">>, ?DEFAULT_SUBOPTS}])). + +-define(PUBPACKET, ?PUBLISH_PACKET(?PUBQOS, <<"sub/topic">>, ?PACKETID, <<"publish">>)). + all() -> [{group, connect}%, % {group, cleanSession} @@ -48,11 +59,11 @@ all() -> groups() -> [{connect, [non_parallel_tests], [ - % mqtt_connect, - % mqtt_connect_with_tcp, - % mqtt_connect_with_ssl_oneway, - % mqtt_connect_with_ssl_twoway%, - mqtt_connect_with_ws%, + mqtt_connect, + mqtt_connect_with_tcp, + mqtt_connect_with_ssl_oneway, + mqtt_connect_with_ssl_twoway, + mqtt_connect_with_ws ]}, {cleanSession, [sequence], [cleanSession_validate] @@ -130,10 +141,24 @@ mqtt_connect_with_ssl_twoway(_Config) -> mqtt_connect_with_ws(_Config) -> WS = rfc6455_client:new("ws://127.0.0.1:8083" ++ "/mqtt", self()), {ok, _} = rfc6455_client:open(WS), + + %% Connect Packet Packet = raw_send_serialise(?CLIENT), ok = rfc6455_client:send_binary(WS, Packet), - {binary, P} = rfc6455_client:recv(WS), - ct:log(":~p", [P]), + {binary, CONACK} = rfc6455_client:recv(WS), + {ok, ?CONNACK_PACKET(?CONNACK_ACCEPT), _} = raw_recv_pase(CONACK), + + %% Sub Packet + SubPacket = raw_send_serialise(?SUBPACKET), + rfc6455_client:send_binary(WS, SubPacket), + {binary, SubAck} = rfc6455_client:recv(WS), + {ok, ?SUBACK_PACKET(?PACKETID, ?SUBCODE), _} = raw_recv_pase(SubAck), + + %% Pub Packet QoS 1 + PubPacket = raw_send_serialise(?PUBPACKET), + rfc6455_client:send_binary(WS, PubPacket), + {binary, PubAck} = rfc6455_client:recv(WS), + {ok, ?PUBACK_PACKET(?PACKETID), _} = raw_recv_pase(PubAck), {close, _} = rfc6455_client:close(WS), ok. From 53d7d0a9d462b90fa6fdcf9426de59a95adb2860 Mon Sep 17 00:00:00 2001 From: HuangDan Date: Wed, 29 Aug 2018 16:24:01 +0800 Subject: [PATCH 4/4] Update the peer_cert_as_username conf desc --- etc/emqx.conf | 6 +++--- priv/emqx.schema | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/etc/emqx.conf b/etc/emqx.conf index 31c5a11ed..588725446 100644 --- a/etc/emqx.conf +++ b/etc/emqx.conf @@ -752,8 +752,8 @@ listener.tcp.external.access.1 = allow all ## Enable the option for X.509 certificate based authentication. ## EMQX will use the common name of certificate as MQTT username. ## -## Value: boolean -## listener.tcp.external.peer_cert_as_username = true +## Value: cn | dn +## listener.tcp.external.peer_cert_as_username = cn ## The TCP backlog defines the maximum length that the queue of pending ## connections can grow to. @@ -1096,7 +1096,7 @@ listener.ssl.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-G ## Use the CN field from the client certificate as a username. ## Notice that 'verify' should be set as 'verify_peer'. ## -## Value: boolean +## Value: cn | en ## listener.ssl.external.peer_cert_as_username = cn ## TCP backlog for the SSL connection. diff --git a/priv/emqx.schema b/priv/emqx.schema index a0d2bc0e2..1a2209dd8 100644 --- a/priv/emqx.schema +++ b/priv/emqx.schema @@ -857,8 +857,7 @@ end}. ]}. {mapping, "listener.tcp.$name.peer_cert_as_username", "emqx.listeners", [ - {default, false}, - {datatype, {enum, [true, false]}} + {datatype, {enum, [cn, dn]}} ]}. {mapping, "listener.tcp.$name.backlog", "emqx.listeners", [