diff --git a/apps/emqx_authn/src/enhanced_authn/emqx_enhanced_authn_scram_mnesia.erl b/apps/emqx_authn/src/enhanced_authn/emqx_enhanced_authn_scram_mnesia.erl index d7c3507e6..23fc99ecb 100644 --- a/apps/emqx_authn/src/enhanced_authn/emqx_enhanced_authn_scram_mnesia.erl +++ b/apps/emqx_authn/src/enhanced_authn/emqx_enhanced_authn_scram_mnesia.erl @@ -42,10 +42,14 @@ , list_users/2 ]). --export([format_user_info/1]). +-export([ query/4 + , format_user_info/1 + , group_match_spec/1]). -define(TAB, ?MODULE). --define(FORMAT_FUN, {?MODULE, format_user_info}). +-define(AUTHN_QSCHEMA, [ {<<"like_username">>, binary} + , {<<"user_group">>, binary}]). +-define(QUERY_FUN, {?MODULE, query}). -type(user_group() :: binary()). @@ -201,9 +205,39 @@ lookup_user(UserID, #{user_group := UserGroup}) -> {error, not_found} end. -list_users(PageParams, #{user_group := UserGroup}) -> - MatchSpec = group_match_spec(UserGroup), - {ok, emqx_mgmt_api:paginate(?TAB, MatchSpec, PageParams, ?FORMAT_FUN)}. +list_users(QueryString, #{user_group := UserGroup}) -> + NQueryString = QueryString#{<<"user_group">> => UserGroup}, + emqx_mgmt_api:node_query(node(), NQueryString, ?TAB, ?AUTHN_QSCHEMA, ?QUERY_FUN). + +%%-------------------------------------------------------------------- +%% Query Functions + +query(Tab, {QString, []}, Continuation, Limit) -> + Ms = ms_from_qstring(QString), + emqx_mgmt_api:select_table_with_count(Tab, Ms, Continuation, Limit, + fun format_user_info/1); + +query(Tab, {QString, FuzzyQString}, Continuation, Limit) -> + Ms = ms_from_qstring(QString), + FuzzyFilterFun = fuzzy_filter_fun(FuzzyQString), + emqx_mgmt_api:select_table_with_count(Tab, {Ms, FuzzyFilterFun}, Continuation, Limit, + fun format_user_info/1). + +%%-------------------------------------------------------------------- +%% Match funcs + +%% Fuzzy username funcs +fuzzy_filter_fun(Fuzzy) -> + fun(MsRaws) when is_list(MsRaws) -> + lists:filter( fun(E) -> run_fuzzy_filter(E, Fuzzy) end + , MsRaws) + end. + +run_fuzzy_filter(_, []) -> + true; +run_fuzzy_filter( E = #user_info{user_id = {_, UserID}} + , [{username, like, UsernameSubStr} | Fuzzy]) -> + binary:match(UserID, UsernameSubStr) /= nomatch andalso run_fuzzy_filter(E, Fuzzy). %%------------------------------------------------------------------------------ %% Internal functions @@ -280,6 +314,14 @@ trans(Fun, Args) -> format_user_info(#user_info{user_id = {_, UserID}, is_superuser = IsSuperuser}) -> #{user_id => UserID, is_superuser => IsSuperuser}. +ms_from_qstring(QString) -> + [Ms] = lists:foldl(fun({user_group, '=:=', UserGroup}, AccIn) -> + [group_match_spec(UserGroup) | AccIn]; + (_, AccIn) -> + AccIn + end, [], QString), + Ms. + group_match_spec(UserGroup) -> ets:fun2ms( fun(#user_info{user_id = {Group, _}} = User) when Group =:= UserGroup -> diff --git a/apps/emqx_authn/test/emqx_enhanced_authn_scram_mnesia_SUITE.erl b/apps/emqx_authn/test/emqx_enhanced_authn_scram_mnesia_SUITE.erl index 55d1f21f1..b36b8ea56 100644 --- a/apps/emqx_authn/test/emqx_enhanced_authn_scram_mnesia_SUITE.erl +++ b/apps/emqx_authn/test/emqx_enhanced_authn_scram_mnesia_SUITE.erl @@ -269,16 +269,21 @@ t_list_users(_) -> fun(U) -> {ok, _} = emqx_enhanced_authn_scram_mnesia:add_user(U, State) end, Users), - {ok, - #{data := [?USER_MAP, ?USER_MAP], - meta := #{page := 1, limit := 2, count := 3}}} = emqx_enhanced_authn_scram_mnesia:list_users( - #{<<"page">> => 1, <<"limit">> => 2}, - State), - {ok, - #{data := [?USER_MAP], - meta := #{page := 2, limit := 2, count := 3}}} = emqx_enhanced_authn_scram_mnesia:list_users( - #{<<"page">> => 2, <<"limit">> => 2}, - State). + #{data := [?USER_MAP, ?USER_MAP], + meta := #{page := 1, limit := 2, count := 3}} = emqx_enhanced_authn_scram_mnesia:list_users( + #{<<"page">> => 1, <<"limit">> => 2}, + State), + #{data := [?USER_MAP], + meta := #{page := 2, limit := 2, count := 3}} = emqx_enhanced_authn_scram_mnesia:list_users( + #{<<"page">> => 2, <<"limit">> => 2}, + State), + #{data := [#{user_id := <<"u1">>, + is_superuser := _}], + meta := #{page := 1, limit := 3, count := 1}} = emqx_enhanced_authn_scram_mnesia:list_users( + #{ <<"page">> => 1 + , <<"limit">> => 3 + , <<"like_username">> => <<"1">>}, + State). t_is_superuser(_Config) -> ok = test_is_superuser(#{is_superuser => false}, false),