diff --git a/apps/emqx_authz/src/emqx_authz_mongodb.erl b/apps/emqx_authz/src/emqx_authz_mongodb.erl index 439c2c853..97fac9627 100644 --- a/apps/emqx_authz/src/emqx_authz_mongodb.erl +++ b/apps/emqx_authz/src/emqx_authz_mongodb.erl @@ -97,7 +97,7 @@ replvar(Selector, #{clientid := Clientid, , bin(Clientid), [global, {return, binary}]), V2 = re:replace( V1, emqx_authz:ph_to_re(?PH_S_USERNAME) , bin(Username), [global, {return, binary}]), - V3 = re:replace( V2, emqx_authz:ph_to_re(?PH_S_HOST) + V3 = re:replace( V2, emqx_authz:ph_to_re(?PH_S_PEERHOST) , inet_parse:ntoa(IpAddress), [global, {return, binary}]), maps:put(K, V3, AccIn); InFun(K, V, AccIn) -> maps:put(K, V, AccIn) diff --git a/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl b/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl index 8a6aa17c1..5b902ec43 100644 --- a/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl @@ -69,7 +69,6 @@ set_special_configs(_) -> %% Testcases %%------------------------------------------------------------------------------ - t_topic_rules(_Config) -> ClientInfo = #{clientid => <<"clientid">>, username => <<"username">>, @@ -78,106 +77,14 @@ t_topic_rules(_Config) -> listener => {tcp, default} }, - %% No rules + ok = emqx_authz_test_lib:test_no_topic_rules(ClientInfo, fun setup_client_samples/2), - ok = setup_samples([]), - ok = setup_config(#{}), - - ok = emqx_authz_test_lib:test_samples( - ClientInfo, - [{deny, subscribe, <<"#">>}, - {deny, subscribe, <<"subs">>}, - {deny, publish, <<"pub">>}]), - - %% Publish rules - - Samples0 = populate_records( - [#{<<"topics">> => [<<"eq testpub1/${username}">>]}, - #{<<"topics">> => [<<"testpub2/${clientid}">>, <<"testpub3/#">>]}], - #{<<"permission">> => <<"allow">>, - <<"action">> => <<"publish">>, - <<"username">> => <<"username">>}), - - ok = setup_samples(Samples0), - ok = setup_config(#{}), - - ok = emqx_authz_test_lib:test_samples( - ClientInfo, - [{deny, publish, <<"testpub1/username">>}, - {allow, publish, <<"testpub1/${username}">>}, - {allow, publish, <<"testpub2/clientid">>}, - {allow, publish, <<"testpub3/foobar">>}, - - {deny, publish, <<"testpub2/username">>}, - {deny, publish, <<"testpub1/clientid">>}, - - - {deny, subscribe, <<"testpub1/username">>}, - {deny, subscribe, <<"testpub2/clientid">>}, - {deny, subscribe, <<"testpub3/foobar">>}]), - - %% Subscribe rules - - Samples1 = populate_records( - [#{<<"topics">> => [<<"eq testsub1/${username}">>]}, - #{<<"topics">> => [<<"testsub2/${clientid}">>, <<"testsub3/#">>]}], - #{<<"permission">> => <<"allow">>, - <<"action">> => <<"subscribe">>, - <<"username">> => <<"username">>}), - - ok = setup_samples(Samples1), - ok = setup_config(#{}), - - ok = emqx_authz_test_lib:test_samples( - ClientInfo, - [{deny, subscribe, <<"testsub1/username">>}, - {allow, subscribe, <<"testsub1/${username}">>}, - {allow, subscribe, <<"testsub2/clientid">>}, - {allow, subscribe, <<"testsub3/foobar">>}, - {allow, subscribe, <<"testsub3/+/foobar">>}, - {allow, subscribe, <<"testsub3/#">>}, - - {deny, subscribe, <<"testsub2/username">>}, - {deny, subscribe, <<"testsub1/clientid">>}, - {deny, subscribe, <<"testsub4/foobar">>}, - {deny, publish, <<"testsub1/username">>}, - {deny, publish, <<"testsub2/clientid">>}, - {deny, publish, <<"testsub3/foobar">>}]), - - %% All rules - - Samples2 = populate_records( - [#{<<"topics">> => [<<"eq testall1/${username}">>]}, - #{<<"topics">> => [<<"testall2/${clientid}">>, <<"testall3/#">>]}], - #{<<"permission">> => <<"allow">>, - <<"action">> => <<"all">>, - <<"username">> => <<"username">>}), - - ok = setup_samples(Samples2), - ok = setup_config(#{}), - - ok = emqx_authz_test_lib:test_samples( - ClientInfo, - [{deny, subscribe, <<"testall1/username">>}, - {allow, subscribe, <<"testall1/${username}">>}, - {allow, subscribe, <<"testall2/clientid">>}, - {allow, subscribe, <<"testall3/foobar">>}, - {allow, subscribe, <<"testall3/+/foobar">>}, - {allow, subscribe, <<"testall3/#">>}, - {deny, publish, <<"testall1/username">>}, - {allow, publish, <<"testall1/${username}">>}, - {allow, publish, <<"testall2/clientid">>}, - {allow, publish, <<"testall3/foobar">>}, - - {deny, subscribe, <<"testall2/username">>}, - {deny, subscribe, <<"testall1/clientid">>}, - {deny, subscribe, <<"testall4/foobar">>}, - {deny, publish, <<"testall2/username">>}, - {deny, publish, <<"testall1/clientid">>}, - {deny, publish, <<"testall4/foobar">>}]). + ok = emqx_authz_test_lib:test_allow_topic_rules(ClientInfo, fun setup_client_samples/2), + ok = emqx_authz_test_lib:test_deny_topic_rules(ClientInfo, fun setup_client_samples/2). t_complex_selector(_) -> + %% atom and string values also supported ClientInfo = #{clientid => clientid, username => "username", peerhost => {127,0,0,1}, @@ -205,6 +112,60 @@ t_complex_selector(_) -> ClientInfo, [{allow, publish, <<"t">>}]). +t_mongo_error(_Config) -> + ClientInfo = #{clientid => <<"clientid">>, + username => <<"username">>, + peerhost => {127,0,0,1}, + zone => default, + listener => {tcp, default} + }, + + ok = setup_samples([]), + ok = setup_config( + #{<<"selector">> => #{<<"$badoperator">> => <<"$badoperator">>}}), + + ok = emqx_authz_test_lib:test_samples( + ClientInfo, + [{deny, publish, <<"t">>}]). + +t_lookups(_Config) -> + ClientInfo = #{clientid => <<"clientid">>, + cn => <<"cn">>, + dn => <<"dn">>, + username => <<"username">>, + peerhost => {127,0,0,1}, + zone => default, + listener => {tcp, default} + }, + + ByClientid = #{<<"clientid">> => <<"clientid">>, + <<"topics">> => [<<"a">>], + <<"action">> => <<"all">>, + <<"permission">> => <<"allow">>}, + + ok = setup_samples([ByClientid]), + ok = setup_config( + #{<<"selector">> => #{<<"clientid">> => <<"${clientid}">>}}), + + ok = emqx_authz_test_lib:test_samples( + ClientInfo, + [{allow, subscribe, <<"a">>}, + {deny, subscribe, <<"b">>}]), + + ByPeerhost = #{<<"peerhost">> => <<"127.0.0.1">>, + <<"topics">> => [<<"a">>], + <<"action">> => <<"all">>, + <<"permission">> => <<"allow">>}, + + ok = setup_samples([ByPeerhost]), + ok = setup_config( + #{<<"selector">> => #{<<"peerhost">> => <<"${peerhost}">>}}), + + ok = emqx_authz_test_lib:test_samples( + ClientInfo, + [{allow, subscribe, <<"a">>}, + {deny, subscribe, <<"b">>}]). + %%------------------------------------------------------------------------------ %% Helpers %%------------------------------------------------------------------------------ @@ -217,6 +178,23 @@ setup_samples(AclRecords) -> {{true, _}, _} = mc_worker_api:insert(?MONGO_CLIENT, <<"acl">>, AclRecords), ok. +setup_client_samples(ClientInfo, Samples) -> + #{username := Username} = ClientInfo, + Records = lists:map( + fun(Sample) -> + #{topics := Topics, + permission := Permission, + action := Action} = Sample, + + #{<<"topics">> => Topics, + <<"permission">> => Permission, + <<"action">> => Action, + <<"username">> => Username} + end, + Samples), + setup_samples(Records), + setup_config(#{<<"selector">> => #{<<"username">> => <<"${username}">>}}). + reset_samples() -> {true, _} = mc_worker_api:delete(?MONGO_CLIENT, <<"acl">>, #{}), ok. diff --git a/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl b/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl index 7853564bf..a3036d498 100644 --- a/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl @@ -76,96 +76,10 @@ t_topic_rules(_Config) -> listener => {tcp, default} }, - %% No rules + ok = emqx_authz_test_lib:test_no_topic_rules(ClientInfo, fun setup_client_samples/2), - ok = setup_sample(#{}), - ok = setup_config(#{}), + ok = emqx_authz_test_lib:test_allow_topic_rules(ClientInfo, fun setup_client_samples/2). - ok = emqx_authz_test_lib:test_samples( - ClientInfo, - [{deny, subscribe, <<"#">>}, - {deny, subscribe, <<"subs">>}, - {deny, publish, <<"pub">>}]), - - %% Publish rules - - Sample0 = #{<<"mqtt_user:username">> => - #{<<"testpub1/${username}">> => <<"publish">>, - <<"testpub2/${clientid}">> => <<"publish">>, - <<"testpub3/#">> => <<"publish">> - } - }, - ok = setup_sample(Sample0), - ok = setup_config(#{}), - - ok = emqx_authz_test_lib:test_samples( - ClientInfo, - [{allow, publish, <<"testpub1/username">>}, - {allow, publish, <<"testpub2/clientid">>}, - {allow, publish, <<"testpub3/foobar">>}, - - {deny, publish, <<"testpub2/username">>}, - {deny, publish, <<"testpub1/clientid">>}, - - - {deny, subscribe, <<"testpub1/username">>}, - {deny, subscribe, <<"testpub2/clientid">>}, - {deny, subscribe, <<"testpub3/foobar">>}]), - - %% Subscribe rules - - Sample1 = #{<<"mqtt_user:username">> => - #{<<"testsub1/${username}">> => <<"subscribe">>, - <<"testsub2/${clientid}">> => <<"subscribe">>, - <<"testsub3/#">> => <<"subscribe">> - } - }, - ok = setup_sample(Sample1), - ok = setup_config(#{}), - - ok = emqx_authz_test_lib:test_samples( - ClientInfo, - [{allow, subscribe, <<"testsub1/username">>}, - {allow, subscribe, <<"testsub2/clientid">>}, - {allow, subscribe, <<"testsub3/foobar">>}, - {allow, subscribe, <<"testsub3/+/foobar">>}, - {allow, subscribe, <<"testsub3/#">>}, - - {deny, subscribe, <<"testsub2/username">>}, - {deny, subscribe, <<"testsub1/clientid">>}, - {deny, subscribe, <<"testsub4/foobar">>}, - {deny, publish, <<"testsub1/username">>}, - {deny, publish, <<"testsub2/clientid">>}, - {deny, publish, <<"testsub3/foobar">>}]), - - %% All rules - - Sample2 = #{<<"mqtt_user:username">> => - #{<<"testall1/${username}">> => <<"all">>, - <<"testall2/${clientid}">> => <<"all">>, - <<"testall3/#">> => <<"all">> - } - }, - ok = setup_sample(Sample2), - ok = setup_config(#{}), - - ok = emqx_authz_test_lib:test_samples( - ClientInfo, - [{allow, subscribe, <<"testall1/username">>}, - {allow, subscribe, <<"testall2/clientid">>}, - {allow, subscribe, <<"testall3/foobar">>}, - {allow, subscribe, <<"testall3/+/foobar">>}, - {allow, subscribe, <<"testall3/#">>}, - {allow, publish, <<"testall1/username">>}, - {allow, publish, <<"testall2/clientid">>}, - {allow, publish, <<"testall3/foobar">>}, - - {deny, subscribe, <<"testall2/username">>}, - {deny, subscribe, <<"testall1/clientid">>}, - {deny, subscribe, <<"testall4/foobar">>}, - {deny, publish, <<"testall2/username">>}, - {deny, publish, <<"testall1/clientid">>}, - {deny, publish, <<"testall4/foobar">>}]). t_lookups(_Config) -> ClientInfo = #{clientid => <<"clientid">>, @@ -267,6 +181,23 @@ setup_sample(AuthzData) -> end, maps:to_list(AuthzData)). +setup_client_samples(ClientInfo, Samples) -> + #{username := Username} = ClientInfo, + Key = <<"mqtt_user:", Username/binary>>, + lists:foreach( + fun(Sample) -> + #{topics := Topics, + permission := <<"allow">>, + action := Action} = Sample, + lists:foreach( + fun(Topic) -> + q(["HSET", Key, Topic, Action]) + end, + Topics) + end, + Samples), + setup_config(#{}). + setup_config(SpecialParams) -> ok = emqx_authz_test_lib:reset_authorizers(deny, false), Config = maps:merge(raw_redis_authz_config(), SpecialParams), diff --git a/apps/emqx_authz/test/emqx_authz_test_lib.erl b/apps/emqx_authz/test/emqx_authz_test_lib.erl index 6dd00527e..0af77c2e6 100644 --- a/apps/emqx_authz/test/emqx_authz_test_lib.erl +++ b/apps/emqx_authz/test/emqx_authz_test_lib.erl @@ -41,6 +41,15 @@ setup_config(BaseConfig, SpecialParams) -> {ok, _} = emqx_authz:update(?CMD_REPLACE, [Config]), ok. +is_tcp_server_available(Host, Port) -> + case gen_tcp:connect(Host, Port, [], ?DEFAULT_CHECK_AVAIL_TIMEOUT) of + {ok, Socket} -> + gen_tcp:close(Socket), + true; + {error, _} -> + false + end. + test_samples(ClientInfo, Samples) -> lists:foreach( fun({Expected, Action, Topic}) -> @@ -56,11 +65,185 @@ test_samples(ClientInfo, Samples) -> end, Samples). -is_tcp_server_available(Host, Port) -> - case gen_tcp:connect(Host, Port, [], ?DEFAULT_CHECK_AVAIL_TIMEOUT) of - {ok, Socket} -> - gen_tcp:close(Socket), - true; - {error, _} -> - false - end. +test_no_topic_rules(ClientInfo, SetupSamples) -> + %% No rules + + ok = SetupSamples(ClientInfo, []), + + ok = test_samples( + ClientInfo, + [{deny, subscribe, <<"#">>}, + {deny, subscribe, <<"subs">>}, + {deny, publish, <<"pub">>}]). + +test_allow_topic_rules(ClientInfo, SetupSamples) -> + Samples = [#{ + topics => [<<"eq testpub1/${username}">>, + <<"testpub2/${clientid}">>, + <<"testpub3/#">>], + permission => <<"allow">>, + action => <<"publish">> + }, + #{ + topics => [<<"eq testsub1/${username}">>, + <<"testsub2/${clientid}">>, + <<"testsub3/#">>], + permission => <<"allow">>, + action => <<"subscribe">> + }, + + #{ + topics => [<<"eq testall1/${username}">>, + <<"testall2/${clientid}">>, + <<"testall3/#">>], + permission => <<"allow">>, + action => <<"all">> + } + ], + + ok = SetupSamples(ClientInfo, Samples), + + ok = test_samples( + ClientInfo, + [ + + %% Publish rules + + {deny, publish, <<"testpub1/username">>}, + {allow, publish, <<"testpub1/${username}">>}, + {allow, publish, <<"testpub2/clientid">>}, + {allow, publish, <<"testpub3/foobar">>}, + + {deny, publish, <<"testpub2/username">>}, + {deny, publish, <<"testpub1/clientid">>}, + + + {deny, subscribe, <<"testpub1/username">>}, + {deny, subscribe, <<"testpub2/clientid">>}, + {deny, subscribe, <<"testpub3/foobar">>}, + + %% Subscribe rules + + {deny, subscribe, <<"testsub1/username">>}, + {allow, subscribe, <<"testsub1/${username}">>}, + {allow, subscribe, <<"testsub2/clientid">>}, + {allow, subscribe, <<"testsub3/foobar">>}, + {allow, subscribe, <<"testsub3/+/foobar">>}, + {allow, subscribe, <<"testsub3/#">>}, + + {deny, subscribe, <<"testsub2/username">>}, + {deny, subscribe, <<"testsub1/clientid">>}, + {deny, subscribe, <<"testsub4/foobar">>}, + {deny, publish, <<"testsub1/username">>}, + {deny, publish, <<"testsub2/clientid">>}, + {deny, publish, <<"testsub3/foobar">>}, + + %% All rules + + {deny, subscribe, <<"testall1/username">>}, + {allow, subscribe, <<"testall1/${username}">>}, + {allow, subscribe, <<"testall2/clientid">>}, + {allow, subscribe, <<"testall3/foobar">>}, + {allow, subscribe, <<"testall3/+/foobar">>}, + {allow, subscribe, <<"testall3/#">>}, + {deny, publish, <<"testall1/username">>}, + {allow, publish, <<"testall1/${username}">>}, + {allow, publish, <<"testall2/clientid">>}, + {allow, publish, <<"testall3/foobar">>}, + + {deny, subscribe, <<"testall2/username">>}, + {deny, subscribe, <<"testall1/clientid">>}, + {deny, subscribe, <<"testall4/foobar">>}, + {deny, publish, <<"testall2/username">>}, + {deny, publish, <<"testall1/clientid">>}, + {deny, publish, <<"testall4/foobar">>} + ]). + +test_deny_topic_rules(ClientInfo, SetupSamples) -> + Samples = [ + #{ + topics => [<<"#">>], + permission => <<"allow">>, + action => <<"all">> + }, + #{ + topics => [<<"eq testpub1/${username}">>, + <<"testpub2/${clientid}">>, + <<"testpub3/#">>], + permission => <<"deny">>, + action => <<"publish">> + }, + #{ + topics => [<<"eq testsub1/${username}">>, + <<"testsub2/${clientid}">>, + <<"testsub3/#">>], + permission => <<"deny">>, + action => <<"subscribe">> + }, + + #{ + topics => [<<"eq testall1/${username}">>, + <<"testall2/${clientid}">>, + <<"testall3/#">>], + permission => <<"deny">>, + action => <<"all">> + } + ], + + ok = SetupSamples(ClientInfo, Samples), + + ok = test_samples( + ClientInfo, + [ + + %% Publish rules + + {allow, publish, <<"testpub1/username">>}, + {deny, publish, <<"testpub1/${username}">>}, + {deny, publish, <<"testpub2/clientid">>}, + {deny, publish, <<"testpub3/foobar">>}, + + {allow, publish, <<"testpub2/username">>}, + {allow, publish, <<"testpub1/clientid">>}, + + + {allow, subscribe, <<"testpub1/username">>}, + {allow, subscribe, <<"testpub2/clientid">>}, + {allow, subscribe, <<"testpub3/foobar">>}, + + %% Subscribe rules + + {allow, subscribe, <<"testsub1/username">>}, + {deny, subscribe, <<"testsub1/${username}">>}, + {deny, subscribe, <<"testsub2/clientid">>}, + {deny, subscribe, <<"testsub3/foobar">>}, + {deny, subscribe, <<"testsub3/+/foobar">>}, + {deny, subscribe, <<"testsub3/#">>}, + + {allow, subscribe, <<"testsub2/username">>}, + {allow, subscribe, <<"testsub1/clientid">>}, + {allow, subscribe, <<"testsub4/foobar">>}, + {allow, publish, <<"testsub1/username">>}, + {allow, publish, <<"testsub2/clientid">>}, + {allow, publish, <<"testsub3/foobar">>}, + + %% All rules + + {allow, subscribe, <<"testall1/username">>}, + {deny, subscribe, <<"testall1/${username}">>}, + {deny, subscribe, <<"testall2/clientid">>}, + {deny, subscribe, <<"testall3/foobar">>}, + {deny, subscribe, <<"testall3/+/foobar">>}, + {deny, subscribe, <<"testall3/#">>}, + {allow, publish, <<"testall1/username">>}, + {deny, publish, <<"testall1/${username}">>}, + {deny, publish, <<"testall2/clientid">>}, + {deny, publish, <<"testall3/foobar">>}, + + {allow, subscribe, <<"testall2/username">>}, + {allow, subscribe, <<"testall1/clientid">>}, + {allow, subscribe, <<"testall4/foobar">>}, + {allow, publish, <<"testall2/username">>}, + {allow, publish, <<"testall1/clientid">>}, + {allow, publish, <<"testall4/foobar">>} + ]).