Kaynağa Gözat

test(listen): also change CA on update and verify clients notice

Andrew Mayorov 2 yıl önce
ebeveyn
işleme
baf46c9aa2
1 değiştirilmiş dosya ile 88 ekleme ve 38 silme
  1. 88 38
      apps/emqx/test/emqx_listeners_SUITE.erl

+ 88 - 38
apps/emqx/test/emqx_listeners_SUITE.erl

@@ -188,38 +188,58 @@ t_ssl_password_cert(Config) ->
 
 t_ssl_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"),
+            <<"cacertfile">> => filename:join(PrivDir, "ca.pem"),
+            <<"password">> => ?SERVER_KEY_PASSWORD,
+            <<"certfile">> => filename:join(PrivDir, "server-password.pem"),
+            <<"keyfile">> => filename:join(PrivDir, "server-password.key"),
             <<"verify">> => verify_none
         }
     },
     ClientSSLOpts = [
         {verify, verify_peer},
-        {cacertfile, CACertfile},
         {customize_hostname_check, [{match_fun, fun(_, _) -> true end}]}
     ],
     with_listener(ssl, updated, Conf, fun() ->
-        C1 = emqtt_connect_ssl(Host, Port, ClientSSLOpts),
+        %% Client connects successfully.
+        C1 = emqtt_connect_ssl(Host, Port, [
+            {cacertfile, filename:join(PrivDir, "ca.pem")} | ClientSSLOpts
+        ]),
 
-        %% Change the listener SSL configuration.
-        %% 1. Another set of (password protected) cert/key files.
-        %% 2. Require peer certificate.
+        %% Change the listener SSL configuration: another set of cert/key files.
+        {ok, _} = emqx:update_config(
+            [listeners, ssl, updated],
+            {update, #{
+                <<"ssl_options">> => #{
+                    <<"cacertfile">> => filename:join(PrivDir, "ca-next.pem"),
+                    <<"certfile">> => filename:join(PrivDir, "server.pem"),
+                    <<"keyfile">> => filename:join(PrivDir, "server.key")
+                }
+            }}
+        ),
+
+        %% Unable to connect with old SSL options, server's cert is signed by another CA.
+        ?assertError(
+            {tls_alert, {unknown_ca, _}},
+            emqtt_connect_ssl(Host, Port, [
+                {cacertfile, filename:join(PrivDir, "ca.pem")} | ClientSSLOpts
+            ])
+        ),
+
+        C2 = emqtt_connect_ssl(Host, Port, [
+            {cacertfile, filename:join(PrivDir, "ca-next.pem")} | ClientSSLOpts
+        ]),
+
+        %% Change the listener SSL configuration: require peer certificate.
         {ok, _} = emqx:update_config(
             [listeners, ssl, 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
                 }
@@ -229,10 +249,13 @@ t_ssl_update_opts(Config) ->
         %% Unable to connect with old SSL options, certificate is now required.
         ?assertError(
             {ssl_error, _Socket, {tls_alert, {certificate_required, _}}},
-            emqtt_connect_ssl(Host, Port, ClientSSLOpts)
+            emqtt_connect_ssl(Host, Port, [
+                {cacertfile, filename:join(PrivDir, "ca-next.pem")} | ClientSSLOpts
+            ])
         ),
 
-        C2 = emqtt_connect_ssl(Host, Port, [
+        C3 = emqtt_connect_ssl(Host, Port, [
+            {cacertfile, filename:join(PrivDir, "ca-next.pem")},
             {certfile, filename:join(PrivDir, "client.pem")},
             {keyfile, filename:join(PrivDir, "client.key")}
             | ClientSSLOpts
@@ -241,38 +264,38 @@ t_ssl_update_opts(Config) ->
         %% Both pre- and post-update clients should be alive.
         ?assertEqual(pong, emqtt:ping(C1)),
         ?assertEqual(pong, emqtt:ping(C2)),
-        %% TODO
-        %% Would be nice to verify that the server picked up new cert/key pair.
-        %% However, there's no usable API for that in `emqtt` at the moment.
-        %% ?assertEqual(<<"server">>, esockd_peercert:common_name(Cert1)),
-        %% ?assertEqual(<<"server-password">>, esockd_peercert:common_name(Cert2)),
+        ?assertEqual(pong, emqtt:ping(C3)),
+
         ok = emqtt:stop(C1),
-        ok = emqtt:stop(C2)
+        ok = emqtt:stop(C2),
+        ok = emqtt:stop(C3)
     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"),
+            <<"cacertfile">> => filename:join(PrivDir, "ca.pem"),
+            <<"certfile">> => filename:join(PrivDir, "server-password.pem"),
+            <<"keyfile">> => filename:join(PrivDir, "server-password.key"),
+            <<"password">> => ?SERVER_KEY_PASSWORD,
             <<"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),
+        C1 = emqtt_connect_wss(Host, Port, [
+            {cacertfile, filename:join(PrivDir, "ca.pem")}
+            | ClientSSLOpts
+        ]),
 
         %% Change the listener SSL configuration.
         %% 1. Another set of (password protected) cert/key files.
@@ -281,10 +304,30 @@ t_wss_update_opts(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"),
+                    <<"cacertfile">> => filename:join(PrivDir, "ca-next.pem"),
+                    <<"certfile">> => filename:join(PrivDir, "server.pem"),
+                    <<"keyfile">> => filename:join(PrivDir, "server.key")
+                }
+            }}
+        ),
+
+        %% Unable to connect with old SSL options, server's cert is signed by another CA.
+        %% Due to a bug `emqtt` exits with `badmatch` in this case.
+        ?assertExit(
+            _Badmatch,
+            emqtt_connect_wss(Host, Port, ClientSSLOpts)
+        ),
+
+        C2 = emqtt_connect_wss(Host, Port, [
+            {cacertfile, filename:join(PrivDir, "ca-next.pem")}
+            | ClientSSLOpts
+        ]),
+
+        %% Change the listener SSL configuration: require peer certificate.
+        {ok, _} = emqx:update_config(
+            [listeners, wss, updated],
+            {update, #{
+                <<"ssl_options">> => #{
                     <<"verify">> => verify_peer,
                     <<"fail_if_no_peer_cert">> => true
                 }
@@ -292,14 +335,17 @@ t_wss_update_opts(Config) ->
         ),
 
         %% Unable to connect with old SSL options, certificate is now required.
+        %% Due to a bug `emqtt` does not instantly report that socket was closed.
         ?assertError(
-            %% Due to a bug `emqtt` does not instantly report that socket was closed.
             timeout,
-            emqtt_connect_wss(Host, Port, ClientSSLOpts)
+            emqtt_connect_wss(Host, Port, [
+                {cacertfile, filename:join(PrivDir, "ca-next.pem")}
+                | ClientSSLOpts
+            ])
         ),
 
-        % C2 = emqx_cth_mqttws:connect(Host, Port, [
-        C2 = emqtt_connect_wss(Host, Port, [
+        C3 = emqtt_connect_wss(Host, Port, [
+            {cacertfile, filename:join(PrivDir, "ca-next.pem")},
             {certfile, filename:join(PrivDir, "client.pem")},
             {keyfile, filename:join(PrivDir, "client.key")}
             | ClientSSLOpts
@@ -308,8 +354,11 @@ t_wss_update_opts(Config) ->
         %% Both pre- and post-update clients should be alive.
         ?assertEqual(pong, emqtt:ping(C1)),
         ?assertEqual(pong, emqtt:ping(C2)),
+        ?assertEqual(pong, emqtt:ping(C3)),
+
         ok = emqtt:stop(C1),
-        ok = emqtt:stop(C2)
+        ok = emqtt:stop(C2),
+        ok = emqtt:stop(C3)
     end).
 
 with_listener(Type, Name, Config, Then) ->
@@ -380,8 +429,9 @@ t_format_bind(_) ->
 generate_tls_certs(Config) ->
     PrivDir = ?config(priv_dir, Config),
     emqx_common_test_helpers:gen_ca(PrivDir, "ca"),
-    emqx_common_test_helpers:gen_host_cert("server", "ca", PrivDir, #{}),
-    emqx_common_test_helpers:gen_host_cert("client", "ca", PrivDir, #{}),
+    emqx_common_test_helpers:gen_ca(PrivDir, "ca-next"),
+    emqx_common_test_helpers:gen_host_cert("server", "ca-next", PrivDir, #{}),
+    emqx_common_test_helpers:gen_host_cert("client", "ca-next", PrivDir, #{}),
     emqx_common_test_helpers:gen_host_cert("server-password", "ca", PrivDir, #{
         password => ?SERVER_KEY_PASSWORD
     }).