From 319d08678ed95bd63c17b1973e1c25de724f33a5 Mon Sep 17 00:00:00 2001 From: "Zaiming (Stone) Shi" Date: Tue, 8 Feb 2022 13:59:10 +0100 Subject: [PATCH 1/4] chore: update license year --- lib-ee/emqx_license/include/emqx_license.hrl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib-ee/emqx_license/include/emqx_license.hrl b/lib-ee/emqx_license/include/emqx_license.hrl index 72f862a59..c6fea77d8 100644 --- a/lib-ee/emqx_license/include/emqx_license.hrl +++ b/lib-ee/emqx_license/include/emqx_license.hrl @@ -1,5 +1,5 @@ %%-------------------------------------------------------------------- -%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved. +%% Copyright (c) 2022 EMQ Technologies Co., Ltd. All Rights Reserved. %% %% @doc EMQ X License Management CLI. %%-------------------------------------------------------------------- From c936706a1fbf1850e363e4a28c016d8f939350d7 Mon Sep 17 00:00:00 2001 From: "Zaiming (Stone) Shi" Date: Tue, 8 Feb 2022 13:57:27 +0100 Subject: [PATCH 2/4] refactor(emqx_license): log a different msg when license is not loaded --- lib-ee/emqx_license/include/emqx_license.hrl | 1 + lib-ee/emqx_license/src/emqx_license.erl | 18 +++++++++++------- .../emqx_license/src/emqx_license_checker.erl | 15 +++++++-------- .../test/emqx_license_checker_SUITE.erl | 12 ++++++------ 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/lib-ee/emqx_license/include/emqx_license.hrl b/lib-ee/emqx_license/include/emqx_license.hrl index c6fea77d8..a906b7b4e 100644 --- a/lib-ee/emqx_license/include/emqx_license.hrl +++ b/lib-ee/emqx_license/include/emqx_license.hrl @@ -35,4 +35,5 @@ -define(EXPIRED_DAY, -90). +-define(ERR_EXPIRED, expired). -endif. diff --git a/lib-ee/emqx_license/src/emqx_license.erl b/lib-ee/emqx_license/src/emqx_license.erl index be59c21e7..7af94af3f 100644 --- a/lib-ee/emqx_license/src/emqx_license.erl +++ b/lib-ee/emqx_license/src/emqx_license.erl @@ -3,6 +3,7 @@ %%-------------------------------------------------------------------- -module(emqx_license). +-include("emqx_license.hrl"). -include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/emqx_mqtt.hrl"). -include_lib("typerefl/include/types.hrl"). @@ -67,19 +68,22 @@ update_key(Value) when is_binary(Value); is_list(Value) -> %%------------------------------------------------------------------------------ check(_ConnInfo, AckProps) -> - #{max_connections := MaxClients} = emqx_license_checker:limits(), - case MaxClients of - 0 -> - ?SLOG(error, #{msg => "Connection rejected due to the license expiration"}), + case emqx_license_checker:limits() of + {ok, #{max_connections := ?ERR_EXPIRED}} -> + ?SLOG(error, #{msg => "connection_rejected_due_to_license_expired"}), {stop, {error, ?RC_QUOTA_EXCEEDED}}; - _ -> + {ok, #{max_connections := MaxClients}} -> case check_max_clients_exceeded(MaxClients) of true -> - ?SLOG(error, #{msg => "Connection rejected due to max clients limitation"}), + ?SLOG(error, #{msg => "connection_rejected_due_to_license_limit_reached"}), {stop, {error, ?RC_QUOTA_EXCEEDED}}; false -> {ok, AckProps} - end + end; + {error, Reason} -> + ?SLOG(error, #{msg => "connection_rejected_due_to_license_not_loaded", + reason => Reason}), + {stop, {error, ?RC_QUOTA_EXCEEDED}} end. %%------------------------------------------------------------------------------ diff --git a/lib-ee/emqx_license/src/emqx_license_checker.erl b/lib-ee/emqx_license/src/emqx_license_checker.erl index 99cc8406e..b54289658 100644 --- a/lib-ee/emqx_license/src/emqx_license_checker.erl +++ b/lib-ee/emqx_license/src/emqx_license_checker.erl @@ -27,7 +27,7 @@ %% API %%------------------------------------------------------------------------------ --type limits() :: #{max_connections := non_neg_integer()}. +-type limits() :: #{max_connections := non_neg_integer() | ?ERR_EXPIRED}. -spec start_link(emqx_license_parser:license()) -> {ok, pid()}. start_link(LicenseFetcher) -> @@ -45,13 +45,14 @@ update(License) -> dump() -> gen_server:call(?MODULE, dump). --spec limits() -> limits(). +-spec limits() -> {ok, limits()} | {error, any()}. limits() -> try ets:lookup(?MODULE, limits) of - [{limits, Limits}] -> Limits; - _ -> default_limits() + [{limits, Limits}] -> {ok, Limits}; + _ -> {error, no_license} catch - error:badarg -> default_limits() + error : badarg -> + {error, no_license} end. %%------------------------------------------------------------------------------ @@ -116,9 +117,7 @@ warn_evaluation(_License, _NeedRestrict) -> false. warn_expiry(_License, NeedRestrict) -> NeedRestrict. limits(License, false) -> #{max_connections => emqx_license_parser:max_connections(License)}; -limits(_License, true) -> #{max_connections => 0}. - -default_limits() -> #{max_connections => 0}. +limits(_License, true) -> #{max_connections => ?ERR_EXPIRED}. days_left(License) -> DateEnd = emqx_license_parser:expiry_date(License), diff --git a/lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl index ad8c39187..0790b8f13 100644 --- a/lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl @@ -47,7 +47,7 @@ set_special_configs(_) -> ok. %%------------------------------------------------------------------------------ t_default_limits(_Config) -> - ?assertMatch(#{max_connections := 0}, emqx_license_checker:limits()). + ?assertMatch({error, no_license}, emqx_license_checker:limits()). t_dump(_Config) -> License = mk_license( @@ -86,7 +86,7 @@ t_update(_Config) -> #{} = emqx_license_checker:update(License), ?assertMatch( - #{max_connections := 123}, + {ok, #{max_connections := 123}}, emqx_license_checker:limits()). t_update_by_timer(_Config) -> @@ -122,7 +122,7 @@ t_expired_trial(_Config) -> #{} = emqx_license_checker:update(License), ?assertMatch( - #{max_connections := 0}, + {ok, #{max_connections := expired}}, emqx_license_checker:limits()). t_overexpired_small_client(_Config) -> @@ -142,7 +142,7 @@ t_overexpired_small_client(_Config) -> #{} = emqx_license_checker:update(License), ?assertMatch( - #{max_connections := 0}, + {ok, #{max_connections := expired}}, emqx_license_checker:limits()). t_overexpired_medium_client(_Config) -> @@ -162,7 +162,7 @@ t_overexpired_medium_client(_Config) -> #{} = emqx_license_checker:update(License), ?assertMatch( - #{max_connections := 123}, + {ok, #{max_connections := 123}}, emqx_license_checker:limits()). t_recently_expired_small_client(_Config) -> @@ -182,7 +182,7 @@ t_recently_expired_small_client(_Config) -> #{} = emqx_license_checker:update(License), ?assertMatch( - #{max_connections := 123}, + {ok, #{max_connections := 123}}, emqx_license_checker:limits()). t_unknown_calls(_Config) -> From ae9c8098ba8ef340f45658c42465dc73634b3ee3 Mon Sep 17 00:00:00 2001 From: "Zaiming (Stone) Shi" Date: Tue, 8 Feb 2022 17:17:47 +0100 Subject: [PATCH 3/4] test: ensure coverage for the `no_license` case --- .../emqx_license/src/emqx_license_checker.erl | 23 +++++++++++++------ .../emqx_license/test/emqx_license_SUITE.erl | 6 +++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib-ee/emqx_license/src/emqx_license_checker.erl b/lib-ee/emqx_license/src/emqx_license_checker.erl index b54289658..5571eaada 100644 --- a/lib-ee/emqx_license/src/emqx_license_checker.erl +++ b/lib-ee/emqx_license/src/emqx_license_checker.erl @@ -15,6 +15,7 @@ start_link/2, update/1, dump/0, + purge/0, limits/0]). %% gen_server callbacks @@ -23,6 +24,8 @@ handle_cast/2, handle_info/2]). +-define(LICENSE_TAB, emqx_license). + %%------------------------------------------------------------------------------ %% API %%------------------------------------------------------------------------------ @@ -39,15 +42,15 @@ start_link(LicenseFetcher, CheckInterval) -> -spec update(emqx_license_parser:license()) -> ok. update(License) -> - gen_server:call(?MODULE, {update, License}). + gen_server:call(?MODULE, {update, License}, infinity). -spec dump() -> [{atom(), term()}]. dump() -> - gen_server:call(?MODULE, dump). + gen_server:call(?MODULE, dump, infinity). -spec limits() -> {ok, limits()} | {error, any()}. limits() -> - try ets:lookup(?MODULE, limits) of + try ets:lookup(?LICENSE_TAB, limits) of [{limits, Limits}] -> {ok, Limits}; _ -> {error, no_license} catch @@ -55,6 +58,11 @@ limits() -> {error, no_license} end. +%% @doc Force purge the license table. +-spec purge() -> ok. +purge() -> + gen_server:call(?MODULE, purge, infinity). + %%------------------------------------------------------------------------------ %% gen_server callbacks %%------------------------------------------------------------------------------ @@ -62,7 +70,7 @@ limits() -> init([LicenseFetcher, CheckInterval]) -> case LicenseFetcher() of {ok, License} -> - _ = ets:new(?MODULE, [set, protected, named_table]), + ?LICENSE_TAB = ets:new(?LICENSE_TAB, [set, protected, named_table]), #{} = check_license(License), State = ensure_timer(#{check_license_interval => CheckInterval, license => License}), @@ -73,10 +81,11 @@ init([LicenseFetcher, CheckInterval]) -> handle_call({update, License}, _From, State) -> {reply, check_license(License), State#{license => License}}; - handle_call(dump, _From, #{license := License} = State) -> {reply, emqx_license_parser:dump(License), State}; - +handle_call(purge, _From, State) -> + _ = ets:delete_all_objects(?LICENSE_TAB), + {reply, ok, State}; handle_call(_Req, _From, State) -> {reply, unknown, State}. @@ -137,4 +146,4 @@ small_customer_overexpired(?SMALL_CUSTOMER, DaysLeft) small_customer_overexpired(_CType, _DaysLeft) -> false. apply_limits(Limits) -> - ets:insert(?MODULE, {limits, Limits}). + ets:insert(?LICENSE_TAB, {limits, Limits}). diff --git a/lib-ee/emqx_license/test/emqx_license_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_SUITE.erl index 1ca7d265f..908b90569 100644 --- a/lib-ee/emqx_license/test/emqx_license_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_SUITE.erl @@ -153,6 +153,12 @@ t_check_expired(_Config) -> {stop, {error, ?RC_QUOTA_EXCEEDED}}, emqx_license:check(#{}, #{})). +t_check_not_loaded(_Config) -> + ok = emqx_license_checker:purge(), + ?assertEqual( + {stop, {error, ?RC_QUOTA_EXCEEDED}}, + emqx_license:check(#{}, #{})). + %%------------------------------------------------------------------------------ %% Helpers %%------------------------------------------------------------------------------ From 4cee12614ba3e5030e22ed62bb07f3bc2d42e907 Mon Sep 17 00:00:00 2001 From: "Zaiming (Stone) Shi" Date: Tue, 8 Feb 2022 17:22:10 +0100 Subject: [PATCH 4/4] fix: mark license key sensitive so it's not logged to console when environment variable is used --- lib-ee/emqx_license/src/emqx_license_schema.erl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib-ee/emqx_license/src/emqx_license_schema.erl b/lib-ee/emqx_license/src/emqx_license_schema.erl index 2e3c56e49..bd4a471f4 100644 --- a/lib-ee/emqx_license/src/emqx_license_schema.erl +++ b/lib-ee/emqx_license/src/emqx_license_schema.erl @@ -19,9 +19,13 @@ roots() -> [{license, hoconsc:union( hoconsc:ref(?MODULE, file_license)])}]. fields(key_license) -> - [ {key, string()} + [ {key, #{type => string(), + sensitive => true, %% so it's not logged + desc => "Configure the license as a string" + }} ]; - fields(file_license) -> - [ {file, string()} + [ {file, #{type => string(), + desc => "Path to the license file" + }} ].