diff --git a/apps/emqx/src/emqx_schema.erl b/apps/emqx/src/emqx_schema.erl index b6390081b..8f016f684 100644 --- a/apps/emqx/src/emqx_schema.erl +++ b/apps/emqx/src/emqx_schema.erl @@ -114,6 +114,7 @@ -export([namespace/0, roots/0, roots/1, fields/1, desc/1, tags/0]). -export([conf_get/2, conf_get/3, keys/2, filter/1]). -export([server_ssl_opts_schema/2, client_ssl_opts_schema/1, ciphers_schema/1]). +-export([password_converter/2, bin_str_converter/2]). -export([authz_fields/0]). -export([sc/2, map/2]). @@ -1510,7 +1511,9 @@ fields("sysmon_top") -> #{ mapping => "system_monitor.db_password", default => "system_monitor_password", - desc => ?DESC(sysmon_top_db_password) + desc => ?DESC(sysmon_top_db_password), + converter => fun password_converter/2, + sensitive => true } )}, {"db_name", @@ -1900,7 +1903,8 @@ common_ssl_opts_schema(Defaults) -> required => false, example => <<"">>, format => <<"password">>, - desc => ?DESC(common_ssl_opts_schema_password) + desc => ?DESC(common_ssl_opts_schema_password), + converter => fun password_converter/2 } )}, {"versions", @@ -2068,6 +2072,21 @@ do_default_ciphers(_) -> %% otherwise resolve default ciphers list at runtime []. +password_converter(X, Opts) -> + bin_str_converter(X, Opts). + +bin_str_converter(undefined, _) -> + undefined; +bin_str_converter(I, _) when is_integer(I) -> + integer_to_binary(I); +bin_str_converter(X, _) -> + try + iolist_to_binary(X) + catch + _:_ -> + throw("must_quote") + end. + authz_fields() -> [ {"no_match", diff --git a/apps/emqx/test/emqx_schema_tests.erl b/apps/emqx/test/emqx_schema_tests.erl index b249dea92..e1ac1874f 100644 --- a/apps/emqx/test/emqx_schema_tests.erl +++ b/apps/emqx/test/emqx_schema_tests.erl @@ -465,3 +465,10 @@ converter_invalid_input_test() -> ?assertEqual(undefined, emqx_schema:convert_servers(undefined)), %% 'foo: bar' is a valid HOCON value, but 'bar' is not a port number ?assertThrow("bad_host_port", emqx_schema:convert_servers(#{foo => bar})). + +password_converter_test() -> + ?assertEqual(undefined, emqx_schema:password_converter(undefined, #{})), + ?assertEqual(<<"123">>, emqx_schema:password_converter(123, #{})), + ?assertEqual(<<"123">>, emqx_schema:password_converter(<<"123">>, #{})), + ?assertThrow("must_quote", emqx_schema:password_converter(foobar, #{})), + ok. diff --git a/apps/emqx_authn/test/emqx_authn_SUITE.erl b/apps/emqx_authn/test/emqx_authn_SUITE.erl index 6b24f7231..b30d2fcff 100644 --- a/apps/emqx_authn/test/emqx_authn_SUITE.erl +++ b/apps/emqx_authn/test/emqx_authn_SUITE.erl @@ -98,6 +98,7 @@ t_will_message_connection_denied(Config) when is_list(Config) -> {will_payload, <<"should not be published">>} ]), Ref = monitor(process, Publisher), + _ = unlink(Publisher), {error, _} = emqtt:connect(Publisher), receive {'DOWN', Ref, process, Publisher, Reason} -> diff --git a/apps/emqx_conf/src/emqx_conf_schema.erl b/apps/emqx_conf/src/emqx_conf_schema.erl index 06ec7478a..bc9154933 100644 --- a/apps/emqx_conf/src/emqx_conf_schema.erl +++ b/apps/emqx_conf/src/emqx_conf_schema.erl @@ -408,7 +408,8 @@ fields("node") -> required => true, 'readOnly' => true, sensitive => true, - desc => ?DESC(node_cookie) + desc => ?DESC(node_cookie), + converter => fun emqx_schema:password_converter/2 } )}, {"process_limit", diff --git a/apps/emqx_connector/src/emqx_connector_schema_lib.erl b/apps/emqx_connector/src/emqx_connector_schema_lib.erl index 5d8f6941c..f64208311 100644 --- a/apps/emqx_connector/src/emqx_connector_schema_lib.erl +++ b/apps/emqx_connector/src/emqx_connector_schema_lib.erl @@ -101,6 +101,7 @@ password(desc) -> ?DESC("password"); password(required) -> false; password(format) -> <<"password">>; password(sensitive) -> true; +password(converter) -> fun emqx_schema:password_converter/2; password(_) -> undefined. auto_reconnect(type) -> boolean(); diff --git a/apps/emqx_connector/src/mqtt/emqx_connector_mqtt_schema.erl b/apps/emqx_connector/src/mqtt/emqx_connector_mqtt_schema.erl index 5e833aa99..be462fcc1 100644 --- a/apps/emqx_connector/src/mqtt/emqx_connector_mqtt_schema.erl +++ b/apps/emqx_connector/src/mqtt/emqx_connector_mqtt_schema.erl @@ -107,7 +107,8 @@ fields("server_configs") -> #{ format => <<"password">>, sensitive => true, - desc => ?DESC("password") + desc => ?DESC("password"), + converter => fun emqx_schema:password_converter/2 } )}, {clean_start, diff --git a/apps/emqx_dashboard/src/emqx_dashboard_schema.erl b/apps/emqx_dashboard/src/emqx_dashboard_schema.erl index 90a9742cd..5a2eb590b 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_schema.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_schema.erl @@ -209,6 +209,7 @@ default_password(default) -> "public"; default_password(required) -> true; default_password('readOnly') -> true; default_password(sensitive) -> true; +default_password(converter) -> fun emqx_schema:password_converter/2; default_password(desc) -> ?DESC(default_password); default_password(_) -> undefined. diff --git a/apps/emqx_gateway/src/emqx_gateway_schema.erl b/apps/emqx_gateway/src/emqx_gateway_schema.erl index 804e1f862..4ea845ea1 100644 --- a/apps/emqx_gateway/src/emqx_gateway_schema.erl +++ b/apps/emqx_gateway/src/emqx_gateway_schema.erl @@ -380,7 +380,13 @@ fields(ssl_server_opts) -> fields(clientinfo_override) -> [ {username, sc(binary(), #{desc => ?DESC(gateway_common_clientinfo_override_username)})}, - {password, sc(binary(), #{desc => ?DESC(gateway_common_clientinfo_override_password)})}, + {password, + sc(binary(), #{ + desc => ?DESC(gateway_common_clientinfo_override_password), + sensitive => true, + format => <<"password">>, + converter => fun emqx_schema:password_converter/2 + })}, {clientid, sc(binary(), #{desc => ?DESC(gateway_common_clientinfo_override_clientid)})} ]; fields(lwm2m_translators) -> diff --git a/changes/v5.0.15/fix-9765.en.md b/changes/v5.0.15/fix-9765.en.md new file mode 100644 index 000000000..7de7e55f3 --- /dev/null +++ b/changes/v5.0.15/fix-9765.en.md @@ -0,0 +1,6 @@ +Parse decimals as password from environment variable overrides correctly. +Prior to this change, config values for passwords are not allowed to be decimals. +e.g. `EMQX_FOOBAR__PASSWORD=12344` or `emqx.foobar.password=1234` +would result in a type check error, unless quoted as: +`EMQX_FOOBAR__PASSWORD='"12344"'` or `emqx.foobar.password="1234"`. +After this fix, the value does not have to be quoted. diff --git a/changes/v5.0.15/fix-9765.zh.md b/changes/v5.0.15/fix-9765.zh.md new file mode 100644 index 000000000..dd0b6a79c --- /dev/null +++ b/changes/v5.0.15/fix-9765.zh.md @@ -0,0 +1,7 @@ +允许使用纯数字作为密码配置。 +在此修复前,密码的配置必须是字符串,使用纯数字时,会报类型检查错误。 +例如,`EMQX_FOOBAR__PASSWORD=12344` 或 `emqx.foobar.password=1234` 会出错, +必须用引把值括起来才行: +`EMQX_FOOBAR__PASSWORD='"12344"'` 或 `emqx.foobar.password="1234"`。 +修复后可以不使用引号。在环境变量重载中使用更加方便。 + diff --git a/lib-ee/emqx_ee_bridge/src/emqx_ee_bridge_kafka.erl b/lib-ee/emqx_ee_bridge/src/emqx_ee_bridge_kafka.erl index 4a6c1411c..e694f6c15 100644 --- a/lib-ee/emqx_ee_bridge/src/emqx_ee_bridge_kafka.erl +++ b/lib-ee/emqx_ee_bridge/src/emqx_ee_bridge_kafka.erl @@ -116,7 +116,12 @@ fields(auth_username_password) -> })}, {username, mk(binary(), #{required => true, desc => ?DESC(auth_sasl_username)})}, {password, - mk(binary(), #{required => true, sensitive => true, desc => ?DESC(auth_sasl_password)})} + mk(binary(), #{ + required => true, + sensitive => true, + desc => ?DESC(auth_sasl_password), + converter => fun emqx_schema:password_converter/2 + })} ]; fields(auth_gssapi_kerberos) -> [ diff --git a/lib-ee/emqx_ee_connector/src/emqx_ee_connector_influxdb.erl b/lib-ee/emqx_ee_connector/src/emqx_ee_connector_influxdb.erl index 0d21b381e..0037242b3 100644 --- a/lib-ee/emqx_ee_connector/src/emqx_ee_connector_influxdb.erl +++ b/lib-ee/emqx_ee_connector/src/emqx_ee_connector_influxdb.erl @@ -157,7 +157,13 @@ fields(influxdb_api_v1) -> [ {database, mk(binary(), #{required => true, desc => ?DESC("database")})}, {username, mk(binary(), #{desc => ?DESC("username")})}, - {password, mk(binary(), #{desc => ?DESC("password"), format => <<"password">>})} + {password, + mk(binary(), #{ + desc => ?DESC("password"), + format => <<"password">>, + sensitive => true, + converter => fun emqx_schema:password_converter/2 + })} ] ++ emqx_connector_schema_lib:ssl_fields(); fields(influxdb_api_v2) -> fields(common) ++