Просмотр исходного кода

test(listen): verify SSL options of WSS listener are hot updateable

Andrew Mayorov 2 лет назад
Родитель
Сommit
4796f85dff
1 измененных файлов с 98 добавлено и 21 удалено
  1. 98 21
      apps/emqx/test/emqx_listeners_SUITE.erl

+ 98 - 21
apps/emqx/test/emqx_listeners_SUITE.erl

@@ -207,12 +207,7 @@ t_ssl_update_opts(Config) ->
         {customize_hostname_check, [{match_fun, fun(_, _) -> true end}]}
         {customize_hostname_check, [{match_fun, fun(_, _) -> true end}]}
     ],
     ],
     with_listener(ssl, updated, Conf, fun() ->
     with_listener(ssl, updated, Conf, fun() ->
-        ClientOpts1 = #{
-            hosts => [{Host, Port}],
-            ssl => true,
-            ssl_opts => ClientSSLOpts
-        },
-        C1 = emqtt_connect(ClientOpts1),
+        C1 = emqtt_connect_ssl(Host, Port, ClientSSLOpts),
 
 
         %% Change the listener SSL configuration.
         %% Change the listener SSL configuration.
         %% 1. Another set of (password protected) cert/key files.
         %% 1. Another set of (password protected) cert/key files.
@@ -234,17 +229,14 @@ t_ssl_update_opts(Config) ->
         %% Unable to connect with old SSL options, certificate is now required.
         %% Unable to connect with old SSL options, certificate is now required.
         ?assertError(
         ?assertError(
             {ssl_error, _Socket, {tls_alert, {certificate_required, _}}},
             {ssl_error, _Socket, {tls_alert, {certificate_required, _}}},
-            emqtt_connect(ClientOpts1)
+            emqtt_connect_ssl(Host, Port, ClientSSLOpts)
         ),
         ),
 
 
-        ClientOpts2 = ClientOpts1#{
-            ssl_opts := [
-                {certfile, filename:join(PrivDir, "client.pem")},
-                {keyfile, filename:join(PrivDir, "client.key")}
-                | ClientSSLOpts
-            ]
-        },
-        C2 = emqtt_connect(ClientOpts2),
+        C2 = emqtt_connect_ssl(Host, Port, [
+            {certfile, filename:join(PrivDir, "client.pem")},
+            {keyfile, filename:join(PrivDir, "client.key")}
+            | ClientSSLOpts
+        ]),
 
 
         %% Both pre- and post-update clients should be alive.
         %% Both pre- and post-update clients should be alive.
         ?assertEqual(pong, emqtt:ping(C1)),
         ?assertEqual(pong, emqtt:ping(C1)),
@@ -258,6 +250,68 @@ t_ssl_update_opts(Config) ->
         ok = emqtt:stop(C2)
         ok = emqtt:stop(C2)
     end).
     end).
 
 
+t_wss_update_opts(Config) ->
+    PrivDir = ?config(priv_dir, Config),
+    CACertfile = filename:join(PrivDir, "ca.pem"),
+    Host = "127.0.0.1",
+    Port = emqx_common_test_helpers:select_free_port(ssl),
+    Conf = #{
+        <<"enable">> => true,
+        <<"bind">> => format_bind({Host, Port}),
+        <<"ssl_options">> => #{
+            <<"cacertfile">> => CACertfile,
+            <<"certfile">> => filename:join(PrivDir, "server.pem"),
+            <<"keyfile">> => filename:join(PrivDir, "server.key"),
+            <<"verify">> => verify_none
+        }
+    },
+    ClientSSLOpts = [
+        {verify, verify_peer},
+        {cacertfile, CACertfile},
+        {customize_hostname_check, [{match_fun, fun(_, _) -> true end}]}
+    ],
+    with_listener(wss, updated, Conf, fun() ->
+        %% Start a client.
+        C1 = emqtt_connect_wss(Host, Port, ClientSSLOpts),
+
+        %% Change the listener SSL configuration.
+        %% 1. Another set of (password protected) cert/key files.
+        %% 2. Require peer certificate.
+        {ok, _} = emqx:update_config(
+            [listeners, wss, updated],
+            {update, #{
+                <<"ssl_options">> => #{
+                    <<"password">> => ?SERVER_KEY_PASSWORD,
+                    <<"cacertfile">> => CACertfile,
+                    <<"certfile">> => filename:join(PrivDir, "server-password.pem"),
+                    <<"keyfile">> => filename:join(PrivDir, "server-password.key"),
+                    <<"verify">> => verify_peer,
+                    <<"fail_if_no_peer_cert">> => true
+                }
+            }}
+        ),
+
+        %% Unable to connect with old SSL options, certificate is now required.
+        ?assertError(
+            %% Due to a bug `emqtt` does not instantly report that socket was closed.
+            timeout,
+            emqtt_connect_wss(Host, Port, ClientSSLOpts)
+        ),
+
+        % C2 = emqx_cth_mqttws:connect(Host, Port, [
+        C2 = emqtt_connect_wss(Host, Port, [
+            {certfile, filename:join(PrivDir, "client.pem")},
+            {keyfile, filename:join(PrivDir, "client.key")}
+            | ClientSSLOpts
+        ]),
+
+        %% Both pre- and post-update clients should be alive.
+        ?assertEqual(pong, emqtt:ping(C1)),
+        ?assertEqual(pong, emqtt:ping(C2)),
+        ok = emqtt:stop(C1),
+        ok = emqtt:stop(C2)
+    end).
+
 with_listener(Type, Name, Config, Then) ->
 with_listener(Type, Name, Config, Then) ->
     {ok, _} = emqx:update_config([listeners, Type, Name], {create, Config}),
     {ok, _} = emqx:update_config([listeners, Type, Name], {create, Config}),
     try
     try
@@ -266,12 +320,35 @@ with_listener(Type, Name, Config, Then) ->
         emqx:update_config([listeners, Type, Name], ?TOMBSTONE_CONFIG_CHANGE_REQ)
         emqx:update_config([listeners, Type, Name], ?TOMBSTONE_CONFIG_CHANGE_REQ)
     end.
     end.
 
 
-emqtt_connect(Options) ->
-    {ok, Client} = emqtt:start_link(Options),
-    true = erlang:unlink(Client),
-    case emqtt:connect(Client) of
-        {ok, _} -> Client;
-        {error, Reason} -> error(Reason)
+emqtt_connect_ssl(Host, Port, SSLOpts) ->
+    emqtt_connect(fun emqtt:connect/1, #{
+        hosts => [{Host, Port}],
+        connect_timeout => 1,
+        ssl => true,
+        ssl_opts => SSLOpts
+    }).
+
+emqtt_connect_wss(Host, Port, SSLOpts) ->
+    emqtt_connect(fun emqtt:ws_connect/1, #{
+        hosts => [{Host, Port}],
+        connect_timeout => 1,
+        ws_transport_options => [
+            {protocols, [http]},
+            {transport, tls},
+            {tls_opts, SSLOpts}
+        ]
+    }).
+
+emqtt_connect(Connect, Opts) ->
+    case emqtt:start_link(Opts) of
+        {ok, Client} ->
+            true = erlang:unlink(Client),
+            case Connect(Client) of
+                {ok, _} -> Client;
+                {error, Reason} -> error(Reason, [Opts])
+            end;
+        {error, Reason} ->
+            error(Reason, [Opts])
     end.
     end.
 
 
 t_format_bind(_) ->
 t_format_bind(_) ->