From 4385b2f02015748d2467bc01ae9d86b00dd208c9 Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Tue, 7 Nov 2023 15:35:15 +0700 Subject: [PATCH] feat(pgsql): accept wrapped secrets as passwords That are coming from `emqx_schema_secret`. Also adapt pgsql-related connectors. --- .../test/emqx_bridge_pgsql_SUITE.erl | 46 +++++++++++-------- .../src/emqx_bridge_tdengine.app.src | 2 +- .../src/emqx_bridge_tdengine_connector.erl | 16 +++---- apps/emqx_postgresql/src/emqx_postgresql.erl | 3 +- 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/apps/emqx_bridge_pgsql/test/emqx_bridge_pgsql_SUITE.erl b/apps/emqx_bridge_pgsql/test/emqx_bridge_pgsql_SUITE.erl index 156d4bd16..722489ba6 100644 --- a/apps/emqx_bridge_pgsql/test/emqx_bridge_pgsql_SUITE.erl +++ b/apps/emqx_bridge_pgsql/test/emqx_bridge_pgsql_SUITE.erl @@ -183,31 +183,33 @@ pgsql_config(BridgeType, Config) -> end, QueryMode = ?config(query_mode, Config), TlsEnabled = ?config(enable_tls, Config), + %% NOTE: supplying password through a file here, to verify that it works. + Password = create_passfile(BridgeType, Config), ConfigString = io_lib:format( - "bridges.~s.~s {\n" - " enable = true\n" - " server = ~p\n" - " database = ~p\n" - " username = ~p\n" - " password = ~p\n" - " sql = ~p\n" - " resource_opts = {\n" - " request_ttl = 500ms\n" - " batch_size = ~b\n" - " query_mode = ~s\n" - " }\n" - " ssl = {\n" - " enable = ~w\n" - " }\n" - "}", + "bridges.~s.~s {" + "\n enable = true" + "\n server = ~p" + "\n database = ~p" + "\n username = ~p" + "\n password = ~p" + "\n sql = ~p" + "\n resource_opts = {" + "\n request_ttl = 500ms" + "\n batch_size = ~b" + "\n query_mode = ~s" + "\n }" + "\n ssl = {" + "\n enable = ~w" + "\n }" + "\n }", [ BridgeType, Name, Server, ?PGSQL_DATABASE, ?PGSQL_USERNAME, - ?PGSQL_PASSWORD, + Password, ?SQL_BRIDGE, BatchSize, QueryMode, @@ -216,6 +218,12 @@ pgsql_config(BridgeType, Config) -> ), {Name, parse_and_check(ConfigString, BridgeType, Name)}. +create_passfile(BridgeType, Config) -> + Filename = binary_to_list(BridgeType) ++ ".passfile", + Filepath = filename:join(?config(priv_dir, Config), Filename), + ok = file:write_file(Filepath, ?PGSQL_PASSWORD), + "file://" ++ Filepath. + parse_and_check(ConfigString, BridgeType, Name) -> {ok, RawConf} = hocon:binary(ConfigString, #{format => map}), hocon_tconf:check_plain(emqx_bridge_schema, RawConf, #{required => false, atom_key => false}), @@ -379,7 +387,9 @@ t_setup_via_http_api_and_publish(Config) -> QueryMode = ?config(query_mode, Config), PgsqlConfig = PgsqlConfig0#{ <<"name">> => Name, - <<"type">> => BridgeType + <<"type">> => BridgeType, + %% NOTE: using literal passwords with HTTP API requests. + <<"password">> => <> }, ?assertMatch( {ok, _}, diff --git a/apps/emqx_bridge_tdengine/src/emqx_bridge_tdengine.app.src b/apps/emqx_bridge_tdengine/src/emqx_bridge_tdengine.app.src index e363f2f9c..5375a6ba9 100644 --- a/apps/emqx_bridge_tdengine/src/emqx_bridge_tdengine.app.src +++ b/apps/emqx_bridge_tdengine/src/emqx_bridge_tdengine.app.src @@ -1,6 +1,6 @@ {application, emqx_bridge_tdengine, [ {description, "EMQX Enterprise TDEngine Bridge"}, - {vsn, "0.1.5"}, + {vsn, "0.1.6"}, {registered, []}, {applications, [ kernel, diff --git a/apps/emqx_bridge_tdengine/src/emqx_bridge_tdengine_connector.erl b/apps/emqx_bridge_tdengine/src/emqx_bridge_tdengine_connector.erl index dcef8506c..522007cbc 100644 --- a/apps/emqx_bridge_tdengine/src/emqx_bridge_tdengine_connector.erl +++ b/apps/emqx_bridge_tdengine/src/emqx_bridge_tdengine_connector.erl @@ -6,7 +6,6 @@ -behaviour(emqx_resource). --include_lib("emqx_resource/include/emqx_resource.hrl"). -include_lib("typerefl/include/types.hrl"). -include_lib("emqx/include/logger.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). @@ -48,8 +47,8 @@ adjust_fields(Fields) -> fun ({username, OrigUsernameFn}) -> {username, add_default_fn(OrigUsernameFn, <<"root">>)}; - ({password, OrigPasswordFn}) -> - {password, make_required_fn(OrigPasswordFn)}; + ({password, _}) -> + {password, emqx_connector_schema_lib:password_field(#{required => true})}; (Field) -> Field end, @@ -62,12 +61,6 @@ add_default_fn(OrigFn, Default) -> (Field) -> OrigFn(Field) end. -make_required_fn(OrigFn) -> - fun - (required) -> true; - (Field) -> OrigFn(Field) - end. - server() -> Meta = #{desc => ?DESC("server")}, emqx_schema:servers_sc(Meta, ?TD_HOST_OPTIONS). @@ -223,7 +216,10 @@ aggregate_query(BatchTks, BatchReqs, Acc) -> ). connect(Opts) -> - tdengine:start_link(Opts). + %% TODO: teach `tdengine` to accept 0-arity closures as passwords. + {value, {password, Secret}, OptsRest} = lists:keytake(password, 1, Opts), + NOpts = [{password, emqx_secret:unwrap(Secret)} | OptsRest], + tdengine:start_link(NOpts). query_opts(#{database := Database} = _Opts) -> [{db_name, Database}]. diff --git a/apps/emqx_postgresql/src/emqx_postgresql.erl b/apps/emqx_postgresql/src/emqx_postgresql.erl index 814d8a074..d83e3509b 100644 --- a/apps/emqx_postgresql/src/emqx_postgresql.erl +++ b/apps/emqx_postgresql/src/emqx_postgresql.erl @@ -131,7 +131,7 @@ on_start( {host, Host}, {port, Port}, {username, User}, - {password, emqx_secret:wrap(maps:get(password, Config, ""))}, + {password, maps:get(password, Config, "")}, {database, DB}, {auto_reconnect, ?AUTO_RECONNECT_INTERVAL}, {pool_size, PoolSize} @@ -357,6 +357,7 @@ validate_table_existence([], _SQL) -> connect(Opts) -> Host = proplists:get_value(host, Opts), Username = proplists:get_value(username, Opts), + %% TODO: teach `epgsql` to accept 0-arity closures as passwords. Password = emqx_secret:unwrap(proplists:get_value(password, Opts)), case epgsql:connect(Host, Username, Password, conn_opts(Opts)) of {ok, _Conn} = Ok ->