From a1aa9a43750e9f7bba8510015a1c6f9e6888bfd9 Mon Sep 17 00:00:00 2001 From: William Yang Date: Fri, 7 Jun 2024 23:27:20 +0200 Subject: [PATCH] fix(ee): emqx no longer deps on emqx_auth_ext --- apps/emqx/include/emqx_schema.hrl | 5 ++ apps/emqx/src/emqx_listeners.erl | 23 ++----- apps/emqx/src/emqx_tls_lib.erl | 14 ++++ apps/emqx_auth_ext/src/emqx_auth_ext.erl | 22 +++++++ .../test/emqx_auth_ext_schema_SUITE.erl | 66 +++++++++++++++++++ apps/emqx_gateway/src/emqx_gateway_utils.erl | 14 +--- 6 files changed, 113 insertions(+), 31 deletions(-) create mode 100644 apps/emqx_auth_ext/test/emqx_auth_ext_schema_SUITE.erl diff --git a/apps/emqx/include/emqx_schema.hrl b/apps/emqx/include/emqx_schema.hrl index b0d465e9c..9f9b09b9d 100644 --- a/apps/emqx/include/emqx_schema.hrl +++ b/apps/emqx/include/emqx_schema.hrl @@ -21,4 +21,9 @@ -define(TOMBSTONE_CONFIG_CHANGE_REQ, mark_it_for_deletion). -define(CONFIG_NOT_FOUND_MAGIC, '$0tFound'). +%%-------------------------------------------------------------------- +%% EE injections +%%-------------------------------------------------------------------- +-define(EMQX_SSL_FUN_MFA(Name), {emqx_ssl_fun_mfa, Name}). + -endif. diff --git a/apps/emqx/src/emqx_listeners.erl b/apps/emqx/src/emqx_listeners.erl index aa4fe1516..e325263c5 100644 --- a/apps/emqx/src/emqx_listeners.erl +++ b/apps/emqx/src/emqx_listeners.erl @@ -75,10 +75,6 @@ -define(TYPES_STRING, ["tcp", "ssl", "ws", "wss", "quic"]). -define(MARK_DEL, ?TOMBSTONE_CONFIG_CHANGE_REQ). --ifndef(EMQX_RELEASE_EDITION). --define(EMQX_RELEASE_EDITION, ce). --endif. - -spec id_example() -> atom(). id_example() -> 'tcp:default'. @@ -978,21 +974,10 @@ quic_listener_optional_settings() -> stateless_operation_expiration_ms ]. --if(?EMQX_RELEASE_EDITION == ee). -inject_root_fun(#{ssl_options := SslOpts} = Opts) -> - Opts#{ssl_options := emqx_auth_ext_tls_lib:opt_partial_chain(SslOpts)}. --else. -inject_root_fun(Opts) -> - Opts. --endif. - --if(?EMQX_RELEASE_EDITION == ee). -inject_verify_fun(#{ssl_options := SslOpts} = Opts) -> - Opts#{ssl_options := emqx_auth_ext_tls_lib:opt_verify_fun(SslOpts)}. --else. -inject_verify_fun(Opts) -> - Opts. --endif. +inject_root_fun(#{ssl_options := SSLOpts} = Opts) -> + Opts#{ssl_options := emqx_tls_lib:maybe_inject_ssl_fun(root_fun, SSLOpts)}. +inject_verify_fun(#{ssl_options := SSLOpts} = Opts) -> + Opts#{ssl_options := emqx_tls_lib:maybe_inject_ssl_fun(verify_fun, SSLOpts)}. inject_sni_fun(ListenerId, Conf = #{ssl_options := #{ocsp := #{enable_ocsp_stapling := true}}}) -> emqx_ocsp_cache:inject_sni_fun(ListenerId, Conf); diff --git a/apps/emqx/src/emqx_tls_lib.erl b/apps/emqx/src/emqx_tls_lib.erl index 57d26220d..e1de50385 100644 --- a/apps/emqx/src/emqx_tls_lib.erl +++ b/apps/emqx/src/emqx_tls_lib.erl @@ -45,10 +45,13 @@ to_client_opts/2 ]). +-export([maybe_inject_ssl_fun/2]). + %% ssl:tls_version/0 is not exported. -type tls_version() :: tlsv1 | 'tlsv1.1' | 'tlsv1.2' | 'tlsv1.3'. -include("logger.hrl"). +-include("emqx_schema.hrl"). -define(IS_TRUE(Val), ((Val =:= true) orelse (Val =:= <<"true">>))). -define(IS_FALSE(Val), ((Val =:= false) orelse (Val =:= <<"false">>))). @@ -686,3 +689,14 @@ ensure_ssl_file_key(SSL, RequiredKeyPaths) -> [] -> ok; Miss -> {error, #{reason => ssl_file_option_not_found, which_options => Miss}} end. + +-spec maybe_inject_ssl_fun(root_fun | verify_fun, map()) -> map(). +maybe_inject_ssl_fun(FunName, SslOpts) -> + case persistent_term:get(?EMQX_SSL_FUN_MFA(FunName), undefined) of + undefined -> + SslOpts; + {M, F, A} -> + %% We should have one entry not a list of {M,F,A}, + %% as ordering matters in validations + erlang:apply(M, F, [SslOpts | A]) + end. diff --git a/apps/emqx_auth_ext/src/emqx_auth_ext.erl b/apps/emqx_auth_ext/src/emqx_auth_ext.erl index c6385dd63..3558be4a5 100644 --- a/apps/emqx_auth_ext/src/emqx_auth_ext.erl +++ b/apps/emqx_auth_ext/src/emqx_auth_ext.erl @@ -3,4 +3,26 @@ %%-------------------------------------------------------------------- -module(emqx_auth_ext). +-include_lib("emqx/include/emqx_schema.hrl"). + +-on_load(on_load/0). + -export([]). + +-spec on_load() -> ok. +on_load() -> + init_ssl_fun_cb(). + +init_ssl_fun_cb() -> + lists:foreach( + fun({FunName, {_, _, _} = MFA}) -> + persistent_term:put( + ?EMQX_SSL_FUN_MFA(FunName), + MFA + ) + end, + [ + {root_fun, {emqx_auth_ext_tls_lib, opt_partial_chain, []}}, + {verify_fun, {emqx_auth_ext_tls_lib, opt_verify_fun, []}} + ] + ). diff --git a/apps/emqx_auth_ext/test/emqx_auth_ext_schema_SUITE.erl b/apps/emqx_auth_ext/test/emqx_auth_ext_schema_SUITE.erl new file mode 100644 index 000000000..b47f5fa39 --- /dev/null +++ b/apps/emqx_auth_ext/test/emqx_auth_ext_schema_SUITE.erl @@ -0,0 +1,66 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- +-module(emqx_auth_ext_schema_SUITE). +-compile(nowarn_export_all). +-compile(export_all). + +-include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). + +-define(BASE_CONF, + "\n" + " listeners.ssl.auth_ext.bind = 28883\n" + " listeners.ssl.auth_ext.enable = true\n" + " listeners.ssl.auth_ext.ssl_options.partial_chain = true\n" + " listeners.ssl.auth_ext.ssl_options.verify = verify_peer\n" + " listeners.ssl.auth_ext.ssl_options.verify_peer_ext_key_usage = \"clientAuth\"\n" + " " +). + +all() -> + emqx_common_test_helpers:all(?MODULE). + +init_per_suite(Config) -> + %% injection happens when module is loaded. + code:load_file(emqx_auth_ext), + Apps = emqx_cth_suite:start( + [ + emqx, + {emqx_conf, ?BASE_CONF} + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + emqx_listeners:restart(), + [{apps, Apps} | Config]. + +end_per_suite(Config) -> + Apps = ?config(apps, Config), + ok = emqx_cth_suite:stop(Apps), + code:delete(emqx_auth_ext), + code:purge(emqx_auth_ext), + ok. + +t_conf_check_default(_Config) -> + Opts = esockd:get_options({'ssl:default', {{0, 0, 0, 0}, 8883}}), + SSLOpts = proplists:get_value(ssl_options, Opts), + ?assertEqual(none, proplists:lookup(partial_chain, SSLOpts)), + ?assertEqual(none, proplists:lookup(verify_fun, SSLOpts)). + +t_conf_check_auth_ext(_Config) -> + Opts = esockd:get_options({'ssl:auth_ext', 28883}), + SSLOpts = proplists:get_value(ssl_options, Opts), + ?assertMatch(Fun when is_function(Fun), proplists:get_value(partial_chain, SSLOpts)), + ?assertMatch({Fun, _} when is_function(Fun), proplists:get_value(verify_fun, SSLOpts)). diff --git a/apps/emqx_gateway/src/emqx_gateway_utils.erl b/apps/emqx_gateway/src/emqx_gateway_utils.erl index 28208683d..e6a5be8ab 100644 --- a/apps/emqx_gateway/src/emqx_gateway_utils.erl +++ b/apps/emqx_gateway/src/emqx_gateway_utils.erl @@ -588,21 +588,11 @@ ssl_server_opts(SSLOpts, ssl_options) -> ssl_server_opts(SSLOpts, dtls_options) -> emqx_tls_lib:to_server_opts(dtls, SSLOpts). --if(defined(EMQX_RELEASE_EDITION) andalso ?EMQX_RELEASE_EDITION == ee). ssl_partial_chain(SSLOpts, _Options) -> - emqx_auth_ext_tls_lib:opt_partial_chain(SSLOpts). --else. -ssl_partial_chain(SSLOpts, _) -> - SSLOpts. --endif. + emqx_tls_lib:maybe_inject_ssl_fun(root_fun, SSLOpts). --if(defined(EMQX_RELEASE_EDITION) andalso ?EMQX_RELEASE_EDITION == ee). ssl_verify_fun(SSLOpts, _Options) -> - emqx_auth_ext_tls_lib:opt_verify_fun(SSLOpts). --else. -ssl_verify_fun(SSLOpts, _) -> - SSLOpts. --endif. + emqx_tls_lib:maybe_inject_ssl_fun(verify_fun, SSLOpts). ranch_opts(Type, ListenOn, Opts) -> NumAcceptors = maps:get(acceptors, Opts, 4),