chore(authz): use atom key for hocon config
This commit is contained in:
parent
47ce507c07
commit
bf4c31b745
|
@ -1,4 +1,4 @@
|
||||||
authz:{
|
emqx_authz:{
|
||||||
rules: [
|
rules: [
|
||||||
# {
|
# {
|
||||||
# type: mysql
|
# type: mysql
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
-type(rule() :: #{binary() => any()}).
|
-type(rule() :: #{atom() => any()}).
|
||||||
-type(rules() :: [rule()]).
|
-type(rules() :: [rule()]).
|
||||||
|
|
||||||
-define(APP, emqx_authz).
|
-define(APP, emqx_authz).
|
||||||
|
|
|
@ -38,16 +38,17 @@ init() ->
|
||||||
ok = register_metrics(),
|
ok = register_metrics(),
|
||||||
Conf = filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'),
|
Conf = filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'),
|
||||||
{ok, RawConf} = hocon:load(Conf),
|
{ok, RawConf} = hocon:load(Conf),
|
||||||
#{<<"authz">> := #{<<"rules">> := Rules}} = hocon_schema:check_plain(emqx_authz_schema, RawConf),
|
#{emqx_authz := #{rules := Rules}} = hocon_schema:check_plain(emqx_authz_schema, RawConf, #{atom_key => true}),
|
||||||
ok = application:set_env(?APP, rules, Rules),
|
emqx_config:put([emqx_authz], #{rules => Rules}),
|
||||||
|
% Rules = emqx_config:get([emqx_authz, rules], []),
|
||||||
NRules = [compile(Rule) || Rule <- Rules],
|
NRules = [compile(Rule) || Rule <- Rules],
|
||||||
ok = emqx_hooks:add('client.authorize', {?MODULE, authorize, [NRules]}, -1).
|
ok = emqx_hooks:add('client.authorize', {?MODULE, authorize, [NRules]}, -1).
|
||||||
|
|
||||||
lookup() ->
|
lookup() ->
|
||||||
application:get_env(?APP, rules, []).
|
emqx_config:get([emqx_authz, rules], []).
|
||||||
|
|
||||||
update(Rules) ->
|
update(Rules) ->
|
||||||
ok = application:set_env(?APP, rules, Rules),
|
emqx_config:put([emqx_authz], #{rules => Rules}),
|
||||||
NRules = [compile(Rule) || Rule <- Rules],
|
NRules = [compile(Rule) || Rule <- Rules],
|
||||||
Action = find_action_in_hooks(),
|
Action = find_action_in_hooks(),
|
||||||
ok = emqx_hooks:del('client.authorize', Action),
|
ok = emqx_hooks:del('client.authorize', Action),
|
||||||
|
@ -63,12 +64,12 @@ find_action_in_hooks() ->
|
||||||
[Action] = [Action || {callback,{?MODULE, authorize, _} = Action, _, _} <- Callbacks ],
|
[Action] = [Action || {callback,{?MODULE, authorize, _} = Action, _, _} <- Callbacks ],
|
||||||
Action.
|
Action.
|
||||||
|
|
||||||
create_resource(#{<<"type">> := DB,
|
create_resource(#{type := DB,
|
||||||
<<"config">> := Config
|
config := Config
|
||||||
} = Rule) ->
|
} = Rule) ->
|
||||||
ResourceID = iolist_to_binary([io_lib:format("~s_~s",[?APP, DB]), "_", integer_to_list(erlang:system_time())]),
|
ResourceID = iolist_to_binary([io_lib:format("~s_~s",[?APP, DB]), "_", integer_to_list(erlang:system_time())]),
|
||||||
NConfig = case DB of
|
NConfig = case DB of
|
||||||
redis -> #{<<"config">> => Config };
|
redis -> #{config => Config };
|
||||||
_ -> Config
|
_ -> Config
|
||||||
end,
|
end,
|
||||||
case emqx_resource:check_and_create(
|
case emqx_resource:check_and_create(
|
||||||
|
@ -77,63 +78,63 @@ create_resource(#{<<"type">> := DB,
|
||||||
NConfig)
|
NConfig)
|
||||||
of
|
of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
Rule#{<<"resource_id">> => ResourceID};
|
Rule#{resource_id => ResourceID};
|
||||||
{error, already_created} ->
|
{error, already_created} ->
|
||||||
Rule#{<<"resource_id">> => ResourceID};
|
Rule#{resource_id => ResourceID};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
error({load_config_error, Reason})
|
error({load_config_error, Reason})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(compile(rule()) -> rule()).
|
-spec(compile(rule()) -> rule()).
|
||||||
compile(#{<<"topics">> := Topics,
|
compile(#{topics := Topics,
|
||||||
<<"action">> := Action,
|
action := Action,
|
||||||
<<"permission">> := Permission,
|
permission := Permission,
|
||||||
<<"principal">> := Principal
|
principal := Principal
|
||||||
} = Rule) when ?ALLOW_DENY(Permission), ?PUBSUB(Action), is_list(Topics) ->
|
} = Rule) when ?ALLOW_DENY(Permission), ?PUBSUB(Action), is_list(Topics) ->
|
||||||
NTopics = [compile_topic(Topic) || Topic <- Topics],
|
NTopics = [compile_topic(Topic) || Topic <- Topics],
|
||||||
Rule#{<<"principal">> => compile_principal(Principal),
|
Rule#{principal => compile_principal(Principal),
|
||||||
<<"topics">> => NTopics
|
topics => NTopics
|
||||||
};
|
};
|
||||||
|
|
||||||
compile(#{<<"principal">> := Principal,
|
compile(#{principal := Principal,
|
||||||
<<"type">> := redis
|
type := redis
|
||||||
} = Rule) ->
|
} = Rule) ->
|
||||||
NRule = create_resource(Rule),
|
NRule = create_resource(Rule),
|
||||||
NRule#{<<"principal">> => compile_principal(Principal)};
|
NRule#{principal => compile_principal(Principal)};
|
||||||
|
|
||||||
compile(#{<<"principal">> := Principal,
|
compile(#{principal := Principal,
|
||||||
<<"type">> := DB,
|
type := DB,
|
||||||
<<"sql">> := SQL
|
sql := SQL
|
||||||
} = Rule) when DB =:= mysql;
|
} = Rule) when DB =:= mysql;
|
||||||
DB =:= pgsql ->
|
DB =:= pgsql ->
|
||||||
Mod = list_to_existing_atom(io_lib:format("~s_~s",[?APP, DB])),
|
Mod = list_to_existing_atom(io_lib:format("~s_~s",[?APP, DB])),
|
||||||
NRule = create_resource(Rule),
|
NRule = create_resource(Rule),
|
||||||
NRule#{<<"principal">> => compile_principal(Principal),
|
NRule#{principal => compile_principal(Principal),
|
||||||
<<"sql">> => Mod:parse_query(SQL)
|
sql => Mod:parse_query(SQL)
|
||||||
}.
|
}.
|
||||||
|
|
||||||
compile_principal(all) -> all;
|
compile_principal(all) -> all;
|
||||||
compile_principal(#{<<"username">> := Username}) ->
|
compile_principal(#{username := Username}) ->
|
||||||
{ok, MP} = re:compile(bin(Username)),
|
{ok, MP} = re:compile(bin(Username)),
|
||||||
#{<<"username">> => MP};
|
#{username => MP};
|
||||||
compile_principal(#{<<"clientid">> := Clientid}) ->
|
compile_principal(#{clientid := Clientid}) ->
|
||||||
{ok, MP} = re:compile(bin(Clientid)),
|
{ok, MP} = re:compile(bin(Clientid)),
|
||||||
#{<<"clientid">> => MP};
|
#{clientid => MP};
|
||||||
compile_principal(#{<<"ipaddress">> := IpAddress}) ->
|
compile_principal(#{ipaddress := IpAddress}) ->
|
||||||
#{<<"ipaddress">> => esockd_cidr:parse(b2l(IpAddress), true)};
|
#{ipaddress => esockd_cidr:parse(b2l(IpAddress), true)};
|
||||||
compile_principal(#{<<"and">> := Principals}) when is_list(Principals) ->
|
compile_principal(#{'and' := Principals}) when is_list(Principals) ->
|
||||||
#{<<"and">> => [compile_principal(Principal) || Principal <- Principals]};
|
#{'and' => [compile_principal(Principal) || Principal <- Principals]};
|
||||||
compile_principal(#{<<"or">> := Principals}) when is_list(Principals) ->
|
compile_principal(#{'or' := Principals}) when is_list(Principals) ->
|
||||||
#{<<"or">> => [compile_principal(Principal) || Principal <- Principals]}.
|
#{'or' => [compile_principal(Principal) || Principal <- Principals]}.
|
||||||
|
|
||||||
compile_topic(<<"eq ", Topic/binary>>) ->
|
compile_topic(<<"eq ", Topic/binary>>) ->
|
||||||
compile_topic(#{<<"eq">> => Topic});
|
compile_topic(#{'eq' => Topic});
|
||||||
compile_topic(#{<<"eq">> := Topic}) ->
|
compile_topic(#{'eq' := Topic}) ->
|
||||||
#{<<"eq">> => emqx_topic:words(bin(Topic))};
|
#{'eq' => emqx_topic:words(bin(Topic))};
|
||||||
compile_topic(Topic) when is_binary(Topic)->
|
compile_topic(Topic) when is_binary(Topic)->
|
||||||
Words = emqx_topic:words(bin(Topic)),
|
Words = emqx_topic:words(bin(Topic)),
|
||||||
case pattern(Words) of
|
case pattern(Words) of
|
||||||
true -> #{<<"pattern">> => Words};
|
true -> #{pattern => Words};
|
||||||
false -> Words
|
false -> Words
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -173,8 +174,8 @@ authorize(#{username := Username,
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_authorize(Client, PubSub, Topic,
|
do_authorize(Client, PubSub, Topic,
|
||||||
[Connector = #{<<"principal">> := Principal,
|
[Connector = #{principal := Principal,
|
||||||
<<"type">> := DB} | Tail] ) ->
|
type := DB} | Tail] ) ->
|
||||||
case match_principal(Client, Principal) of
|
case match_principal(Client, Principal) of
|
||||||
true ->
|
true ->
|
||||||
Mod = list_to_existing_atom(io_lib:format("~s_~s",[emqx_authz, DB])),
|
Mod = list_to_existing_atom(io_lib:format("~s_~s",[emqx_authz, DB])),
|
||||||
|
@ -185,7 +186,7 @@ do_authorize(Client, PubSub, Topic,
|
||||||
false -> do_authorize(Client, PubSub, Topic, Tail)
|
false -> do_authorize(Client, PubSub, Topic, Tail)
|
||||||
end;
|
end;
|
||||||
do_authorize(Client, PubSub, Topic,
|
do_authorize(Client, PubSub, Topic,
|
||||||
[#{<<"permission">> := Permission} = Rule | Tail]) ->
|
[#{permission := Permission} = Rule | Tail]) ->
|
||||||
case match(Client, PubSub, Topic, Rule) of
|
case match(Client, PubSub, Topic, Rule) of
|
||||||
true -> {matched, Permission};
|
true -> {matched, Permission};
|
||||||
false -> do_authorize(Client, PubSub, Topic, Tail)
|
false -> do_authorize(Client, PubSub, Topic, Tail)
|
||||||
|
@ -193,9 +194,9 @@ do_authorize(Client, PubSub, Topic,
|
||||||
do_authorize(_Client, _PubSub, _Topic, []) -> nomatch.
|
do_authorize(_Client, _PubSub, _Topic, []) -> nomatch.
|
||||||
|
|
||||||
match(Client, PubSub, Topic,
|
match(Client, PubSub, Topic,
|
||||||
#{<<"principal">> := Principal,
|
#{principal := Principal,
|
||||||
<<"topics">> := TopicFilters,
|
topics := TopicFilters,
|
||||||
<<"action">> := Action
|
action := Action
|
||||||
}) ->
|
}) ->
|
||||||
match_action(PubSub, Action) andalso
|
match_action(PubSub, Action) andalso
|
||||||
match_principal(Client, Principal) andalso
|
match_principal(Client, Principal) andalso
|
||||||
|
@ -207,27 +208,27 @@ match_action(_, all) -> true;
|
||||||
match_action(_, _) -> false.
|
match_action(_, _) -> false.
|
||||||
|
|
||||||
match_principal(_, all) -> true;
|
match_principal(_, all) -> true;
|
||||||
match_principal(#{username := undefined}, #{<<"username">> := _MP}) ->
|
match_principal(#{username := undefined}, #{username := _MP}) ->
|
||||||
false;
|
false;
|
||||||
match_principal(#{username := Username}, #{<<"username">> := MP}) ->
|
match_principal(#{username := Username}, #{username := MP}) ->
|
||||||
case re:run(Username, MP) of
|
case re:run(Username, MP) of
|
||||||
{match, _} -> true;
|
{match, _} -> true;
|
||||||
_ -> false
|
_ -> false
|
||||||
end;
|
end;
|
||||||
match_principal(#{clientid := Clientid}, #{<<"clientid">> := MP}) ->
|
match_principal(#{clientid := Clientid}, #{clientid := MP}) ->
|
||||||
case re:run(Clientid, MP) of
|
case re:run(Clientid, MP) of
|
||||||
{match, _} -> true;
|
{match, _} -> true;
|
||||||
_ -> false
|
_ -> false
|
||||||
end;
|
end;
|
||||||
match_principal(#{peerhost := undefined}, #{<<"ipaddress">> := _CIDR}) ->
|
match_principal(#{peerhost := undefined}, #{ipaddress := _CIDR}) ->
|
||||||
false;
|
false;
|
||||||
match_principal(#{peerhost := IpAddress}, #{<<"ipaddress">> := CIDR}) ->
|
match_principal(#{peerhost := IpAddress}, #{ipaddress := CIDR}) ->
|
||||||
esockd_cidr:match(IpAddress, CIDR);
|
esockd_cidr:match(IpAddress, CIDR);
|
||||||
match_principal(ClientInfo, #{<<"and">> := Principals}) when is_list(Principals) ->
|
match_principal(ClientInfo, #{'and' := Principals}) when is_list(Principals) ->
|
||||||
lists:foldl(fun(Principal, Permission) ->
|
lists:foldl(fun(Principal, Permission) ->
|
||||||
match_principal(ClientInfo, Principal) andalso Permission
|
match_principal(ClientInfo, Principal) andalso Permission
|
||||||
end, true, Principals);
|
end, true, Principals);
|
||||||
match_principal(ClientInfo, #{<<"or">> := Principals}) when is_list(Principals) ->
|
match_principal(ClientInfo, #{'or' := Principals}) when is_list(Principals) ->
|
||||||
lists:foldl(fun(Principal, Permission) ->
|
lists:foldl(fun(Principal, Permission) ->
|
||||||
match_principal(ClientInfo, Principal) orelse Permission
|
match_principal(ClientInfo, Principal) orelse Permission
|
||||||
end, false, Principals);
|
end, false, Principals);
|
||||||
|
@ -235,7 +236,7 @@ match_principal(_, _) -> false.
|
||||||
|
|
||||||
match_topics(_ClientInfo, _Topic, []) ->
|
match_topics(_ClientInfo, _Topic, []) ->
|
||||||
false;
|
false;
|
||||||
match_topics(ClientInfo, Topic, [#{<<"pattern">> := PatternFilter}|Filters]) ->
|
match_topics(ClientInfo, Topic, [#{pattern := PatternFilter}|Filters]) ->
|
||||||
TopicFilter = feed_var(ClientInfo, PatternFilter),
|
TopicFilter = feed_var(ClientInfo, PatternFilter),
|
||||||
match_topic(emqx_topic:words(Topic), TopicFilter)
|
match_topic(emqx_topic:words(Topic), TopicFilter)
|
||||||
orelse match_topics(ClientInfo, Topic, Filters);
|
orelse match_topics(ClientInfo, Topic, Filters);
|
||||||
|
@ -243,7 +244,7 @@ match_topics(ClientInfo, Topic, [TopicFilter|Filters]) ->
|
||||||
match_topic(emqx_topic:words(Topic), TopicFilter)
|
match_topic(emqx_topic:words(Topic), TopicFilter)
|
||||||
orelse match_topics(ClientInfo, Topic, Filters).
|
orelse match_topics(ClientInfo, Topic, Filters).
|
||||||
|
|
||||||
match_topic(Topic, #{<<"eq">> := TopicFilter}) ->
|
match_topic(Topic, #{'eq' := TopicFilter}) ->
|
||||||
Topic == TopicFilter;
|
Topic == TopicFilter;
|
||||||
match_topic(Topic, TopicFilter) ->
|
match_topic(Topic, TopicFilter) ->
|
||||||
emqx_topic:match(Topic, TopicFilter).
|
emqx_topic:match(Topic, TopicFilter).
|
||||||
|
|
|
@ -74,10 +74,9 @@ push_authz(_Bindings, Params) ->
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
get_rules(Params) ->
|
get_rules(Params) ->
|
||||||
% #{<<"authz">> := #{<<"rules">> := Rules}} = hocon_schema:check_plain(emqx_authz_schema, #{<<"authz">> => Params}),
|
{ok, Conf} = hocon:binary(jsx:encode(#{<<"emqx_authz">> => Params}), #{format => richmap}),
|
||||||
{ok, Conf} = hocon:binary(jsx:encode(#{<<"authz">> => Params}), #{format => richmap}),
|
CheckConf = hocon_schema:check(emqx_authz_schema, Conf, #{atom_key => true}),
|
||||||
CheckConf = hocon_schema:check(emqx_authz_schema, Conf),
|
#{emqx_authz := #{rules := Rules}} = hocon_schema:richmap_to_map(CheckConf),
|
||||||
#{<<"authz">> := #{<<"rules">> := Rules}} = hocon_schema:richmap_to_map(CheckConf),
|
|
||||||
Rules.
|
Rules.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -46,8 +46,8 @@ parse_query(Sql) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
authorize(Client, PubSub, Topic,
|
authorize(Client, PubSub, Topic,
|
||||||
#{<<"resource_id">> := ResourceID,
|
#{resource_id := ResourceID,
|
||||||
<<"sql">> := {SQL, Params}
|
sql := {SQL, Params}
|
||||||
}) ->
|
}) ->
|
||||||
case emqx_resource:query(ResourceID, {sql, SQL, replvar(Params, Client)}) of
|
case emqx_resource:query(ResourceID, {sql, SQL, replvar(Params, Client)}) of
|
||||||
{ok, _Columns, []} -> nomatch;
|
{ok, _Columns, []} -> nomatch;
|
||||||
|
@ -87,12 +87,12 @@ match(Client, PubSub, Topic,
|
||||||
<<"action">> => Action,
|
<<"action">> => Action,
|
||||||
<<"permission">> => Permission
|
<<"permission">> => Permission
|
||||||
},
|
},
|
||||||
#{<<"simple_rule">> :=
|
#{simple_rule :=
|
||||||
#{<<"permission">> := NPermission} = NRule
|
#{permission := NPermission} = NRule
|
||||||
} = hocon_schema:check_plain(
|
} = hocon_schema:check_plain(
|
||||||
emqx_authz_schema,
|
emqx_authz_schema,
|
||||||
#{<<"simple_rule">> => Rule},
|
#{<<"simple_rule">> => Rule},
|
||||||
#{},
|
#{atom_key => true},
|
||||||
[simple_rule]),
|
[simple_rule]),
|
||||||
case emqx_authz:match(Client, PubSub, Topic, emqx_authz:compile(NRule)) of
|
case emqx_authz:match(Client, PubSub, Topic, emqx_authz:compile(NRule)) of
|
||||||
true -> {matched, NPermission};
|
true -> {matched, NPermission};
|
||||||
|
|
|
@ -50,8 +50,8 @@ parse_query(Sql) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
authorize(Client, PubSub, Topic,
|
authorize(Client, PubSub, Topic,
|
||||||
#{<<"resource_id">> := ResourceID,
|
#{resource_id := ResourceID,
|
||||||
<<"sql">> := {SQL, Params}
|
sql := {SQL, Params}
|
||||||
}) ->
|
}) ->
|
||||||
case emqx_resource:query(ResourceID, {sql, SQL, replvar(Params, Client)}) of
|
case emqx_resource:query(ResourceID, {sql, SQL, replvar(Params, Client)}) of
|
||||||
{ok, _Columns, []} -> nomatch;
|
{ok, _Columns, []} -> nomatch;
|
||||||
|
@ -91,12 +91,12 @@ match(Client, PubSub, Topic,
|
||||||
<<"action">> => Action,
|
<<"action">> => Action,
|
||||||
<<"permission">> => Permission
|
<<"permission">> => Permission
|
||||||
},
|
},
|
||||||
#{<<"simple_rule">> :=
|
#{simple_rule :=
|
||||||
#{<<"permission">> := NPermission} = NRule
|
#{permission := NPermission} = NRule
|
||||||
} = hocon_schema:check_plain(
|
} = hocon_schema:check_plain(
|
||||||
emqx_authz_schema,
|
emqx_authz_schema,
|
||||||
#{<<"simple_rule">> => Rule},
|
#{<<"simple_rule">> => Rule},
|
||||||
#{},
|
#{atom_key => true},
|
||||||
[simple_rule]),
|
[simple_rule]),
|
||||||
case emqx_authz:match(Client, PubSub, Topic, emqx_authz:compile(NRule)) of
|
case emqx_authz:match(Client, PubSub, Topic, emqx_authz:compile(NRule)) of
|
||||||
true -> {matched, NPermission};
|
true -> {matched, NPermission};
|
||||||
|
|
|
@ -34,8 +34,8 @@ description() ->
|
||||||
"AuthZ with redis".
|
"AuthZ with redis".
|
||||||
|
|
||||||
authorize(Client, PubSub, Topic,
|
authorize(Client, PubSub, Topic,
|
||||||
#{<<"resource_id">> := ResourceID,
|
#{resource_id := ResourceID,
|
||||||
<<"cmd">> := CMD
|
cmd := CMD
|
||||||
}) ->
|
}) ->
|
||||||
NCMD = string:tokens(replvar(CMD, Client), " "),
|
NCMD = string:tokens(replvar(CMD, Client), " "),
|
||||||
case emqx_resource:query(ResourceID, {cmd, NCMD}) of
|
case emqx_resource:query(ResourceID, {cmd, NCMD}) of
|
||||||
|
@ -68,11 +68,11 @@ match(Client, PubSub, Topic,
|
||||||
<<"action">> => Action,
|
<<"action">> => Action,
|
||||||
<<"permission">> => allow
|
<<"permission">> => allow
|
||||||
},
|
},
|
||||||
#{<<"simple_rule">> := NRule
|
#{simple_rule := NRule
|
||||||
} = hocon_schema:check_plain(
|
} = hocon_schema:check_plain(
|
||||||
emqx_authz_schema,
|
emqx_authz_schema,
|
||||||
#{<<"simple_rule">> => Rule},
|
#{<<"simple_rule">> => Rule},
|
||||||
#{},
|
#{atom_key => true},
|
||||||
[simple_rule]),
|
[simple_rule]),
|
||||||
case emqx_authz:match(Client, PubSub, Topic, emqx_authz:compile(NRule)) of
|
case emqx_authz:match(Client, PubSub, Topic, emqx_authz:compile(NRule)) of
|
||||||
true -> {matched, allow};
|
true -> {matched, allow};
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
|
|
||||||
-export([structs/0, fields/1]).
|
-export([structs/0, fields/1]).
|
||||||
|
|
||||||
structs() -> [authz].
|
structs() -> ["emqx_authz"].
|
||||||
|
|
||||||
fields(authz) ->
|
fields("emqx_authz") ->
|
||||||
[ {rules, rules()}
|
[ {rules, rules()}
|
||||||
];
|
];
|
||||||
fields(redis_connector) ->
|
fields(redis_connector) ->
|
||||||
|
@ -39,7 +39,7 @@ fields(simple_rule) ->
|
||||||
, {action, #{type => action()}}
|
, {action, #{type => action()}}
|
||||||
, {topics, #{type => union_array(
|
, {topics, #{type => union_array(
|
||||||
[ binary()
|
[ binary()
|
||||||
, hoconsc:ref(eq_topic)
|
, hoconsc:ref(?MODULE, eq_topic)
|
||||||
]
|
]
|
||||||
)}}
|
)}}
|
||||||
, {principal, principal()}
|
, {principal, principal()}
|
||||||
|
@ -52,18 +52,18 @@ fields(ipaddress) ->
|
||||||
[{ipaddress, #{type => string()}}];
|
[{ipaddress, #{type => string()}}];
|
||||||
fields(andlist) ->
|
fields(andlist) ->
|
||||||
[{'and', #{type => union_array(
|
[{'and', #{type => union_array(
|
||||||
[ hoconsc:ref(username)
|
[ hoconsc:ref(?MODULE, username)
|
||||||
, hoconsc:ref(clientid)
|
, hoconsc:ref(?MODULE, clientid)
|
||||||
, hoconsc:ref(ipaddress)
|
, hoconsc:ref(?MODULE, ipaddress)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
fields(orlist) ->
|
fields(orlist) ->
|
||||||
[{'or', #{type => union_array(
|
[{'or', #{type => union_array(
|
||||||
[ hoconsc:ref(username)
|
[ hoconsc:ref(?MODULE, username)
|
||||||
, hoconsc:ref(clientid)
|
, hoconsc:ref(?MODULE, clientid)
|
||||||
, hoconsc:ref(ipaddress)
|
, hoconsc:ref(?MODULE, ipaddress)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,9 +81,9 @@ union_array(Item) when is_list(Item) ->
|
||||||
|
|
||||||
rules() ->
|
rules() ->
|
||||||
#{type => union_array(
|
#{type => union_array(
|
||||||
[ hoconsc:ref(simple_rule)
|
[ hoconsc:ref(?MODULE, simple_rule)
|
||||||
, hoconsc:ref(sql_connector)
|
, hoconsc:ref(?MODULE, sql_connector)
|
||||||
, hoconsc:ref(redis_connector)
|
, hoconsc:ref(?MODULE, redis_connector)
|
||||||
])
|
])
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
@ -91,11 +91,11 @@ principal() ->
|
||||||
#{default => all,
|
#{default => all,
|
||||||
type => hoconsc:union(
|
type => hoconsc:union(
|
||||||
[ all
|
[ all
|
||||||
, hoconsc:ref(username)
|
, hoconsc:ref(?MODULE, username)
|
||||||
, hoconsc:ref(clientid)
|
, hoconsc:ref(?MODULE, clientid)
|
||||||
, hoconsc:ref(ipaddress)
|
, hoconsc:ref(?MODULE, ipaddress)
|
||||||
, hoconsc:ref(andlist)
|
, hoconsc:ref(?MODULE, andlist)
|
||||||
, hoconsc:ref(orlist)
|
, hoconsc:ref(?MODULE, orlist)
|
||||||
])
|
])
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
|
|
@ -43,41 +43,42 @@ set_special_configs(emqx) ->
|
||||||
set_special_configs(emqx_authz) ->
|
set_special_configs(emqx_authz) ->
|
||||||
application:set_env(emqx, plugins_etc_dir,
|
application:set_env(emqx, plugins_etc_dir,
|
||||||
emqx_ct_helpers:deps_path(emqx_authz, "test")),
|
emqx_ct_helpers:deps_path(emqx_authz, "test")),
|
||||||
Conf = #{<<"authz">> => #{<<"rules">> => []}},
|
Conf = #{<<"emqx_authz">> => #{<<"rules">> => []}},
|
||||||
ok = file:write_file(filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'), jsx:encode(Conf)),
|
ok = file:write_file(filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'), jsx:encode(Conf)),
|
||||||
|
% emqx_config:put([emqx_authz], #{rules => []}),
|
||||||
ok;
|
ok;
|
||||||
set_special_configs(_App) ->
|
set_special_configs(_App) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
-define(RULE1, #{<<"principal">> => all,
|
-define(RULE1, #{principal => all,
|
||||||
<<"topics">> => [<<"#">>],
|
topics => [<<"#">>],
|
||||||
<<"action">> => all,
|
action => all,
|
||||||
<<"permission">> => deny}
|
permission => deny}
|
||||||
).
|
).
|
||||||
-define(RULE2, #{<<"principal">> =>
|
-define(RULE2, #{principal =>
|
||||||
#{<<"ipaddress">> => <<"127.0.0.1">>},
|
#{ipaddress => <<"127.0.0.1">>},
|
||||||
<<"topics">> =>
|
topics =>
|
||||||
[#{<<"eq">> => <<"#">>},
|
[#{eq => <<"#">>},
|
||||||
#{<<"eq">> => <<"+">>}
|
#{eq => <<"+">>}
|
||||||
] ,
|
] ,
|
||||||
<<"action">> => all,
|
action => all,
|
||||||
<<"permission">> => allow}
|
permission => allow}
|
||||||
).
|
).
|
||||||
-define(RULE3,#{<<"principal">> =>
|
-define(RULE3,#{principal =>
|
||||||
#{<<"and">> => [#{<<"username">> => "^test?"},
|
#{'and' => [#{username => "^test?"},
|
||||||
#{<<"clientid">> => "^test?"}
|
#{clientid => "^test?"}
|
||||||
]},
|
]},
|
||||||
<<"topics">> => [<<"test">>],
|
topics => [<<"test">>],
|
||||||
<<"action">> => publish,
|
action => publish,
|
||||||
<<"permission">> => allow}
|
permission => allow}
|
||||||
).
|
).
|
||||||
-define(RULE4,#{<<"principal">> =>
|
-define(RULE4,#{principal =>
|
||||||
#{<<"or">> => [#{<<"username">> => <<"^test">>},
|
#{'or' => [#{username => <<"^test">>},
|
||||||
#{<<"clientid">> => <<"test?">>}
|
#{clientid => <<"test?">>}
|
||||||
]},
|
]},
|
||||||
<<"topics">> => [<<"%u">>,<<"%c">>],
|
topics => [<<"%u">>,<<"%c">>],
|
||||||
<<"action">> => publish,
|
action => publish,
|
||||||
<<"permission">> => deny}
|
permission => deny}
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,38 +86,38 @@ set_special_configs(_App) ->
|
||||||
%% Testcases
|
%% Testcases
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
t_compile(_) ->
|
t_compile(_) ->
|
||||||
?assertEqual(#{<<"permission">> => deny,
|
?assertEqual(#{permission => deny,
|
||||||
<<"action">> => all,
|
action => all,
|
||||||
<<"principal">> => all,
|
principal => all,
|
||||||
<<"topics">> => [['#']]
|
topics => [['#']]
|
||||||
},emqx_authz:compile(?RULE1)),
|
},emqx_authz:compile(?RULE1)),
|
||||||
?assertEqual(#{<<"permission">> => allow,
|
?assertEqual(#{permission => allow,
|
||||||
<<"action">> => all,
|
action => all,
|
||||||
<<"principal">> =>
|
principal =>
|
||||||
#{<<"ipaddress">> => {{127,0,0,1},{127,0,0,1},32}},
|
#{ipaddress => {{127,0,0,1},{127,0,0,1},32}},
|
||||||
<<"topics">> => [#{<<"eq">> => ['#']},
|
topics => [#{eq => ['#']},
|
||||||
#{<<"eq">> => ['+']}]
|
#{eq => ['+']}]
|
||||||
}, emqx_authz:compile(?RULE2)),
|
}, emqx_authz:compile(?RULE2)),
|
||||||
?assertMatch(
|
?assertMatch(
|
||||||
#{<<"permission">> := allow,
|
#{permission := allow,
|
||||||
<<"action">> := publish,
|
action := publish,
|
||||||
<<"principal">> :=
|
principal :=
|
||||||
#{<<"and">> := [#{<<"username">> := {re_pattern, _, _, _, _}},
|
#{'and' := [#{username := {re_pattern, _, _, _, _}},
|
||||||
#{<<"clientid">> := {re_pattern, _, _, _, _}}
|
#{clientid := {re_pattern, _, _, _, _}}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
<<"topics">> := [[<<"test">>]]
|
topics := [[<<"test">>]]
|
||||||
}, emqx_authz:compile(?RULE3)),
|
}, emqx_authz:compile(?RULE3)),
|
||||||
?assertMatch(
|
?assertMatch(
|
||||||
#{<<"permission">> := deny,
|
#{permission := deny,
|
||||||
<<"action">> := publish,
|
action := publish,
|
||||||
<<"principal">> :=
|
principal :=
|
||||||
#{<<"or">> := [#{<<"username">> := {re_pattern, _, _, _, _}},
|
#{'or' := [#{username := {re_pattern, _, _, _, _}},
|
||||||
#{<<"clientid">> := {re_pattern, _, _, _, _}}
|
#{clientid := {re_pattern, _, _, _, _}}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
<<"topics">> := [#{<<"pattern">> := [<<"%u">>]},
|
topics := [#{pattern := [<<"%u">>]},
|
||||||
#{<<"pattern">> := [<<"%c">>]}
|
#{pattern := [<<"%c">>]}
|
||||||
]
|
]
|
||||||
}, emqx_authz:compile(?RULE4)),
|
}, emqx_authz:compile(?RULE4)),
|
||||||
ok.
|
ok.
|
||||||
|
|
|
@ -57,11 +57,10 @@ set_special_configs(emqx) ->
|
||||||
set_special_configs(emqx_authz) ->
|
set_special_configs(emqx_authz) ->
|
||||||
application:set_env(emqx, plugins_etc_dir,
|
application:set_env(emqx, plugins_etc_dir,
|
||||||
emqx_ct_helpers:deps_path(emqx_authz, "test")),
|
emqx_ct_helpers:deps_path(emqx_authz, "test")),
|
||||||
Conf = #{<<"authz">> => #{<<"rules">> => []}},
|
Conf = #{<<"emqx_authz">> => #{<<"rules">> => []}},
|
||||||
ok = file:write_file(filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'), jsx:encode(Conf)),
|
ok = file:write_file(filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'), jsx:encode(Conf)),
|
||||||
|
% emqx_config:put([emqx_authz], #{rules => []}),
|
||||||
ok;
|
ok;
|
||||||
|
|
||||||
set_special_configs(_App) ->
|
set_special_configs(_App) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ set_special_configs(emqx) ->
|
||||||
set_special_configs(emqx_authz) ->
|
set_special_configs(emqx_authz) ->
|
||||||
application:set_env(emqx, plugins_etc_dir,
|
application:set_env(emqx, plugins_etc_dir,
|
||||||
emqx_ct_helpers:deps_path(emqx_authz, "test")),
|
emqx_ct_helpers:deps_path(emqx_authz, "test")),
|
||||||
Conf = #{<<"authz">> =>
|
Conf = #{<<"emqx_authz">> =>
|
||||||
#{<<"rules">> =>
|
#{<<"rules">> =>
|
||||||
[#{<<"config">> =>#{<<"meck">> => <<"fake">>},
|
[#{<<"config">> =>#{<<"meck">> => <<"fake">>},
|
||||||
<<"principal">> => all,
|
<<"principal">> => all,
|
||||||
|
@ -57,6 +57,12 @@ set_special_configs(emqx_authz) ->
|
||||||
<<"type">> => mysql}
|
<<"type">> => mysql}
|
||||||
]}},
|
]}},
|
||||||
ok = file:write_file(filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'), jsx:encode(Conf)),
|
ok = file:write_file(filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'), jsx:encode(Conf)),
|
||||||
|
% Rules = [#{config =>#{<<"meck">> => <<"fake">>},
|
||||||
|
% principal => all,
|
||||||
|
% sql => <<"fake sql">>,
|
||||||
|
% type => mysql}
|
||||||
|
% ],
|
||||||
|
% emqx_config:put([emqx_authz], #{rules => Rules}),
|
||||||
ok;
|
ok;
|
||||||
set_special_configs(_App) ->
|
set_special_configs(_App) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
|
@ -49,7 +49,7 @@ set_special_configs(emqx) ->
|
||||||
set_special_configs(emqx_authz) ->
|
set_special_configs(emqx_authz) ->
|
||||||
application:set_env(emqx, plugins_etc_dir,
|
application:set_env(emqx, plugins_etc_dir,
|
||||||
emqx_ct_helpers:deps_path(emqx_authz, "test")),
|
emqx_ct_helpers:deps_path(emqx_authz, "test")),
|
||||||
Conf = #{<<"authz">> =>
|
Conf = #{<<"emqx_authz">> =>
|
||||||
#{<<"rules">> =>
|
#{<<"rules">> =>
|
||||||
[#{<<"config">> =>#{<<"meck">> => <<"fake">>},
|
[#{<<"config">> =>#{<<"meck">> => <<"fake">>},
|
||||||
<<"principal">> => all,
|
<<"principal">> => all,
|
||||||
|
@ -57,6 +57,12 @@ set_special_configs(emqx_authz) ->
|
||||||
<<"type">> => pgsql}
|
<<"type">> => pgsql}
|
||||||
]}},
|
]}},
|
||||||
ok = file:write_file(filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'), jsx:encode(Conf)),
|
ok = file:write_file(filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'), jsx:encode(Conf)),
|
||||||
|
% Rules = [#{config =>#{<<"meck">> => <<"fake">>},
|
||||||
|
% principal => all,
|
||||||
|
% sql => <<"fake sql">>,
|
||||||
|
% type => pgsql}
|
||||||
|
% ],
|
||||||
|
% emqx_config:put([emqx_authz], #{rules => Rules}),
|
||||||
ok;
|
ok;
|
||||||
set_special_configs(_App) ->
|
set_special_configs(_App) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
|
@ -49,7 +49,7 @@ set_special_configs(emqx) ->
|
||||||
set_special_configs(emqx_authz) ->
|
set_special_configs(emqx_authz) ->
|
||||||
application:set_env(emqx, plugins_etc_dir,
|
application:set_env(emqx, plugins_etc_dir,
|
||||||
emqx_ct_helpers:deps_path(emqx_authz, "test")),
|
emqx_ct_helpers:deps_path(emqx_authz, "test")),
|
||||||
Conf = #{<<"authz">> =>
|
Conf = #{<<"emqx_authz">> =>
|
||||||
#{<<"rules">> =>
|
#{<<"rules">> =>
|
||||||
[#{<<"config">> =>#{
|
[#{<<"config">> =>#{
|
||||||
<<"server">> => <<"127.0.0.1:6379">>,
|
<<"server">> => <<"127.0.0.1:6379">>,
|
||||||
|
@ -63,6 +63,12 @@ set_special_configs(emqx_authz) ->
|
||||||
<<"type">> => redis}
|
<<"type">> => redis}
|
||||||
]}},
|
]}},
|
||||||
ok = file:write_file(filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'), jsx:encode(Conf)),
|
ok = file:write_file(filename:join(emqx:get_env(plugins_etc_dir), 'authz.conf'), jsx:encode(Conf)),
|
||||||
|
% Rules = [#{config =>#{<<"meck">> => <<"fake">>},
|
||||||
|
% principal => all,
|
||||||
|
% cmd => <<"fake cmd">>,
|
||||||
|
% type => redis}
|
||||||
|
% ],
|
||||||
|
% emqx_config:put([emqx_authz], #{rules => Rules}),
|
||||||
ok;
|
ok;
|
||||||
set_special_configs(_App) ->
|
set_special_configs(_App) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
Loading…
Reference in New Issue