From b44512cdab40bb0ea2eb27efc36d8bcacbdd38e1 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Wed, 16 Mar 2022 10:20:09 +0800 Subject: [PATCH 1/7] fix: Add string legitimacy check. --- apps/emqx_management/src/emqx_mgmt_auth.erl | 64 +++++++++++-------- .../src/emqx_dashboard_admin.erl | 26 +++++--- .../test/emqx_dashboard_SUITE.erl | 4 +- src/emqx_misc.erl | 45 +++++++++++++ 4 files changed, 100 insertions(+), 39 deletions(-) diff --git a/apps/emqx_management/src/emqx_mgmt_auth.erl b/apps/emqx_management/src/emqx_mgmt_auth.erl index c05cbf581..6793c9885 100644 --- a/apps/emqx_management/src/emqx_mgmt_auth.erl +++ b/apps/emqx_management/src/emqx_mgmt_auth.erl @@ -89,36 +89,45 @@ add_app(AppId, Name, Desc, Status, Expired) when is_binary(AppId) -> -> {ok, appsecret()} | {error, term()}). add_app(AppId, Name, Secret, Desc, Status, Expired) when is_binary(AppId) -> - Secret1 = generate_appsecret_if_need(Secret), - App = #mqtt_app{id = AppId, - secret = Secret1, - name = Name, - desc = Desc, - status = Status, - expired = Expired}, - AddFun = fun() -> - case mnesia:wread({mqtt_app, AppId}) of - [] -> mnesia:write(App); - _ -> mnesia:abort(alread_existed) - end - end, - case mnesia:transaction(AddFun) of - {atomic, ok} -> {ok, Secret1}; - {aborted, Reason} -> {error, Reason} + case emqx_misc:valid_str(Name) of + ok -> + Secret1 = generate_appsecret_if_need(Secret), + App = #mqtt_app{id = AppId, + secret = Secret1, + name = Name, + desc = Desc, + status = Status, + expired = Expired}, + AddFun = fun() -> + case mnesia:wread({mqtt_app, AppId}) of + [] -> mnesia:write(App); + _ -> mnesia:abort(alread_existed) + end + end, + case mnesia:transaction(AddFun) of + {atomic, ok} -> {ok, Secret1}; + {aborted, Reason} -> {error, Reason} + end; + {error, Reason} -> {error, Reason} end. force_add_app(AppId, Name, Secret, Desc, Status, Expired) -> - AddFun = fun() -> - mnesia:write(#mqtt_app{id = AppId, - secret = Secret, - name = Name, - desc = Desc, - status = Status, - expired = Expired}) - end, - case mnesia:transaction(AddFun) of - {atomic, ok} -> ok; - {aborted, Reason} -> {error, Reason} + case emqx_misc:valid_str(Name) of + ok -> + AddFun = fun() -> + mnesia:write(#mqtt_app{ + id = AppId, + secret = Secret, + name = Name, + desc = Desc, + status = Status, + expired = Expired}) + end, + case mnesia:transaction(AddFun) of + {atomic, ok} -> ok; + {aborted, Reason} -> {error, Reason} + end; + {error, Reason} -> {error, Reason} end. -spec(generate_appsecret_if_need(binary() | undefined) -> binary()). @@ -207,4 +216,3 @@ is_authorized(AppId, AppSecret) -> is_expired(undefined) -> true; is_expired(Expired) -> Expired >= erlang:system_time(second). - diff --git a/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl b/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl index c9e9bee3c..7ce1f564f 100644 --- a/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl +++ b/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl @@ -78,18 +78,24 @@ start_link() -> -spec(add_user(binary(), binary(), binary()) -> ok | {error, any()}). add_user(Username, Password, Tags) when is_binary(Username), is_binary(Password) -> - Admin = #mqtt_admin{username = Username, password = hash(Password), tags = Tags}, - return(mnesia:transaction(fun add_user_/1, [Admin])). + case emqx_misc:valid_str(Username) of + ok -> + Admin = #mqtt_admin{username = Username, password = hash(Password), tags = Tags}, + return(mnesia:transaction(fun add_user_/1, [Admin])); + {error, Reason} -> {error, Reason} + end. force_add_user(Username, Password, Tags) -> - AddFun = fun() -> - mnesia:write(#mqtt_admin{username = Username, - password = Password, - tags = Tags}) - end, - case mnesia:transaction(AddFun) of - {atomic, ok} -> ok; - {aborted, Reason} -> {error, Reason} + case emqx_misc:valid_str(Username) of + ok -> + AddFun = fun() -> + mnesia:write(#mqtt_admin{username = Username, password = Password, tags = Tags}) + end, + case mnesia:transaction(AddFun) of + {atomic, ok} -> ok; + {aborted, Reason} -> {error, Reason} + end; + {error, Reason} -> {error, Reason} end. %% @private diff --git a/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl b/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl index ef2e747fa..3bca197f0 100644 --- a/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl +++ b/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl @@ -67,6 +67,9 @@ t_overview(_) -> t_admins_add_delete(_) -> ok = emqx_dashboard_admin:add_user(<<"username">>, <<"password">>, <<"tag">>), ok = emqx_dashboard_admin:add_user(<<"username1">>, <<"password1">>, <<"tag1">>), + {error, _} = emqx_dashboard_admin:add_user(<<"1username1">>, <<"password1">>, <<"tag1">>), + {error, _} = emqx_dashboard_admin:add_user(<<"u/sername1">>, <<"password1">>, <<"tag1">>), + {error, _} = emqx_dashboard_admin:add_user(<<"/username1">>, <<"password1">>, <<"tag1">>), Admins = emqx_dashboard_admin:all_users(), ?assertEqual(3, length(Admins)), ok = emqx_dashboard_admin:remove_user(<<"username1">>), @@ -165,4 +168,3 @@ api_path(Path) -> json(Data) -> {ok, Jsx} = emqx_json:safe_decode(Data, [return_maps]), Jsx. - diff --git a/src/emqx_misc.erl b/src/emqx_misc.erl index eb6a25377..8c76ff4a6 100644 --- a/src/emqx_misc.erl +++ b/src/emqx_misc.erl @@ -52,6 +52,26 @@ , hexstr2bin/1 ]). +-export([ valid_str/1 + ]). + +-define(VALID_STR_RE, "^[A-Za-z]+[A-Za-z0-9-_]*$"). + +-spec valid_str(list() | binary()) -> ok | {error, Reason::binary()}. +valid_str(Str) -> + StrLen = len(Str), + case StrLen > 0 andalso StrLen =< 256 of + true -> + case re:run(Str, ?VALID_STR_RE) of + nomatch -> {error, <<"required: " ?VALID_STR_RE>>}; + _ -> ok + end; + false -> {error, <<"0 < Length =< 256">>} + end. + +len(Bin) when is_binary(Bin) -> byte_size(Bin); +len(Str) when is_list(Str) -> length(Str). + -define(OOM_FACTOR, 1.25). %% @doc Parse v4 or v6 string format address to tuple. @@ -309,4 +329,29 @@ hexchar2int(I) when I >= $a andalso I =< $f -> I - $a + 10. ipv6_probe_test() -> ?assertEqual([{ipv6_probe, true}], ipv6_probe([])). +valid_str_test() -> + ?assertMatch({error, _}, valid_str("")), + ?assertMatch({error, _}, valid_str("_")), + ?assertMatch({error, _}, valid_str("_aaa")), + ?assertMatch({error, _}, valid_str("lkad/oddl")), + ?assertMatch({error, _}, valid_str("lkad*oddl")), + ?assertMatch({error, _}, valid_str("