emqx_authn_https_SUITE.erl 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(emqx_authn_https_SUITE).
  17. -compile(nowarn_export_all).
  18. -compile(export_all).
  19. -include("emqx_authn.hrl").
  20. -include_lib("eunit/include/eunit.hrl").
  21. -include_lib("common_test/include/ct.hrl").
  22. -include_lib("emqx/include/emqx_placeholder.hrl").
  23. -define(PATH, [?CONF_NS_ATOM]).
  24. -define(HTTPS_PORT, 32334).
  25. -define(HTTPS_PATH, "/auth").
  26. -define(CREDENTIALS, #{
  27. username => <<"plain">>,
  28. password => <<"plain">>,
  29. listener => 'tcp:default',
  30. protocol => mqtt
  31. }).
  32. all() ->
  33. emqx_common_test_helpers:all(?MODULE).
  34. init_per_suite(Config) ->
  35. _ = application:load(emqx_conf),
  36. emqx_common_test_helpers:start_apps([emqx_authn]),
  37. application:ensure_all_started(cowboy),
  38. Config.
  39. end_per_suite(_) ->
  40. emqx_authn_test_lib:delete_authenticators(
  41. [authentication],
  42. ?GLOBAL
  43. ),
  44. emqx_common_test_helpers:stop_apps([emqx_authn]),
  45. application:stop(cowboy),
  46. ok.
  47. init_per_testcase(_Case, Config) ->
  48. {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000),
  49. emqx_authn_test_lib:delete_authenticators(
  50. [authentication],
  51. ?GLOBAL
  52. ),
  53. {ok, _} = emqx_authn_http_test_server:start_link(?HTTPS_PORT, ?HTTPS_PATH, server_ssl_opts()),
  54. ok = emqx_authn_http_test_server:set_handler(fun cowboy_handler/2),
  55. Config.
  56. end_per_testcase(_Case, _Config) ->
  57. ok = emqx_authn_http_test_server:stop().
  58. %%------------------------------------------------------------------------------
  59. %% Tests
  60. %%------------------------------------------------------------------------------
  61. t_create(_Config) ->
  62. {ok, _} = create_https_auth_with_ssl_opts(
  63. #{
  64. <<"server_name_indication">> => <<"authn-server">>,
  65. <<"verify">> => <<"verify_peer">>,
  66. <<"versions">> => [<<"tlsv1.2">>],
  67. <<"ciphers">> => [<<"ECDHE-RSA-AES256-GCM-SHA384">>]
  68. }
  69. ),
  70. ?assertMatch(
  71. {ok, _},
  72. emqx_access_control:authenticate(?CREDENTIALS)
  73. ).
  74. t_create_invalid_domain(_Config) ->
  75. {ok, _} = create_https_auth_with_ssl_opts(
  76. #{
  77. <<"server_name_indication">> => <<"authn-server-unknown-host">>,
  78. <<"verify">> => <<"verify_peer">>,
  79. <<"versions">> => [<<"tlsv1.2">>],
  80. <<"ciphers">> => [<<"ECDHE-RSA-AES256-GCM-SHA384">>]
  81. }
  82. ),
  83. ?assertEqual(
  84. {error, not_authorized},
  85. emqx_access_control:authenticate(?CREDENTIALS)
  86. ).
  87. t_create_invalid_version(_Config) ->
  88. {ok, _} = create_https_auth_with_ssl_opts(
  89. #{
  90. <<"server_name_indication">> => <<"authn-server">>,
  91. <<"verify">> => <<"verify_peer">>,
  92. <<"versions">> => [<<"tlsv1.1">>]
  93. }
  94. ),
  95. ?assertEqual(
  96. {error, not_authorized},
  97. emqx_access_control:authenticate(?CREDENTIALS)
  98. ).
  99. t_create_invalid_ciphers(_Config) ->
  100. {ok, _} = create_https_auth_with_ssl_opts(
  101. #{
  102. <<"server_name_indication">> => <<"authn-server">>,
  103. <<"verify">> => <<"verify_peer">>,
  104. <<"versions">> => [<<"tlsv1.2">>],
  105. <<"ciphers">> => [<<"ECDHE-ECDSA-AES256-SHA384">>]
  106. }
  107. ),
  108. ?assertEqual(
  109. {error, not_authorized},
  110. emqx_access_control:authenticate(?CREDENTIALS)
  111. ).
  112. %%------------------------------------------------------------------------------
  113. %% Helpers
  114. %%------------------------------------------------------------------------------
  115. create_https_auth_with_ssl_opts(SpecificSSLOpts) ->
  116. AuthConfig = raw_https_auth_config(SpecificSSLOpts),
  117. emqx:update_config(?PATH, {create_authenticator, ?GLOBAL, AuthConfig}).
  118. raw_https_auth_config(SpecificSSLOpts) ->
  119. SSLOpts = maps:merge(
  120. emqx_authn_test_lib:client_ssl_cert_opts(),
  121. #{<<"enable">> => <<"true">>}
  122. ),
  123. #{
  124. <<"mechanism">> => <<"password_based">>,
  125. <<"enable">> => <<"true">>,
  126. <<"backend">> => <<"http">>,
  127. <<"method">> => <<"get">>,
  128. <<"url">> => <<"https://127.0.0.1:32334/auth">>,
  129. <<"body">> => #{<<"username">> => ?PH_USERNAME, <<"password">> => ?PH_PASSWORD},
  130. <<"headers">> => #{<<"X-Test-Header">> => <<"Test Value">>},
  131. <<"ssl">> => maps:merge(SSLOpts, SpecificSSLOpts)
  132. }.
  133. start_apps(Apps) ->
  134. lists:foreach(fun application:ensure_all_started/1, Apps).
  135. stop_apps(Apps) ->
  136. lists:foreach(fun application:stop/1, Apps).
  137. cert_path(FileName) ->
  138. Dir = code:lib_dir(emqx_authn, test),
  139. filename:join([Dir, <<"data/certs">>, FileName]).
  140. cowboy_handler(Req0, State) ->
  141. Req = cowboy_req:reply(
  142. 200,
  143. #{<<"content-type">> => <<"application/json">>},
  144. jiffy:encode(#{result => allow, is_superuser => false}),
  145. Req0
  146. ),
  147. {ok, Req, State}.
  148. server_ssl_opts() ->
  149. [
  150. {keyfile, cert_path("server.key")},
  151. {certfile, cert_path("server.crt")},
  152. {cacertfile, cert_path("ca.crt")},
  153. {verify, verify_none},
  154. {versions, ['tlsv1.2', 'tlsv1.3']},
  155. {ciphers, ["ECDHE-RSA-AES256-GCM-SHA384", "TLS_CHACHA20_POLY1305_SHA256"]}
  156. ].