fix(emqx_acl_mnesia): split pubsub into two different capabilities
This commit is contained in:
parent
2c029c0607
commit
61ad5d718f
|
@ -49,8 +49,13 @@ add_acl(Login, Topic, Action, Access) ->
|
||||||
ret(mnesia:transaction(
|
ret(mnesia:transaction(
|
||||||
fun() ->
|
fun() ->
|
||||||
OldRecords = mnesia:wread({?TABLE, Filter}),
|
OldRecords = mnesia:wread({?TABLE, Filter}),
|
||||||
maybe_delete_shadowed_records(Action, OldRecords),
|
case Action of
|
||||||
mnesia:write(Acl)
|
pubsub ->
|
||||||
|
update_permission(pub, Acl, OldRecords),
|
||||||
|
update_permission(sub, Acl, OldRecords);
|
||||||
|
_ ->
|
||||||
|
update_permission(Action, Acl, OldRecords)
|
||||||
|
end
|
||||||
end)).
|
end)).
|
||||||
|
|
||||||
%% @doc Lookup acl by login
|
%% @doc Lookup acl by login
|
||||||
|
@ -240,12 +245,26 @@ print_acl({all, Topic, Action, Access, _}) ->
|
||||||
[Topic, Action, Access]
|
[Topic, Action, Access]
|
||||||
).
|
).
|
||||||
|
|
||||||
|
update_permission(Action, Acl0, OldRecords) ->
|
||||||
|
Acl = Acl0 #?TABLE{action = Action},
|
||||||
|
maybe_delete_shadowed_records(Action, OldRecords),
|
||||||
|
mnesia:write(Acl).
|
||||||
|
|
||||||
maybe_delete_shadowed_records(_, []) ->
|
maybe_delete_shadowed_records(_, []) ->
|
||||||
ok;
|
ok;
|
||||||
maybe_delete_shadowed_records(Action1, [Rec = #emqx_acl{action = Action2} | Rest]) ->
|
maybe_delete_shadowed_records(Action1, [Rec = #emqx_acl{action = Action2} | Rest]) ->
|
||||||
if Action1 =:= Action2 orelse Action1 =:= pubsub ->
|
if Action1 =:= Action2 ->
|
||||||
ok = mnesia:delete_object(Rec);
|
ok = mnesia:delete_object(Rec);
|
||||||
|
Action2 =:= pubsub ->
|
||||||
|
%% Perform migration from the old data format on the
|
||||||
|
%% fly. This is needed only for the enterprise version,
|
||||||
|
%% delete this branch on 5.0
|
||||||
|
mnesia:delete_object(Rec),
|
||||||
|
mnesia:write(Rec#?TABLE{action = other_action(Action1)});
|
||||||
true ->
|
true ->
|
||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
maybe_delete_shadowed_records(Action1, Rest).
|
maybe_delete_shadowed_records(Action1, Rest).
|
||||||
|
|
||||||
|
other_action(pub) -> sub;
|
||||||
|
other_action(sub) -> pub.
|
||||||
|
|
|
@ -86,11 +86,15 @@ t_management(_Config) ->
|
||||||
ok = emqx_acl_mnesia_cli:add_acl({username, <<"test_username">>}, <<"topic/%u">>, sub, deny),
|
ok = emqx_acl_mnesia_cli:add_acl({username, <<"test_username">>}, <<"topic/%u">>, sub, deny),
|
||||||
ok = emqx_acl_mnesia_cli:add_acl({username, <<"test_username">>}, <<"topic/+">>, pub, allow),
|
ok = emqx_acl_mnesia_cli:add_acl({username, <<"test_username">>}, <<"topic/+">>, pub, allow),
|
||||||
ok = emqx_acl_mnesia_cli:add_acl(all, <<"#">>, pubsub, deny),
|
ok = emqx_acl_mnesia_cli:add_acl(all, <<"#">>, pubsub, deny),
|
||||||
|
%% Sleeps below are needed to hide the race condition between
|
||||||
|
%% mnesia and ets dirty select in check_acl, that make this test
|
||||||
|
%% flaky
|
||||||
|
timer:sleep(100),
|
||||||
|
|
||||||
?assertEqual(2, length(emqx_acl_mnesia_cli:lookup_acl({clientid, <<"test_clientid">>}))),
|
?assertEqual(2, length(emqx_acl_mnesia_cli:lookup_acl({clientid, <<"test_clientid">>}))),
|
||||||
?assertEqual(2, length(emqx_acl_mnesia_cli:lookup_acl({username, <<"test_username">>}))),
|
?assertEqual(2, length(emqx_acl_mnesia_cli:lookup_acl({username, <<"test_username">>}))),
|
||||||
?assertEqual(1, length(emqx_acl_mnesia_cli:lookup_acl(all))),
|
?assertEqual(2, length(emqx_acl_mnesia_cli:lookup_acl(all))),
|
||||||
?assertEqual(5, length(emqx_acl_mnesia_cli:all_acls())),
|
?assertEqual(6, length(emqx_acl_mnesia_cli:all_acls())),
|
||||||
|
|
||||||
User1 = #{zone => external, clientid => <<"test_clientid">>},
|
User1 = #{zone => external, clientid => <<"test_clientid">>},
|
||||||
User2 = #{zone => external, clientid => <<"no_exist">>, username => <<"test_username">>},
|
User2 = #{zone => external, clientid => <<"no_exist">>, username => <<"test_username">>},
|
||||||
|
@ -105,11 +109,35 @@ t_management(_Config) ->
|
||||||
deny = emqx_access_control:check_acl(User3, subscribe, <<"topic/A/B">>),
|
deny = emqx_access_control:check_acl(User3, subscribe, <<"topic/A/B">>),
|
||||||
deny = emqx_access_control:check_acl(User3, publish, <<"topic/A/B">>),
|
deny = emqx_access_control:check_acl(User3, publish, <<"topic/A/B">>),
|
||||||
|
|
||||||
|
%% Test merging of pubsub capability:
|
||||||
|
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, pubsub, deny),
|
||||||
|
timer:sleep(100),
|
||||||
|
deny = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
|
||||||
|
deny = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
|
||||||
|
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, pub, allow),
|
||||||
|
timer:sleep(100),
|
||||||
|
deny = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
|
||||||
|
allow = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
|
||||||
|
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, pubsub, allow),
|
||||||
|
timer:sleep(100),
|
||||||
|
allow = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
|
||||||
|
allow = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
|
||||||
|
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, sub, deny),
|
||||||
|
timer:sleep(100),
|
||||||
|
deny = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
|
||||||
|
allow = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
|
||||||
|
ok = emqx_acl_mnesia_cli:add_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>, pub, deny),
|
||||||
|
timer:sleep(100),
|
||||||
|
deny = emqx_access_control:check_acl(User1, subscribe, <<"topic/mix">>),
|
||||||
|
deny = emqx_access_control:check_acl(User1, publish, <<"topic/mix">>),
|
||||||
|
|
||||||
ok = emqx_acl_mnesia_cli:remove_acl({clientid, <<"test_clientid">>}, <<"topic/%c">>),
|
ok = emqx_acl_mnesia_cli:remove_acl({clientid, <<"test_clientid">>}, <<"topic/%c">>),
|
||||||
ok = emqx_acl_mnesia_cli:remove_acl({clientid, <<"test_clientid">>}, <<"topic/+">>),
|
ok = emqx_acl_mnesia_cli:remove_acl({clientid, <<"test_clientid">>}, <<"topic/+">>),
|
||||||
|
ok = emqx_acl_mnesia_cli:remove_acl({clientid, <<"test_clientid">>}, <<"topic/mix">>),
|
||||||
ok = emqx_acl_mnesia_cli:remove_acl({username, <<"test_username">>}, <<"topic/%u">>),
|
ok = emqx_acl_mnesia_cli:remove_acl({username, <<"test_username">>}, <<"topic/%u">>),
|
||||||
ok = emqx_acl_mnesia_cli:remove_acl({username, <<"test_username">>}, <<"topic/+">>),
|
ok = emqx_acl_mnesia_cli:remove_acl({username, <<"test_username">>}, <<"topic/+">>),
|
||||||
ok = emqx_acl_mnesia_cli:remove_acl(all, <<"#">>),
|
ok = emqx_acl_mnesia_cli:remove_acl(all, <<"#">>),
|
||||||
|
timer:sleep(100),
|
||||||
|
|
||||||
?assertEqual([], emqx_acl_mnesia_cli:all_acls()).
|
?assertEqual([], emqx_acl_mnesia_cli:all_acls()).
|
||||||
|
|
||||||
|
@ -139,10 +167,12 @@ t_acl_cli(_Config) ->
|
||||||
|
|
||||||
emqx_acl_mnesia_cli:cli(["add", "_all", "#", "pub", "allow"]),
|
emqx_acl_mnesia_cli:cli(["add", "_all", "#", "pub", "allow"]),
|
||||||
emqx_acl_mnesia_cli:cli(["add", "_all", "#", "pubsub", "deny"]),
|
emqx_acl_mnesia_cli:cli(["add", "_all", "#", "pubsub", "deny"]),
|
||||||
?assertMatch(["Acl($all topic = <<\"#\">> action = pubsub access = deny)\n"],
|
?assertMatch(["",
|
||||||
emqx_acl_mnesia_cli:cli(["list", "_all"])
|
"Acl($all topic = <<\"#\">> action = pub access = deny)",
|
||||||
|
"Acl($all topic = <<\"#\">> action = sub access = deny)"],
|
||||||
|
lists:sort(string:split(emqx_acl_mnesia_cli:cli(["list", "_all"]), "\n", all))
|
||||||
),
|
),
|
||||||
?assertEqual(3, length(emqx_acl_mnesia_cli:cli(["list"]))),
|
?assertEqual(4, length(emqx_acl_mnesia_cli:cli(["list"]))),
|
||||||
|
|
||||||
emqx_acl_mnesia_cli:cli(["del", "clientid", "test_clientid", "topic/A"]),
|
emqx_acl_mnesia_cli:cli(["del", "clientid", "test_clientid", "topic/A"]),
|
||||||
emqx_acl_mnesia_cli:cli(["del", "username", "test_username", "topic/B"]),
|
emqx_acl_mnesia_cli:cli(["del", "username", "test_username", "topic/B"]),
|
||||||
|
@ -171,7 +201,7 @@ t_rest_api(_Config) ->
|
||||||
}],
|
}],
|
||||||
{ok, _} = request_http_rest_add([], Params1),
|
{ok, _} = request_http_rest_add([], Params1),
|
||||||
{ok, Re1} = request_http_rest_list(["clientid", "test_clientid"]),
|
{ok, Re1} = request_http_rest_list(["clientid", "test_clientid"]),
|
||||||
?assertMatch(3, length(get_http_data(Re1))),
|
?assertMatch(4, length(get_http_data(Re1))),
|
||||||
{ok, _} = request_http_rest_delete(["clientid", "test_clientid", "topic", "topic/A"]),
|
{ok, _} = request_http_rest_delete(["clientid", "test_clientid", "topic", "topic/A"]),
|
||||||
{ok, _} = request_http_rest_delete(["clientid", "test_clientid", "topic", "topic/B"]),
|
{ok, _} = request_http_rest_delete(["clientid", "test_clientid", "topic", "topic/B"]),
|
||||||
{ok, _} = request_http_rest_delete(["clientid", "test_clientid", "topic", "topic/C"]),
|
{ok, _} = request_http_rest_delete(["clientid", "test_clientid", "topic", "topic/C"]),
|
||||||
|
@ -195,7 +225,7 @@ t_rest_api(_Config) ->
|
||||||
}],
|
}],
|
||||||
{ok, _} = request_http_rest_add([], Params2),
|
{ok, _} = request_http_rest_add([], Params2),
|
||||||
{ok, Re2} = request_http_rest_list(["username", "test_username"]),
|
{ok, Re2} = request_http_rest_list(["username", "test_username"]),
|
||||||
?assertMatch(3, length(get_http_data(Re2))),
|
?assertMatch(4, length(get_http_data(Re2))),
|
||||||
{ok, _} = request_http_rest_delete(["username", "test_username", "topic", "topic/A"]),
|
{ok, _} = request_http_rest_delete(["username", "test_username", "topic", "topic/A"]),
|
||||||
{ok, _} = request_http_rest_delete(["username", "test_username", "topic", "topic/B"]),
|
{ok, _} = request_http_rest_delete(["username", "test_username", "topic", "topic/B"]),
|
||||||
{ok, _} = request_http_rest_delete(["username", "test_username", "topic", "topic/C"]),
|
{ok, _} = request_http_rest_delete(["username", "test_username", "topic", "topic/C"]),
|
||||||
|
@ -216,7 +246,7 @@ t_rest_api(_Config) ->
|
||||||
}],
|
}],
|
||||||
{ok, _} = request_http_rest_add([], Params3),
|
{ok, _} = request_http_rest_add([], Params3),
|
||||||
{ok, Re3} = request_http_rest_list(["$all"]),
|
{ok, Re3} = request_http_rest_list(["$all"]),
|
||||||
?assertMatch(3, length(get_http_data(Re3))),
|
?assertMatch(4, length(get_http_data(Re3))),
|
||||||
{ok, _} = request_http_rest_delete(["$all", "topic", "topic/A"]),
|
{ok, _} = request_http_rest_delete(["$all", "topic", "topic/A"]),
|
||||||
{ok, _} = request_http_rest_delete(["$all", "topic", "topic/B"]),
|
{ok, _} = request_http_rest_delete(["$all", "topic", "topic/B"]),
|
||||||
{ok, _} = request_http_rest_delete(["$all", "topic", "topic/C"]),
|
{ok, _} = request_http_rest_delete(["$all", "topic", "topic/C"]),
|
||||||
|
|
Loading…
Reference in New Issue