From 3f66cb16a1bcf56c15755e5f5bf358e44513527f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chrz=C4=85szcz?= Date: Thu, 13 Jan 2022 18:32:15 +0100 Subject: [PATCH] WIP --- big_tests/tests/login_SUITE.erl | 2 +- src/acl.erl | 176 +++++++--------------- src/config/mongoose_config_spec.erl | 35 +++-- src/ejabberd_c2s.erl | 11 +- src/ejabberd_commands.erl | 3 +- src/ejabberd_s2s.erl | 6 +- src/ejabberd_s2s_in.erl | 5 +- src/ejabberd_service.erl | 2 +- src/ejabberd_sm.erl | 2 +- src/mam/mod_mam.erl | 2 +- src/mam/mod_mam_muc.erl | 2 +- src/mod_muc.erl | 6 +- src/mod_muc_log.erl | 3 +- src/mod_muc_room.erl | 16 +- src/mod_register.erl | 4 +- src/offline/mod_offline.erl | 2 +- src/pubsub/node_flat.erl | 3 +- src/pubsub/node_hometree.erl | 3 +- src/pubsub/node_pep.erl | 3 +- src/shaper_srv.erl | 2 +- test/acl_SUITE.erl | 219 ++++++++++++++-------------- test/config_parser_SUITE.erl | 30 ++-- test/config_parser_helper.erl | 2 +- 23 files changed, 242 insertions(+), 297 deletions(-) diff --git a/big_tests/tests/login_SUITE.erl b/big_tests/tests/login_SUITE.erl index 3738e790d7..d9aeea2330 100644 --- a/big_tests/tests/login_SUITE.erl +++ b/big_tests/tests/login_SUITE.erl @@ -449,7 +449,7 @@ set_acl_for_blocking(Config, Spec) -> User = proplists:get_value(username, Spec), LUser = jid:nodeprep(User), mongoose_helper:backup_and_set_config_option(Config, {acl, blocked, host_type()}, - [{user, LUser}]). + [#{user => LUser}]). unset_acl_for_blocking(Config) -> mongoose_helper:restore_config_option(Config, {acl, blocked, host_type()}). diff --git a/src/acl.erl b/src/acl.erl index 95b2189bc4..2723f71718 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -26,76 +26,42 @@ -module(acl). -author('alexey@process-one.net'). --export([match_rule/3, - match_rule/4, - match_rule_for_host_type/4, - match_rule_for_host_type/5]). - --export([prepare_spec/1]). - --ignore_xref([add/3, delete/3, match_rule/4]). +-export([match_rule/4, match_rule/5]). -include("jlib.hrl"). -include("mongoose.hrl"). --export_type([rule/0, domain_or_global/0, host_type_or_global/0]). +-export_type([rule/0]). --type rule() :: 'all' | 'none' | atom(). --type domain_or_global() :: jid:lserver() | global. --type host_type_or_global() :: mongooseim:host_type() | global. --type aclspec() :: #{match => all | none} | #{jid_part() => acl_pattern()}. --type jid_part() :: user | server | resource. --type acl_pattern() :: {value | regexp | glob, binary()}. +-type rule() :: atom(). +-type acl_spec() :: #{match := all | none | valid_domain} | + #{acl_spec_key() => binary()}. +-type acl_spec_key() :: user | user_regexp | user_glob + | server | server_regexp | server_glob + | resource | resource_regexp | resource_glob. -type acl_result() :: allow | deny | term(). -%% legacy API, use match_rule_for_host_type instead --spec match_rule(Domain :: domain_or_global(), - Rule :: rule(), - JID :: jid:jid()) -> acl_result(). -match_rule(Domain, Rule, JID) -> - match_rule(Domain, Rule, JID, deny). - --spec match_rule_for_host_type(HostType :: host_type_or_global(), - Domain :: domain_or_global(), - Rule :: rule(), - JID :: jid:jid()) -> acl_result(). -match_rule_for_host_type(HostType, Domain, Rule, JID) -> - match_rule_for_host_type(HostType, Domain, Rule, JID, deny). - -%% legacy API, use match_rule_for_host_type instead --spec match_rule(Domain :: domain_or_global(), - Rule :: rule(), - JID :: jid:jid(), - Default :: acl_result()) -> acl_result(). -match_rule(Domain, Rule, JID, Default) -> - %% We don't want to cast Domain to HostType here. - %% Developers should start using match_rule_for_host_type explicitly. - match_rule_for_host_type(Domain, Domain, Rule, JID, Default). - -%% HostType determines which rules and ACLs are checked: -%% - 'global' - only global ones -%% - a specific host type - both global and per-host-type ones -%% Domain is only used for validating the user's domain name: -%% - 'global' - any domain hosted by the server is accepted -%% - a specific domain name - only the provided name is accepted --spec match_rule_for_host_type(HostType :: host_type_or_global(), - Domain :: domain_or_global(), - Rule :: rule(), - JID :: jid:jid(), - Default :: acl_result()) -> acl_result(). -match_rule_for_host_type(_HostType, _, all, _, _Default) -> +-spec match_rule(mongooseim:host_type_or_global(), jid:lserver(), rule(), jid:jid()) -> + acl_result(). +match_rule(_HostType, _Domain, all, _JID) -> allow; -match_rule_for_host_type(_HostType, _, none, _, _Default) -> +match_rule(_HostType, _Domain, none, _JID) -> deny; -match_rule_for_host_type(global, Domain, Rule, JID, Default) -> +match_rule(HostType, Domain, Rule, JID) -> + match_rule(HostType, Domain, Rule, JID, deny). + +-spec match_rule(mongooseim:host_type_or_global(), jid:lserver(), rule(), jid:jid(), + Default :: acl_result()) -> + acl_result(). +match_rule(global, Domain, Rule, JID, Default) -> case mongoose_config:lookup_opt({access, Rule, global}) of {error, not_found} -> Default; - {ok, GACLs} -> - match_acls(GACLs, JID, global, Domain) + {ok, ACLs} -> + match_acls(ACLs, JID, global, Domain) end; -match_rule_for_host_type(HostType, Domain, Rule, JID, Default) -> +match_rule(HostType, Domain, Rule, JID, Default) -> case {mongoose_config:lookup_opt({access, Rule, global}), mongoose_config:lookup_opt({access, Rule, HostType})} of {{error, not_found}, {error, not_found}} -> @@ -117,10 +83,8 @@ merge_acls(Global, HostLocal) -> Global ++ HostLocal end. --spec match_acls(ACLs :: [{any(), rule()}], - JID :: jid:jid(), - HostType :: host_type_or_global(), - Domain :: domain_or_global()) -> deny | term(). +-spec match_acls(ACLs :: [{any(), rule()}], jid:jid(), mongooseim:host_type(), jid:lserver()) -> + acl_result(). match_acls([], _, _HostType, _Domain) -> deny; match_acls([{Value, Rule} | ACLs], JID, HostType, Domain) -> @@ -131,10 +95,7 @@ match_acls([{Value, Rule} | ACLs], JID, HostType, Domain) -> match_acls(ACLs, JID, HostType, Domain) end. --spec match_acl(Rule :: rule(), - JID :: jid:jid(), - HostType :: host_type_or_global(), - Domain :: domain_or_global()) -> boolean(). +-spec match_acl(rule(), jid:jid(), mongooseim:host_type_or_global(), jid:lserver()) -> boolean(). match_acl(all, _JID, _HostType, _Domain) -> true; match_acl(none, _JID, _HostType, _Domain) -> @@ -144,71 +105,36 @@ match_acl(Rule, JID, HostType, Domain) -> global -> get_acl_specs(Rule, global); _ -> get_acl_specs(Rule, HostType) ++ get_acl_specs(Rule, global) end, - Pred = fun(ACLSpec) -> match(ACLSpec, JID) end, - is_server_valid(Domain, JID#jid.lserver) andalso lists:any(Pred, AllSpecs). + Pred = fun(ACLSpec) -> match(ACLSpec, Domain, JID) end, + lists:any(Pred, AllSpecs). --spec get_acl_specs(rule(), host_type_or_global()) -> [aclspec()]. +-spec get_acl_specs(rule(), mongooseim:host_type()) -> [acl_spec()]. get_acl_specs(Rule, HostType) -> mongoose_config:get_opt({acl, Rule, HostType}, []). --spec is_server_valid(domain_or_global(), jid:lserver()) -> boolean(). -is_server_valid(Domain, Domain) -> - true; -is_server_valid(global, JIDServer) -> - case mongoose_domain_api:get_domain_host_type(JIDServer) of - {ok, _HostType} -> - true; - _ -> - false - end; -is_server_valid(_Domain, _JIDServer) -> - false. - --spec match(aclspec(), jid:jid()) -> boolean(). -match(#{match := Match}, _JID) -> - Match =:= all; -match(M, JID) -> - lists:all(fun({K, V}) -> check(K, V, JID) end, maps:to_list(M)). - --spec check(jid_part(), acl_pattern(), jid:jid()) -> boolean(). -check(user, Spec, #jid{luser = LUser}) -> check(Spec, LUser); -check(server, Spec, #jid{lserver = LServer}) -> check(Spec, LServer); -check(resource, Spec, #jid{lresource = LResource}) -> check(Spec, LResource). - --spec check(acl_pattern(), binary()) -> boolean(). -check({regexp, Regexp}, Value) -> is_regexp_match(Value, Regexp); -check({glob, Glob}, Value) -> is_glob_match(Value, Glob); -check({value, ExpValue}, Value) -> ExpValue =:= Value. - --spec prepare_spec(map()) -> aclspec(). -prepare_spec(M) -> - KVs = [prepare_check(K, V) || {K, V} <- maps:to_list(M)], - case conflicts(proplists:get_keys(KVs)) of - [] -> maps:from_list(KVs); - Conflicts -> - error(#{what => wrong_acl_expression, - text => <<"Wrong ACL expression in the configuration file">>, - wrong_spec => M, - conflicts => Conflicts}) - end. - --spec conflicts([atom()]) -> [atom()]. -conflicts(Keys) -> - case lists:member(match, Keys) of - true -> Keys -- [match]; - false -> Keys -- [user, server, resource] - end. - -prepare_check(user, User) -> {user, {value, User}}; -prepare_check(server, Server) -> {server, {value, Server}}; -prepare_check(resource, Resource) -> {resource, {value, Resource}}; -prepare_check(user_regexp, Regexp) -> {user, {regexp, Regexp}}; -prepare_check(server_regexp, Regexp) -> {server, {regexp, Regexp}}; -prepare_check(resource_regexp, Regexp) -> {resource, {regexp, Regexp}}; -prepare_check(user_glob, Glob) -> {user, {glob, Glob}}; -prepare_check(server_glob, Glob) -> {server, {glob, Glob}}; -prepare_check(resource_glob, Glob) -> {resource, {glob, Glob}}; -prepare_check(match, Value) -> {match, Value}. +%% @doc Check if all conditions from ACLSpec are satisfied by JID +-spec match(acl_spec(), jid:lserver(), jid:jid()) -> boolean(). +match(ACLSpec, Domain, JID) -> + match_step(maps:next(maps:iterator(ACLSpec)), Domain, JID). + +match_step({K, V, I}, Domain, JID) -> + check(K, V, Domain, JID) andalso match_step(maps:next(I), Domain, JID); +match_step(none, _Domain, _JID) -> + true. + +-spec check(acl_spec_key(), binary(), jid:lserver(), jid:jid()) -> boolean(). +check(match, all, _, _) -> true; +check(match, none, _, _) -> false; +check(match, current_domain, Domain, JID) -> JID#jid.lserver =:= Domain; +check(user, User, _, JID) -> JID#jid.luser =:= User; +check(user_regexp, Regexp, _, JID) -> is_regexp_match(JID#jid.luser, Regexp); +check(user_glob, Glob, _, JID) -> is_glob_match(JID#jid.luser, Glob); +check(server, Server, _, JID) -> JID#jid.lserver =:= Server; +check(server_regexp, Regexp, _, JID) -> is_regexp_match(JID#jid.lserver, Regexp); +check(server_glob, Glob, _, JID) -> is_glob_match(JID#jid.lserver, Glob); +check(resource, Resource, _, JID) -> JID#jid.lresource =:= Resource; +check(resource_regexp, Regexp, _, JID) -> is_regexp_match(JID#jid.lresource, Regexp); +check(resource_glob, Glob, _, JID) -> is_glob_match(JID#jid.lresource, Glob). -spec is_regexp_match(binary(), RegExp :: iodata()) -> boolean(). is_regexp_match(String, RegExp) -> diff --git a/src/config/mongoose_config_spec.erl b/src/config/mongoose_config_spec.erl index 2ba0f8d9a5..0ce69669ea 100644 --- a/src/config/mongoose_config_spec.erl +++ b/src/config/mongoose_config_spec.erl @@ -30,6 +30,7 @@ process_riak_credentials/1, process_iqdisc/1, process_shaper/1, + process_acl_condition/1, process_access_rule_item/1, process_s2s_address_family/1, process_s2s_host_policy/1, @@ -824,22 +825,23 @@ acl() -> %% path: (host_config[].)acl.*[] acl_item() -> + Cond = #option{type = binary, + process = fun ?MODULE:process_acl_condition/1}, #section{ items = #{<<"match">> => #option{type = atom, - validate = {enum, [all, none]}}, - <<"user">> => #option{type = binary}, - <<"server">> => #option{type = binary}, - <<"resource">> => #option{type = binary}, - <<"user_regexp">> => #option{type = binary}, - <<"server_regexp">> => #option{type = binary}, - <<"resource_regexp">> => #option{type = binary}, - <<"user_glob">> => #option{type = binary}, - <<"server_glob">> => #option{type = binary}, - <<"resource_glob">> => #option{type = binary} + validate = {enum, [all, none, current_domain]}}, + <<"user">> => Cond, + <<"server">> => Cond, + <<"resource">> => Cond, + <<"user_regexp">> => Cond, + <<"server_regexp">> => Cond, + <<"resource_regexp">> => Cond, + <<"user_glob">> => Cond, + <<"server_glob">> => Cond, + <<"resource_glob">> => Cond }, - validate_keys = non_empty, - format_items = map, - process = fun acl:prepare_spec/1 + defaults = #{<<"match">> => current_domain}, + format_items = map }. %% path: (host_config[].)access @@ -1235,6 +1237,13 @@ wpool_strategy_values() -> process_shaper([MaxRate]) -> MaxRate. +process_acl_condition(Value) -> + case jid:nodeprep(Value) of + error -> error(#{what => incorrect_acl_condition_value, + text => <<"Value could not be parsed as a JID node part">>}); + Node -> Node + end. + process_access_rule_item(KVs) -> {[[{acl, Acl}], [{value, Value}]], []} = proplists:split(KVs, [acl, value]), {Value, Acl}. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 5bcdbde570..3eee329d70 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1612,11 +1612,10 @@ generate_random_resource() -> <<(mongoose_bin:gen_from_crypto())/binary, (mongoose_bin:gen_from_timestamp())/binary>>. -spec change_shaper(state(), jid:jid()) -> any(). -change_shaper(StateData, JID) -> - Shaper = acl:match_rule(StateData#state.server, - StateData#state.shaper, JID), - (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). - +change_shaper(#state{host_type = HostType, server = Server, shaper = ShaperRule, + socket = Socket, sockmod = SockMod}, JID) -> + Shaper = acl:match_rule(HostType, Server, ShaperRule, JID), + SockMod:change_shaper(Socket, Shaper). -spec send_text(state(), Text :: binary()) -> any(). send_text(StateData, Text) -> @@ -3316,7 +3315,7 @@ handle_sasl_step(#state{host_type = HostType, server = Server, socket = Sock} = end. user_allowed(JID, #state{host_type = HostType, server = Server, access = Access}) -> - case acl:match_rule_for_host_type(HostType, Server, Access, JID) of + case acl:match_rule(HostType, Server, Access, JID) of allow -> open_session_allowed_hook(HostType, JID); deny -> diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index d07e47f4cb..f298ca6738 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -447,7 +447,8 @@ check_access(Access, Auth) -> {ok, JID} = check_auth(Auth), %% Check this user has access permission {_, LServer} = jid:to_lus(JID), - case acl:match_rule(LServer, Access, JID) of + {ok, HostType} = mongoose_domain_api:get_domain_host_type(LServer), + case acl:match_rule(HostType, LServer, Access, JID) of allow -> true; deny -> false end. diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 28b41d27d8..e33c13141e 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -437,16 +437,18 @@ new_connection(MyServer, Server, From, FromTo = {FromServer, ToServer}, -spec max_s2s_connections_number(fromto()) -> pos_integer(). max_s2s_connections_number({From, To}) -> + {ok, HostType} = mongoose_domain_api:get_host_type(From), case acl:match_rule( - From, max_s2s_connections, jid:make(<<"">>, To, <<"">>)) of + HostType, To, max_s2s_connections, jid:make(<<"">>, To, <<"">>)) of Max when is_integer(Max) -> Max; _ -> ?DEFAULT_MAX_S2S_CONNECTIONS_NUMBER end. -spec max_s2s_connections_number_per_node(fromto()) -> pos_integer(). max_s2s_connections_number_per_node({From, To}) -> + {ok, HostType} = mongoose_domain_api:get_host_type(From), case acl:match_rule( - From, max_s2s_connections_per_node, jid:make(<<"">>, To, <<"">>)) of + HostType, To, max_s2s_connections_per_node, jid:make(<<"">>, To, <<"">>)) of Max when is_integer(Max) -> Max; _ -> ?DEFAULT_MAX_S2S_CONNECTIONS_NUMBER_PER_NODE end. diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index e6c0c4fad8..3a23042a78 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -586,9 +586,10 @@ stream_features(Domain) -> {error, not_found} -> [] end. --spec change_shaper(state(), Host :: 'global' | binary(), jid:jid()) -> any(). +-spec change_shaper(state(), Host :: binary(), jid:jid()) -> any(). change_shaper(StateData, Host, JID) -> - Shaper = acl:match_rule(Host, StateData#state.shaper, JID), + {ok, HostType} = mongoose_domain_api:get_host_type(Host), + Shaper = acl:match_rule(HostType, Host, StateData#state.shaper, JID), (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index c4c209b0f7..28dcd12b90 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -371,7 +371,7 @@ handle_info({route, From, To, Acc}, StateName, StateData) -> ?LOG_DEBUG(#{what => comp_route, text => <<"Route packet to an external component">>, component => component_host(StateData), acc => Acc}), - case acl:match_rule(global, StateData#state.access, From) of + case acl:match_rule(global, From#jid.lserver, StateData#state.access, From) of allow -> mongoose_hooks:packet_to_component(Acc, From, To), Attrs2 = jlib:replace_from_to_attrs(jid:to_binary(From), diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index ee4ce60a9a..ce1c9470f4 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -971,7 +971,7 @@ check_max_sessions(HostType, LUser, LServer, ReplacedPIDs) -> Result :: infinity | pos_integer(). get_max_user_sessions(HostType, LUser, LServer) -> JID = jid:make_noprep(LUser, LServer, <<>>), - case acl:match_rule_for_host_type(HostType, LServer, max_user_sessions, JID) of + case acl:match_rule(HostType, LServer, max_user_sessions, JID) of Max when is_integer(Max) -> Max; infinity -> infinity; _ -> ?MAX_USER_SESSIONS diff --git a/src/mam/mod_mam.erl b/src/mam/mod_mam.erl index 039edf29bb..ed57119fbd 100644 --- a/src/mam/mod_mam.erl +++ b/src/mam/mod_mam.erl @@ -362,7 +362,7 @@ acc_to_host_type(Acc) -> Action :: mam_iq:action(), From :: jid:jid(), To :: jid:jid()) -> boolean(). is_action_allowed(HostType, Action, From, To) -> - case acl:match_rule_for_host_type(HostType, To#jid.lserver, Action, From, default) of + case acl:match_rule(HostType, To#jid.lserver, Action, From, default) of allow -> true; deny -> false; default -> is_action_allowed_by_default(Action, From, To) diff --git a/src/mam/mod_mam_muc.erl b/src/mam/mod_mam_muc.erl index 34865ebfea..6dee3a4319 100644 --- a/src/mam/mod_mam_muc.erl +++ b/src/mam/mod_mam_muc.erl @@ -277,7 +277,7 @@ forget_room(Acc, _HostType, MucServer, RoomName) -> -spec check_action_allowed(host_type(), mongoose_acc:t(), jid:lserver(), mam_iq:action(), muc_action(), jid:jid(), jid:jid()) -> ok | {error, binary()}. check_action_allowed(HostType, Acc, Domain, Action, MucAction, From, To) -> - case acl:match_rule_for_host_type(HostType, Domain, MucAction, From, default) of + case acl:match_rule(HostType, Domain, MucAction, From, default) of allow -> ok; deny -> {false, <<"Blocked by service policy.">>}; default -> check_room_action_allowed_by_default(HostType, Acc, Action, From, To) diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 3100ba0cd8..71f6fff394 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -582,7 +582,7 @@ process_packet(Acc, From, To, El, #{state := State}) -> {AccessRoute, _, _, _} = State#state.access, ServerHost = make_server_host(To, State), HostType = State#state.host_type, - case acl:match_rule_for_host_type(HostType, ServerHost, AccessRoute, From) of + case acl:match_rule(HostType, ServerHost, AccessRoute, From) of allow -> {Room, MucHost, _} = jid:to_lower(To), route_to_room(MucHost, Room, {From, To, Acc, El}, State), @@ -797,7 +797,7 @@ route_by_type(<<"message">>, {From, To, Acc, Packet}, <<"error">> -> ok; _ -> - case acl:match_rule_for_host_type(HostType, ServerHost, AccessAdmin, From) of + case acl:match_rule(HostType, ServerHost, AccessAdmin, From) of allow -> Msg = xml:get_path_s(Packet, [{elem, <<"body">>}, cdata]), broadcast_service_message(MucHost, Msg); @@ -815,7 +815,7 @@ route_by_type(<<"presence">>, _Routed, _State) -> -spec check_user_can_create_room(host_type(), jid:lserver(), allow | atom(), jid:jid(), room()) -> ok | {error, term()}. check_user_can_create_room(HostType, ServerHost, AccessCreate, From, RoomID) -> - case acl:match_rule_for_host_type(HostType, ServerHost, AccessCreate, From) of + case acl:match_rule(HostType, ServerHost, AccessCreate, From) of allow -> MaxLen = gen_mod:get_module_opt(HostType, mod_muc, max_room_id, infinity), diff --git a/src/mod_muc_log.erl b/src/mod_muc_log.erl index 15005bd1d4..6475b61fdf 100644 --- a/src/mod_muc_log.erl +++ b/src/mod_muc_log.erl @@ -234,8 +234,7 @@ init([Host, Opts]) -> From :: any(), logstate()) -> {'reply', 'allow' | 'deny', logstate()} | {'stop', 'normal', 'ok', _}. handle_call({check_access_log, HostType, ServerHost, FromJID}, _From, State) -> - Reply = acl:match_rule_for_host_type(HostType, ServerHost, - State#logstate.access, FromJID), + Reply = acl:match_rule(HostType, ServerHost, State#logstate.access, FromJID), {reply, Reply, State}; handle_call(stop, _From, State) -> {stop, normal, ok, State}. diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 668256137d..b195b6e34c 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -1397,8 +1397,7 @@ set_affiliation_and_reason(JID, Affiliation, Reason, StateData) -spec get_affiliation(jid:jid(), state()) -> mod_muc:affiliation(). get_affiliation(JID, StateData) -> AccessAdmin = access_admin(StateData), - case acl:match_rule_for_host_type(StateData#state.host_type, - StateData#state.server_host, AccessAdmin, JID) of + case acl:match_rule(StateData#state.host_type, StateData#state.server_host, AccessAdmin, JID) of allow -> owner; _ -> @@ -1424,8 +1423,7 @@ lookup_affiliation([], _Affiliations) -> -spec get_service_affiliation(jid:jid(), state()) -> mod_muc:affiliation(). get_service_affiliation(JID, StateData) -> AccessAdmin = access_admin(StateData), - case acl:match_rule_for_host_type(StateData#state.host_type, - StateData#state.server_host, AccessAdmin, JID) of + case acl:match_rule(StateData#state.host_type, StateData#state.server_host, AccessAdmin, JID) of allow -> owner; _ -> @@ -3321,9 +3319,8 @@ is_allowed_persistent_change(XEl, StateData, From) -> true; true -> AccessPersistent = access_persistent(StateData), - (allow == acl:match_rule_for_host_type(StateData#state.host_type, - StateData#state.server_host, - AccessPersistent, From)) + (allow == acl:match_rule(StateData#state.host_type, StateData#state.server_host, + AccessPersistent, From)) end. @@ -3418,9 +3415,8 @@ get_config(Lang, StateData, From) -> <<"muc#roomconfig_roomdesc">>, Config#config.description, Lang) ] ++ - case acl:match_rule_for_host_type(StateData#state.host_type, - StateData#state.server_host, - AccessPersistent, From) of + case acl:match_rule(StateData#state.host_type, StateData#state.server_host, + AccessPersistent, From) of allow -> [boolxfield(<<"Make room persistent">>, <<"muc#roomconfig_persistentroom">>, diff --git a/src/mod_register.erl b/src/mod_register.erl index b76eb4728e..af6f411d92 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -260,7 +260,7 @@ inband_registration_and_cancelation_allowed(_HostType, _ServerDomain, no_JID) -> true; inband_registration_and_cancelation_allowed(HostType, ServerDomain, JID) -> Rule = gen_mod:get_module_opt(HostType, ?MODULE, access, none), - allow =:= acl:match_rule_for_host_type(HostType, ServerDomain, Rule, JID). + allow =:= acl:match_rule(HostType, ServerDomain, Rule, JID). process_iq_get(_HostType, From, _To, #iq{lang = Lang, sub_el = Child} = IQ, _Source) -> true = is_query_element(Child), @@ -333,7 +333,7 @@ try_register(HostType, User, Server, Password, SourceRaw, Lang) -> JID = jid:make(User, Server, <<>>), Access = gen_mod:get_module_opt(HostType, ?MODULE, access, all), IPAccess = get_ip_access(HostType), - case {acl:match_rule_for_host_type(HostType, Server, Access, JID), + case {acl:match_rule(HostType, Server, Access, JID), check_ip_access(SourceRaw, IPAccess)} of {deny, _} -> {error, mongoose_xmpp_errors:forbidden()}; diff --git a/src/offline/mod_offline.erl b/src/offline/mod_offline.erl index cf4637d677..11379ca81a 100644 --- a/src/offline/mod_offline.erl +++ b/src/offline/mod_offline.erl @@ -209,7 +209,7 @@ is_message_count_threshold_reached(HostType, MaxOfflineMsgs, LUser, LServer, Len get_max_user_messages(HostType, AccessRule, LUser, LServer) -> - case acl:match_rule(HostType, AccessRule, jid:make_noprep(LUser, LServer, <<>>)) of + case acl:match_rule(HostType, LServer, AccessRule, jid:make_noprep(LUser, LServer, <<>>)) of Max when is_integer(Max) -> Max; infinity -> infinity; _ -> ?MAX_USER_MESSAGES diff --git a/src/pubsub/node_flat.erl b/src/pubsub/node_flat.erl index 2f5efa0d64..478a1a23e0 100644 --- a/src/pubsub/node_flat.erl +++ b/src/pubsub/node_flat.erl @@ -146,7 +146,8 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> {<<"">>, Host, <<"">>} -> true; % pubsub service always allowed _ -> - acl:match_rule(ServerHost, Access, Owner) =:= allow + {ok, HostType} = mongoose_domain_api:get_domain_host_type(ServerHost), + acl:match_rule(HostType, ServerHost, Access, Owner) =:= allow end, {result, Allowed}. diff --git a/src/pubsub/node_hometree.erl b/src/pubsub/node_hometree.erl index 855096ce16..6c2c6583c6 100644 --- a/src/pubsub/node_hometree.erl +++ b/src/pubsub/node_hometree.erl @@ -66,7 +66,8 @@ create_node_permission(Host, _ServerHost, _Node, _ParentNode, {result, true}; % pubsub service always allowed create_node_permission(_Host, ServerHost, Node, _ParentNode, #jid{ luser = LUser, lserver = LServer } = Owner, Access) -> - case acl:match_rule(ServerHost, Access, Owner) of + {ok, HostType} = mongoose_domain_api:get_domain_host_type(ServerHost), + case acl:match_rule(HostType, ServerHost, Access, Owner) of allow -> case node_to_path(Node) of [<<"home">>, LServer, LUser | _] -> {result, true}; diff --git a/src/pubsub/node_pep.erl b/src/pubsub/node_pep.erl index b854ce019b..6daeb2bbf7 100644 --- a/src/pubsub/node_pep.erl +++ b/src/pubsub/node_pep.erl @@ -97,7 +97,8 @@ create_node_permission(Host, _ServerHost, _Node, _ParentNode, {result, true}; % pubsub service always allowed create_node_permission(Host, ServerHost, _Node, _ParentNode, #jid{ luser = User, lserver = Server } = Owner, Access) -> - case acl:match_rule(ServerHost, Access, Owner) of + {ok, HostType} = mongoose_domain_api:get_domain_host_type(ServerHost), + case acl:match_rule(HostType, ServerHost, Access, Owner) of allow -> case Host of {User, Server, _} -> {result, true}; diff --git a/src/shaper_srv.erl b/src/shaper_srv.erl index 7a9aca2514..5d2932bc78 100644 --- a/src/shaper_srv.erl +++ b/src/shaper_srv.erl @@ -204,7 +204,7 @@ default_shaper() -> Action :: atom(), jid:jid(), Default :: 'none') -> 'allow' | 'none'. get_shaper_name(HostType, Domain, Action, FromJID, Default) -> - case acl:match_rule_for_host_type(HostType, Domain, Action, FromJID) of + case acl:match_rule(HostType, Domain, Action, FromJID) of deny -> Default; Value -> Value end. diff --git a/test/acl_SUITE.erl b/test/acl_SUITE.erl index 7668664be8..49ba10362d 100644 --- a/test/acl_SUITE.erl +++ b/test/acl_SUITE.erl @@ -23,7 +23,7 @@ basic_test_cases() -> host_specific_access_rules, global_host_priority, all_and_none_specs, - invalid_spec, + match_domain, different_specs_matching_the_same_user ]. @@ -57,41 +57,46 @@ init_per_testcase(_TC, Config) -> end_per_testcase(_TC, _Config) -> ok. +host_type() -> + <<"test host type">>. + all_rule_returns_allow(_Config) -> JID = jid:make(<<"pawel">>, <<"phost">>, <<"test">>), - ?assertEqual(allow, acl:match_rule(global, all, JID)), - ?assertEqual(allow, acl:match_rule(<<"phost">>, all, JID)), - ?assertEqual(allow, acl:match_rule(<<"localhost">>, all, JID)), + ?assertEqual(allow, acl:match_rule(global, <<"phost">>, all, JID)), + ?assertEqual(allow, acl:match_rule(global, <<"localhost">>, all, JID)), + ?assertEqual(allow, acl:match_rule(host_type(), <<"phost">>, all, JID)), + ?assertEqual(allow, acl:match_rule(host_type(), <<"localhost">>, all, JID)), ok. none_rule_returns_deny(_Config) -> JID = jid:make(<<"gawel">>, <<"phost">>, <<"test">>), - ?assertEqual(deny, acl:match_rule(global, none, JID)), - ?assertEqual(deny, acl:match_rule(<<"phosty">>, none, JID)), - ?assertEqual(deny, acl:match_rule(<<"localhosty">>, none, JID)), + ?assertEqual(deny, acl:match_rule(global, <<"phost">>, none, JID)), + ?assertEqual(deny, acl:match_rule(global, <<"localhost">>, none, JID)), + ?assertEqual(deny, acl:match_rule(host_type(), <<"phost">>, none, JID)), + ?assertEqual(deny, acl:match_rule(host_type(), <<"localhost">>, none, JID)), ok. basic_access_rules(_Config) -> JID = jid:make(<<"pawel">>, <<"phost">>, <<"test">>), %% rule is not defined deny by default - deny - ?assertEqual(deny, (acl:match_rule(global, single_rule, JID))), + ?assertEqual(deny, (acl:match_rule(global, <<"phost">>, single_rule, JID))), %% add the rule and recheck set_global_rule(single_rule, [{allow, all}]), - ?assertEqual(allow, (acl:match_rule(global, single_rule, JID))), + ?assertEqual(allow, (acl:match_rule(global, <<"phost">>, single_rule, JID))), %% override it to deny rule set_global_rule(single_rule, [{deny, all}]), - ?assertEqual(deny, (acl:match_rule(global, single_rule, JID))), + ?assertEqual(deny, (acl:match_rule(global, <<"phost">>, single_rule, JID))), %% deny by default set_global_rule(single_rule, []), - ?assertEqual(deny, (acl:match_rule(global, single_rule, JID))), + ?assertEqual(deny, (acl:match_rule(global, <<"phost">>, single_rule, JID))), %% allow nobody set_global_rule(single_rule, [{allow, none}]), - ?assertEqual(deny, (acl:match_rule(global, single_rule, JID))), + ?assertEqual(deny, (acl:match_rule(global, <<"phost">>, single_rule, JID))), ok. host_specific_access_rules(Config) -> @@ -100,16 +105,16 @@ host_specific_access_rules(Config) -> PozAdmin = jid:make(<<"gawel">>, <<"poznan">>, <<"test">>), Pawel = jid:make(<<"pawel">>, <<"wroclaw">>, <<"test">>), - set_acl(global, admin_poz, {user, <<"gawel">>, <<"poznan">>}), + set_acl(global, admin_poz, #{user => <<"gawel">>, server => <<"poznan">>}), set_host_rule(only_poz_admin, <<"poznan">>, [{allow, admin_poz}, {deny, all}]), set_host_rule(only_poz_admin, <<"wroclaw">>, [{deny, admin_poz}, {allow, all}]), - ?assertEqual(allow, acl:match_rule(<<"poznan">>, only_poz_admin, PozAdmin)), - ?assertEqual(deny, acl:match_rule(<<"poznan">>, only_poz_admin, Pawel)), + ?assertEqual(allow, acl:match_rule(<<"poznan">>, <<"poznan">>, only_poz_admin, PozAdmin)), + ?assertEqual(deny, acl:match_rule(<<"poznan">>, <<"wroclaw">>, only_poz_admin, Pawel)), - ?assertEqual(deny, acl:match_rule(<<"wroclaw">>, only_poz_admin, PozAdmin)), - ?assertEqual(allow, acl:match_rule(<<"wroclaw">>, only_poz_admin, Pawel)), + ?assertEqual(deny, acl:match_rule(<<"wroclaw">>, <<"poznan">>, only_poz_admin, PozAdmin)), + ?assertEqual(allow, acl:match_rule(<<"wroclaw">>, <<"wroclaw">>, only_poz_admin, Pawel)), ok. compound_access_rules(Config) -> @@ -119,17 +124,17 @@ compound_access_rules(Config) -> KrkNormal = jid:make(<<"pawel">>, <<"krakow">>, <<"test">>), %% add admin user rule - set_acl(global, admin_wawa, {user, <<"gawel">>, <<"wawa">>}), - set_acl(global, admin_krakow, {user, <<"gawel">>, <<"krakow">>}), + set_acl(global, admin_wawa, #{user => <<"gawel">>, server => <<"wawa">>}), + set_acl(global, admin_krakow, #{user => <<"gawel">>, server => <<"krakow">>}), set_global_rule(only_krakow_admin, [{allow, admin_krakow}, {deny, all}]), set_global_rule(only_wawa_admin, [{allow, admin_wawa}, {deny, all}]), - ?assertEqual(deny, acl:match_rule(global, only_krakow_admin, KrkNormal)), - ?assertEqual(deny, acl:match_rule(global, only_wawa_admin, KrkNormal)), + ?assertEqual(deny, acl:match_rule(global, <<"krakow">>, only_krakow_admin, KrkNormal)), + ?assertEqual(deny, acl:match_rule(global, <<"krakow">>, only_wawa_admin, KrkNormal)), - ?assertEqual(allow, acl:match_rule(global, only_krakow_admin, KrkAdmin)), - ?assertEqual(deny, acl:match_rule(global, only_wawa_admin, KrkAdmin)), + ?assertEqual(allow, acl:match_rule(global, <<"krakow">>, only_krakow_admin, KrkAdmin)), + ?assertEqual(deny, acl:match_rule(global, <<"krakow">>, only_wawa_admin, KrkAdmin)), ok. global_host_priority(Config) -> @@ -138,8 +143,8 @@ global_host_priority(Config) -> RzeAdmin = jid:make(<<"pawel">>, <<"rzeszow">>, <<"test">>), %% add admin user rule - set_acl(<<"rzeszow">>, admin, {user, <<"pawel">>, <<"rzeszow">>}), - set_acl(global, admin, {user, <<"pawel">>, <<"lublin">>}), + set_acl(<<"rzeszow">>, admin, #{user => <<"pawel">>, server => <<"rzeszow">>}), + set_acl(global, admin, #{user => <<"pawel">>, server => <<"lublin">>}), %% allow only admin set_global_rule(only_admin, [{allow, admin}, {deny, all}]), @@ -149,36 +154,46 @@ global_host_priority(Config) -> set_global_rule(ban_admin, [{allow, all}]), set_host_rule(ban_admin, <<"rzeszow">>, [{deny, admin}, {allow, all}]), - %% host rule is more important than the host one - ?assertEqual(allow, acl:match_rule(<<"rzeszow">>, only_admin, RzeAdmin)), + %% host rule is more important than the global one + ?assertEqual(allow, acl:match_rule(<<"rzeszow">>, <<"rzeszow">>, only_admin, RzeAdmin)), %% host rule applies when global doesn't match and ends up with {allow, all} %% ... - ?assertEqual(deny, acl:match_rule(<<"rzeszow">>, ban_admin, RzeAdmin)), + ?assertEqual(deny, acl:match_rule(<<"rzeszow">>, <<"rzeszow">>, ban_admin, RzeAdmin)), ok. all_and_none_specs(Config) -> given_registered_domains(Config, [<<"zakopane">>]), User = jid:make(<<"pawel">>, <<"zakopane">>, <<"test">>), - set_acl(global, a_users, all), - set_acl(global, n_users, none), + set_acl(global, a_users, #{match => all}), + set_acl(global, n_users, #{match => none}), set_global_rule(all_users, [{allow, a_users}, {deny, all}]), set_global_rule(none_users, [{allow, n_users}, {deny, all}]), - ?assertEqual(allow, acl:match_rule(global, all_users, User)), - ?assertEqual(deny, acl:match_rule(global, none_users, User)), + ?assertEqual(allow, acl:match_rule(global, <<"zakopane">>, all_users, User)), + ?assertEqual(deny, acl:match_rule(global, <<"zakopane">>, none_users, User)), + + %% domain doesn't matter for 'all' + ?assertEqual(allow, acl:match_rule(global, <<"any domain">>, all_users, User)), + ?assertEqual(deny, acl:match_rule(global, <<"any domain">>, none_users, User)), ok. -invalid_spec(Config) -> - given_registered_domains(Config, [<<"bialystok">>]), +match_domain(Config) -> + given_registered_domains(Config, [<<"zakopane">>]), + + UserZa = jid:make(<<"pawel">>, <<"zakopane">>, <<"test">>), + UserGd = jid:make(<<"pawel">>, <<"gdansk">>, <<"test">>), + UserGb = jid:make(<<"pawel">>, <<"gdansk">>, <<"best">>), - User = jid:make(<<"pawel">>, <<"bialystok">>, <<"test">>), - set_acl(global, invalid, {non_existing_spec, "lalala"}), + set_acl(global, a_users, #{resource => <<"test">>}), + set_acl(global, c_users, #{match => all, resource => <<"test">>}), - set_global_rule(invalid, [{allow, invalid}, {deny, all}]), - ?assertEqual(deny, acl:match_rule(global, invalid, User)), + set_global_rule(rule, [{allow, a_users}, {deny, c_users}, {default, all}]), + ?assertEqual(allow, acl:match_rule(global, <<"zakopane">>, rule, UserZa)), + ?assertEqual(deny, acl:match_rule(global, <<"zakopane">>, rule, UserGd)), + ?assertEqual(default, acl:match_rule(global, <<"zakopane">>, rule, UserGb)), ok. match_host_specific_rule_for_host_type(Config) -> @@ -187,26 +202,16 @@ match_host_specific_rule_for_host_type(Config) -> UserGd = jid:make(<<"pawel">>, <<"gdansk">>, <<"res">>), set_host_rule(allow_admin, <<"test type">>, [{allow, admin}, {deny, all}]), - set_acl(<<"test type">>, admin, {user, <<"pawel">>}), + set_acl(<<"test type">>, admin, #{user => <<"pawel">>}), %% Check for host type for a specific domain - ?assertEqual(allow, acl:match_rule_for_host_type(<<"test type">>, <<"gdansk">>, - allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule_for_host_type(<<"test type">>, <<"koszalin">>, - allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule_for_host_type(<<"empty type">>, <<"gdansk">>, - allow_admin, UserGd)), - - %% Check for host type for any domain - ?assertEqual(allow, acl:match_rule_for_host_type(<<"test type">>, global, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule_for_host_type(<<"empty type">>, global, allow_admin, UserGd)), + ?assertEqual(allow, acl:match_rule(<<"test type">>, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(<<"test type">>, <<"koszalin">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(<<"empty type">>, <<"gdansk">>, allow_admin, UserGd)), %% Check globally for a specific domain - ?assertEqual(deny, acl:match_rule_for_host_type(global, <<"gdansk">>, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule_for_host_type(global, <<"koszalin">>, allow_admin, UserGd)), - - %% Check globally for any domain - ?assertEqual(deny, acl:match_rule_for_host_type(global, global, allow_admin, UserGd)). + ?assertEqual(deny, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserGd)). match_global_rule_for_host_type(Config) -> given_registered_domains(Config, [<<"gdansk">>, <<"koszalin">>]), @@ -214,23 +219,15 @@ match_global_rule_for_host_type(Config) -> UserGd = jid:make(<<"pawel">>, <<"gdansk">>, <<"res">>), set_global_rule(allow_admin, [{allow, admin}, {deny, all}]), - set_acl(global, admin, {user, <<"pawel">>}), + set_acl(global, admin, #{user => <<"pawel">>}), %% Check for host type for a specific domain - ?assertEqual(allow, acl:match_rule_for_host_type(<<"test type">>, <<"gdansk">>, - allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule_for_host_type(<<"test type">>, <<"koszalin">>, - allow_admin, UserGd)), - - %% Check for host type for any domain - ?assertEqual(allow, acl:match_rule_for_host_type(<<"test type">>, global, allow_admin, UserGd)), + ?assertEqual(allow, acl:match_rule(<<"test type">>, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(<<"test type">>, <<"koszalin">>, allow_admin, UserGd)), %% Check globally for a specific domain - ?assertEqual(allow, acl:match_rule_for_host_type(global, <<"gdansk">>, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule_for_host_type(global, <<"koszalin">>, allow_admin, UserGd)), - - %% Check globally for any domain - ?assertEqual(allow, acl:match_rule_for_host_type(global, global, allow_admin, UserGd)). + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserGd)). different_specs_matching_the_same_user(Config) -> given_registered_domains(Config, [<<"gdansk">>, <<"koszalin">>]), @@ -242,79 +239,81 @@ different_specs_matching_the_same_user(Config) -> set_global_rule(allow_admin, [{allow, admin}, {deny, all}]), %% match on pawel - set_acl(global, admin, {user, <<"pawel">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{user => <<"pawel">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(allow, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on pawel@gdansk - set_acl(global, admin, {user, <<"pawel">>, <<"gdansk">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{user => <<"pawel">>, server => <<"gdansk">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on gdansk - set_acl(global, admin, {server, <<"gdansk">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{server => <<"gdansk">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on res - set_acl(global, admin, {resource, <<"res">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{resource => <<"res">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on user regex - set_acl(global, admin, {user_regexp, <<"^paw.*">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{user_regexp => <<"^paw.*">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(allow, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on user regex - set_acl(global, admin, {user_regexp, <<"^paw.*">>, <<"gdansk">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{user_regexp => <<"^paw.*">>, server => <<"gdansk">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on server regex - set_acl(global, admin, {server_regexp, <<"^gda.*">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{server_regexp => <<"^gda.*">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on resource regex - set_acl(global, admin, {resource_regexp, <<"^res.*">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{resource_regexp => <<"^res.*">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(allow, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match node regex - set_acl(global, admin, {node_regexp, <<"^pawe.*">>, <<"^gda.*">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{user_regexp => <<"^pawe.*">>, server_regexp => <<"^gda.*">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on user glob - set_acl(global, admin, {user_glob, <<"paw??">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{user_glob => <<"paw??">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(allow, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on user glob - set_acl(global, admin, {user_glob, <<"paw??">>, <<"gdansk">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{user_glob => <<"paw??">>, server => <<"gdansk">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on server glob - set_acl(global, admin, {server_glob, <<"gda*">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{server_glob => <<"gda*">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on server glob - set_acl(global, admin, {resource_glob, <<"re*">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{resource_glob => <<"re*">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(allow, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), %% match on node glob - set_acl(global, admin, {node_glob, <<"pawe?">>, <<"gd*">>}), - ?assertEqual(allow, acl:match_rule(global, allow_admin, UserGd)), - ?assertEqual(deny, acl:match_rule(global, allow_admin, UserKo)), + set_acl(global, admin, #{user_glob => <<"pawe?">>, server_glob => <<"gd*">>}), + ?assertEqual(allow, acl:match_rule(global, <<"gdansk">>, allow_admin, UserGd)), + ?assertEqual(deny, acl:match_rule(global, <<"koszalin">>, allow_admin, UserKo)), ok. set_acl(HostType, ACLName, ACLSpec) -> - mongoose_config:set_opt({acl, ACLName, HostType}, [ACLSpec]). + %% ACL specs match 'current_domain' by default + ACLSpecs = [maps:merge(#{match => current_domain}, ACLSpec)], + mongoose_config:set_opt({acl, ACLName, HostType}, ACLSpecs). given_clean_config() -> [persistent_term:erase(Key) || {Key = {mongoose_config, _}, _Value} <- persistent_term:get()], diff --git a/test/config_parser_SUITE.erl b/test/config_parser_SUITE.erl index 66a139a627..fbe4953111 100644 --- a/test/config_parser_SUITE.erl +++ b/test/config_parser_SUITE.erl @@ -24,6 +24,8 @@ assert_options_host_or_global(ExpectedOpts, RawConfig)). %% host-or-global config error +-define(errh(Pattern, RawConfig), + [?assertMatch(Pattern, Errors) || Errors <- assert_error_host_or_global(RawConfig)]). -define(errh(RawConfig), assert_error_host_or_global(RawConfig)). -import(mongoose_config_parser_toml, [extract_errors/1]). @@ -1325,19 +1327,26 @@ shaper(_Config) -> ?errh(#{<<"shaper">> => #{<<"fast">> => #{}}}). acl(_Config) -> - ?cfgh({acl, local}, [all], + ?cfgh({acl, local}, [#{match => all}], #{<<"acl">> => #{<<"local">> => [#{<<"match">> => <<"all">>}]}}), - ?cfgh({acl, local}, [{user_regexp, <<>>}], + ?cfgh({acl, local}, [#{match => current_domain, + user_regexp => <<>>}], #{<<"acl">> => #{<<"local">> => [#{<<"user_regexp">> => <<>>}]}}), - ?cfgh({acl, alice}, [{node_regexp, <<"ali.*">>, <<".*host">>}], - #{<<"acl">> => #{<<"alice">> => [#{<<"user_regexp">> => <<"ali.*">>, - <<"server_regexp">> => <<".*host">>}]}}), - ?cfgh({acl, alice}, [{user, <<"alice">>, <<"localhost">>}], + ?cfgh({acl, alice}, [#{match => current_domain, + user_regexp => <<"ali.*">>, + server_regexp => <<".*host">>}], + #{<<"acl">> => #{<<"alice">> => [#{<<"user_regexp">> => <<"aLi.*">>, + <<"server_regexp">> => <<".*HosT">>}]}}), + ?cfgh({acl, alice}, [#{match => current_domain, + user => <<"alice">>, + server => <<"localhost">>}], #{<<"acl">> => #{<<"alice">> => [#{<<"user">> => <<"alice">>, <<"server">> => <<"localhost">>}]}}), ?errh(#{<<"acl">> => #{<<"local">> => <<"everybody">>}}), ?errh(#{<<"acl">> => #{<<"alice">> => [#{<<"user_glob">> => <<"a*">>, - <<"server_blog">> => <<"bloghost">>}]}}). + <<"server_blog">> => <<"bloghost">>}]}}), + ?errh([#{reason := incorrect_acl_condition_value}], + #{<<"acl">> => #{<<"local">> => [#{<<"user">> => <<"@@@">>}]}}). access(_Config) -> ?cfgh({access, c2s}, [{deny, blocked}, {allow, all}], @@ -3075,10 +3084,11 @@ host_key([TopKey | Rest], HostType) when is_atom(TopKey) -> host_key(Key, HostType) when is_atom(Key) -> {Key, HostType}. --spec assert_error_host_or_global(mongoose_config_parser_toml:toml_section()) -> any(). +-spec assert_error_host_or_global(mongoose_config_parser_toml:toml_section()) -> + [[mongoose_config_parser_toml:config_error()]]. assert_error_host_or_global(RawConfig) -> - assert_error(parse(RawConfig)), - assert_error(parse(host_config(RawConfig))). + [assert_error(parse(RawConfig)), + assert_error(parse(host_config(RawConfig)))]. host_config(Config) -> #{<<"host_config">> => [Config#{<<"host_type">> => ?HOST_TYPE}]}. diff --git a/test/config_parser_helper.erl b/test/config_parser_helper.erl index 289dba5d7e..7613cf1a42 100644 --- a/test/config_parser_helper.erl +++ b/test/config_parser_helper.erl @@ -290,7 +290,7 @@ options("mongooseim-pgsql") -> {{access, muc_create, global}, [{allow, local}]}, {{access, register, global}, [{allow, all}]}, {{access, s2s_shaper, global}, [{fast, all}]}, - {{acl, local, global}, [{user_regexp, <<>>}]}, + {{acl, local, global}, [#{user_regexp => <<>>, match => current_domain}]}, {{shaper, fast, global}, {maxrate, 50000}}, {{shaper, mam_global_shaper, global}, {maxrate, 1000}}, {{shaper, mam_shaper, global}, {maxrate, 1}},