746 lines
24 KiB
Erlang
746 lines
24 KiB
Erlang
%%--------------------------------------------------------------------
|
|
%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
|
%%
|
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
|
%% you may not use this file except in compliance with the License.
|
|
%% You may obtain a copy of the License at
|
|
%%
|
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
%%
|
|
%% Unless required by applicable law or agreed to in writing, software
|
|
%% distributed under the License is distributed on an "AS IS" BASIS,
|
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
%% See the License for the specific language governing permissions and
|
|
%% limitations under the License.
|
|
%%--------------------------------------------------------------------
|
|
|
|
-module(emqx_authz_api_mnesia).
|
|
|
|
-behaviour(minirest_api).
|
|
|
|
-include("emqx_authz.hrl").
|
|
-include_lib("emqx/include/logger.hrl").
|
|
-include_lib("hocon/include/hoconsc.hrl").
|
|
|
|
-import(hoconsc, [mk/1, mk/2, ref/1, ref/2, array/1, enum/1]).
|
|
|
|
-define(QUERY_USERNAME_FUN, fun ?MODULE:query_username/2).
|
|
-define(QUERY_CLIENTID_FUN, fun ?MODULE:query_clientid/2).
|
|
|
|
-define(ACL_USERNAME_QSCHEMA, [{<<"like_username">>, binary}]).
|
|
-define(ACL_CLIENTID_QSCHEMA, [{<<"like_clientid">>, binary}]).
|
|
|
|
-export([
|
|
api_spec/0,
|
|
paths/0,
|
|
schema/1,
|
|
fields/1
|
|
]).
|
|
|
|
%% operation funs
|
|
-export([
|
|
users/2,
|
|
clients/2,
|
|
user/2,
|
|
client/2,
|
|
all/2,
|
|
rules/2
|
|
]).
|
|
|
|
%% query funs
|
|
-export([
|
|
query_username/2,
|
|
query_clientid/2,
|
|
run_fuzzy_filter/2,
|
|
format_result/1
|
|
]).
|
|
|
|
-define(BAD_REQUEST, 'BAD_REQUEST').
|
|
-define(NOT_FOUND, 'NOT_FOUND').
|
|
-define(ALREADY_EXISTS, 'ALREADY_EXISTS').
|
|
|
|
-define(TYPE_REF, ref).
|
|
-define(TYPE_ARRAY, array).
|
|
-define(PAGE_QUERY_EXAMPLE, example_in_data).
|
|
-define(PUT_MAP_EXAMPLE, in_put_requestBody).
|
|
-define(POST_ARRAY_EXAMPLE, in_post_requestBody).
|
|
|
|
api_spec() ->
|
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
|
|
|
|
paths() ->
|
|
[
|
|
"/authorization/sources/built_in_database/rules/users",
|
|
"/authorization/sources/built_in_database/rules/clients",
|
|
"/authorization/sources/built_in_database/rules/users/:username",
|
|
"/authorization/sources/built_in_database/rules/clients/:clientid",
|
|
"/authorization/sources/built_in_database/rules/all",
|
|
"/authorization/sources/built_in_database/rules"
|
|
].
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% Schema for each URI
|
|
%%--------------------------------------------------------------------
|
|
|
|
schema("/authorization/sources/built_in_database/rules/users") ->
|
|
#{
|
|
'operationId' => users,
|
|
get =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(users_username_get),
|
|
parameters =>
|
|
[
|
|
ref(emqx_dashboard_swagger, page),
|
|
ref(emqx_dashboard_swagger, limit),
|
|
{like_username,
|
|
mk(binary(), #{
|
|
in => query,
|
|
required => false,
|
|
desc => ?DESC(fuzzy_username)
|
|
})}
|
|
],
|
|
responses =>
|
|
#{
|
|
200 => swagger_with_example(
|
|
{username_response_data, ?TYPE_REF},
|
|
{username, ?PAGE_QUERY_EXAMPLE}
|
|
)
|
|
}
|
|
},
|
|
post =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(users_username_post),
|
|
'requestBody' => swagger_with_example(
|
|
{rules_for_username, ?TYPE_ARRAY},
|
|
{username, ?POST_ARRAY_EXAMPLE}
|
|
),
|
|
responses =>
|
|
#{
|
|
204 => <<"Created">>,
|
|
400 => emqx_dashboard_swagger:error_codes(
|
|
[?BAD_REQUEST], <<"Bad username or bad rule schema">>
|
|
),
|
|
409 => emqx_dashboard_swagger:error_codes(
|
|
[?ALREADY_EXISTS], <<"ALREADY_EXISTS">>
|
|
)
|
|
}
|
|
}
|
|
};
|
|
schema("/authorization/sources/built_in_database/rules/clients") ->
|
|
#{
|
|
'operationId' => clients,
|
|
get =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(users_clientid_get),
|
|
parameters =>
|
|
[
|
|
ref(emqx_dashboard_swagger, page),
|
|
ref(emqx_dashboard_swagger, limit),
|
|
{like_clientid,
|
|
mk(
|
|
binary(),
|
|
#{
|
|
in => query,
|
|
required => false,
|
|
desc => ?DESC(fuzzy_clientid)
|
|
}
|
|
)}
|
|
],
|
|
responses =>
|
|
#{
|
|
200 => swagger_with_example(
|
|
{clientid_response_data, ?TYPE_REF},
|
|
{clientid, ?PAGE_QUERY_EXAMPLE}
|
|
)
|
|
}
|
|
},
|
|
post =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(users_clientid_post),
|
|
'requestBody' => swagger_with_example(
|
|
{rules_for_clientid, ?TYPE_ARRAY},
|
|
{clientid, ?POST_ARRAY_EXAMPLE}
|
|
),
|
|
responses =>
|
|
#{
|
|
204 => <<"Created">>,
|
|
400 => emqx_dashboard_swagger:error_codes(
|
|
[?BAD_REQUEST], <<"Bad clientid or bad rule schema">>
|
|
)
|
|
}
|
|
}
|
|
};
|
|
schema("/authorization/sources/built_in_database/rules/users/:username") ->
|
|
#{
|
|
'operationId' => user,
|
|
get =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(user_username_get),
|
|
parameters => [ref(username)],
|
|
responses =>
|
|
#{
|
|
200 => swagger_with_example(
|
|
{rules_for_username, ?TYPE_REF},
|
|
{username, ?PUT_MAP_EXAMPLE}
|
|
),
|
|
404 => emqx_dashboard_swagger:error_codes(
|
|
[?NOT_FOUND], <<"Not Found">>
|
|
)
|
|
}
|
|
},
|
|
put =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(user_username_put),
|
|
parameters => [ref(username)],
|
|
'requestBody' => swagger_with_example(
|
|
{rules_for_username, ?TYPE_REF},
|
|
{username, ?PUT_MAP_EXAMPLE}
|
|
),
|
|
responses =>
|
|
#{
|
|
204 => <<"Updated">>,
|
|
400 => emqx_dashboard_swagger:error_codes(
|
|
[?BAD_REQUEST], <<"Bad username or bad rule schema">>
|
|
)
|
|
}
|
|
},
|
|
delete =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(user_username_delete),
|
|
parameters => [ref(username)],
|
|
responses =>
|
|
#{
|
|
204 => <<"Deleted">>,
|
|
400 => emqx_dashboard_swagger:error_codes(
|
|
[?BAD_REQUEST], <<"Bad username">>
|
|
),
|
|
404 => emqx_dashboard_swagger:error_codes(
|
|
[?NOT_FOUND], <<"Username Not Found">>
|
|
)
|
|
}
|
|
}
|
|
};
|
|
schema("/authorization/sources/built_in_database/rules/clients/:clientid") ->
|
|
#{
|
|
'operationId' => client,
|
|
get =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(user_clientid_get),
|
|
parameters => [ref(clientid)],
|
|
responses =>
|
|
#{
|
|
200 => swagger_with_example(
|
|
{rules_for_clientid, ?TYPE_REF},
|
|
{clientid, ?PUT_MAP_EXAMPLE}
|
|
),
|
|
404 => emqx_dashboard_swagger:error_codes(
|
|
[?NOT_FOUND], <<"Not Found">>
|
|
)
|
|
}
|
|
},
|
|
put =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(user_clientid_put),
|
|
parameters => [ref(clientid)],
|
|
'requestBody' => swagger_with_example(
|
|
{rules_for_clientid, ?TYPE_REF},
|
|
{clientid, ?PUT_MAP_EXAMPLE}
|
|
),
|
|
responses =>
|
|
#{
|
|
204 => <<"Updated">>,
|
|
400 => emqx_dashboard_swagger:error_codes(
|
|
[?BAD_REQUEST], <<"Bad clientid or bad rule schema">>
|
|
)
|
|
}
|
|
},
|
|
delete =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(user_clientid_delete),
|
|
parameters => [ref(clientid)],
|
|
responses =>
|
|
#{
|
|
204 => <<"Deleted">>,
|
|
400 => emqx_dashboard_swagger:error_codes(
|
|
[?BAD_REQUEST], <<"Bad clientid">>
|
|
),
|
|
404 => emqx_dashboard_swagger:error_codes(
|
|
[?NOT_FOUND], <<"ClientID Not Found">>
|
|
)
|
|
}
|
|
}
|
|
};
|
|
schema("/authorization/sources/built_in_database/rules/all") ->
|
|
#{
|
|
'operationId' => all,
|
|
get =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(rules_all_get),
|
|
responses =>
|
|
#{200 => swagger_with_example({rules, ?TYPE_REF}, {all, ?PUT_MAP_EXAMPLE})}
|
|
},
|
|
post =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(rules_all_post),
|
|
'requestBody' =>
|
|
swagger_with_example({rules, ?TYPE_REF}, {all, ?PUT_MAP_EXAMPLE}),
|
|
responses =>
|
|
#{
|
|
204 => <<"Updated">>,
|
|
400 => emqx_dashboard_swagger:error_codes(
|
|
[?BAD_REQUEST], <<"Bad rule schema">>
|
|
)
|
|
}
|
|
},
|
|
delete =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(rules_all_delete),
|
|
responses =>
|
|
#{
|
|
204 => <<"Deleted">>
|
|
}
|
|
}
|
|
};
|
|
schema("/authorization/sources/built_in_database/rules") ->
|
|
#{
|
|
'operationId' => rules,
|
|
delete =>
|
|
#{
|
|
tags => [<<"authorization">>],
|
|
description => ?DESC(rules_delete),
|
|
responses =>
|
|
#{
|
|
204 => <<"Deleted">>,
|
|
400 => emqx_dashboard_swagger:error_codes(
|
|
[?BAD_REQUEST], <<"Bad Request">>
|
|
)
|
|
}
|
|
}
|
|
}.
|
|
|
|
fields(rule_item) ->
|
|
[
|
|
{topic,
|
|
mk(
|
|
string(),
|
|
#{
|
|
required => true,
|
|
desc => ?DESC(topic),
|
|
example => <<"test/topic/1">>
|
|
}
|
|
)},
|
|
{permission,
|
|
mk(
|
|
enum([allow, deny]),
|
|
#{
|
|
desc => ?DESC(permission),
|
|
required => true,
|
|
example => allow
|
|
}
|
|
)},
|
|
{action,
|
|
mk(
|
|
enum([publish, subscribe, all]),
|
|
#{
|
|
desc => ?DESC(action),
|
|
required => true,
|
|
example => publish
|
|
}
|
|
)}
|
|
];
|
|
fields(clientid) ->
|
|
[
|
|
{clientid,
|
|
mk(
|
|
binary(),
|
|
#{
|
|
in => path,
|
|
required => true,
|
|
desc => ?DESC(clientid),
|
|
example => <<"client1">>
|
|
}
|
|
)}
|
|
];
|
|
fields(username) ->
|
|
[
|
|
{username,
|
|
mk(
|
|
binary(),
|
|
#{
|
|
in => path,
|
|
required => true,
|
|
desc => ?DESC(username),
|
|
example => <<"user1">>
|
|
}
|
|
)}
|
|
];
|
|
fields(rules_for_username) ->
|
|
fields(rules) ++
|
|
fields(username);
|
|
fields(username_response_data) ->
|
|
[
|
|
{data, mk(array(ref(rules_for_username)), #{})},
|
|
{meta, ref(emqx_dashboard_swagger, meta)}
|
|
];
|
|
fields(rules_for_clientid) ->
|
|
fields(rules) ++
|
|
fields(clientid);
|
|
fields(clientid_response_data) ->
|
|
[
|
|
{data, mk(array(ref(rules_for_clientid)), #{})},
|
|
{meta, ref(emqx_dashboard_swagger, meta)}
|
|
];
|
|
fields(rules) ->
|
|
[{rules, mk(array(ref(rule_item)))}].
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% HTTP API
|
|
%%--------------------------------------------------------------------
|
|
|
|
users(get, #{query_string := QueryString}) ->
|
|
case
|
|
emqx_mgmt_api:node_query(
|
|
node(),
|
|
?ACL_TABLE,
|
|
QueryString,
|
|
?ACL_USERNAME_QSCHEMA,
|
|
?QUERY_USERNAME_FUN,
|
|
fun ?MODULE:format_result/1
|
|
)
|
|
of
|
|
{error, page_limit_invalid} ->
|
|
{400, #{code => <<"INVALID_PARAMETER">>, message => <<"page_limit_invalid">>}};
|
|
{error, Node, Error} ->
|
|
Message = list_to_binary(io_lib:format("bad rpc call ~p, Reason ~p", [Node, Error])),
|
|
{500, #{code => <<"NODE_DOWN">>, message => Message}};
|
|
Result ->
|
|
{200, Result}
|
|
end;
|
|
users(post, #{body := Body}) when is_list(Body) ->
|
|
case ensure_all_not_exists(<<"username">>, username, Body) of
|
|
[] ->
|
|
lists:foreach(
|
|
fun(#{<<"username">> := Username, <<"rules">> := Rules}) ->
|
|
emqx_authz_mnesia:store_rules({username, Username}, format_rules(Rules))
|
|
end,
|
|
Body
|
|
),
|
|
{204};
|
|
Exists ->
|
|
{409, #{
|
|
code => <<"ALREADY_EXISTS">>,
|
|
message => binfmt("Users '~ts' already exist", [binjoin(Exists)])
|
|
}}
|
|
end.
|
|
|
|
clients(get, #{query_string := QueryString}) ->
|
|
case
|
|
emqx_mgmt_api:node_query(
|
|
node(),
|
|
?ACL_TABLE,
|
|
QueryString,
|
|
?ACL_CLIENTID_QSCHEMA,
|
|
?QUERY_CLIENTID_FUN,
|
|
fun ?MODULE:format_result/1
|
|
)
|
|
of
|
|
{error, page_limit_invalid} ->
|
|
{400, #{code => <<"INVALID_PARAMETER">>, message => <<"page_limit_invalid">>}};
|
|
{error, Node, Error} ->
|
|
Message = list_to_binary(io_lib:format("bad rpc call ~p, Reason ~p", [Node, Error])),
|
|
{500, #{code => <<"NODE_DOWN">>, message => Message}};
|
|
Result ->
|
|
{200, Result}
|
|
end;
|
|
clients(post, #{body := Body}) when is_list(Body) ->
|
|
case ensure_all_not_exists(<<"clientid">>, clientid, Body) of
|
|
[] ->
|
|
lists:foreach(
|
|
fun(#{<<"clientid">> := ClientID, <<"rules">> := Rules}) ->
|
|
emqx_authz_mnesia:store_rules({clientid, ClientID}, format_rules(Rules))
|
|
end,
|
|
Body
|
|
),
|
|
{204};
|
|
Exists ->
|
|
{409, #{
|
|
code => <<"ALREADY_EXISTS">>,
|
|
message => binfmt("Clients '~ts' already exist", [binjoin(Exists)])
|
|
}}
|
|
end.
|
|
|
|
user(get, #{bindings := #{username := Username}}) ->
|
|
case emqx_authz_mnesia:get_rules({username, Username}) of
|
|
not_found ->
|
|
{404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}};
|
|
{ok, Rules} ->
|
|
{200, #{
|
|
username => Username,
|
|
rules => [
|
|
#{
|
|
topic => Topic,
|
|
action => Action,
|
|
permission => Permission
|
|
}
|
|
|| {Permission, Action, Topic} <- Rules
|
|
]
|
|
}}
|
|
end;
|
|
user(put, #{
|
|
bindings := #{username := Username},
|
|
body := #{<<"username">> := Username, <<"rules">> := Rules}
|
|
}) ->
|
|
emqx_authz_mnesia:store_rules({username, Username}, format_rules(Rules)),
|
|
{204};
|
|
user(delete, #{bindings := #{username := Username}}) ->
|
|
case emqx_authz_mnesia:get_rules({username, Username}) of
|
|
not_found ->
|
|
{404, #{code => <<"NOT_FOUND">>, message => <<"Username Not Found">>}};
|
|
{ok, _Rules} ->
|
|
emqx_authz_mnesia:delete_rules({username, Username}),
|
|
{204}
|
|
end.
|
|
|
|
client(get, #{bindings := #{clientid := ClientID}}) ->
|
|
case emqx_authz_mnesia:get_rules({clientid, ClientID}) of
|
|
not_found ->
|
|
{404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}};
|
|
{ok, Rules} ->
|
|
{200, #{
|
|
clientid => ClientID,
|
|
rules => [
|
|
#{
|
|
topic => Topic,
|
|
action => Action,
|
|
permission => Permission
|
|
}
|
|
|| {Permission, Action, Topic} <- Rules
|
|
]
|
|
}}
|
|
end;
|
|
client(put, #{
|
|
bindings := #{clientid := ClientID},
|
|
body := #{<<"clientid">> := ClientID, <<"rules">> := Rules}
|
|
}) ->
|
|
emqx_authz_mnesia:store_rules({clientid, ClientID}, format_rules(Rules)),
|
|
{204};
|
|
client(delete, #{bindings := #{clientid := ClientID}}) ->
|
|
case emqx_authz_mnesia:get_rules({clientid, ClientID}) of
|
|
not_found ->
|
|
{404, #{code => <<"NOT_FOUND">>, message => <<"ClientID Not Found">>}};
|
|
{ok, _Rules} ->
|
|
emqx_authz_mnesia:delete_rules({clientid, ClientID}),
|
|
{204}
|
|
end.
|
|
|
|
all(get, _) ->
|
|
case emqx_authz_mnesia:get_rules(all) of
|
|
not_found ->
|
|
{200, #{rules => []}};
|
|
{ok, Rules} ->
|
|
{200, #{
|
|
rules => [
|
|
#{
|
|
topic => Topic,
|
|
action => Action,
|
|
permission => Permission
|
|
}
|
|
|| {Permission, Action, Topic} <- Rules
|
|
]
|
|
}}
|
|
end;
|
|
all(post, #{body := #{<<"rules">> := Rules}}) ->
|
|
emqx_authz_mnesia:store_rules(all, format_rules(Rules)),
|
|
{204};
|
|
all(delete, _) ->
|
|
emqx_authz_mnesia:store_rules(all, []),
|
|
{204}.
|
|
|
|
rules(delete, _) ->
|
|
case emqx_authz_api_sources:get_raw_source(<<"built_in_database">>) of
|
|
[#{<<"enable">> := false}] ->
|
|
ok = emqx_authz_mnesia:purge_rules(),
|
|
{204};
|
|
[#{<<"enable">> := true}] ->
|
|
{400, #{
|
|
code => <<"BAD_REQUEST">>,
|
|
message =>
|
|
<<"'built_in_database' type source must be disabled before purge.">>
|
|
}};
|
|
[] ->
|
|
{404, #{
|
|
code => <<"BAD_REQUEST">>,
|
|
message => <<"'built_in_database' type source is not found.">>
|
|
}}
|
|
end.
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% QueryString to MatchSpec
|
|
|
|
-spec query_username(atom(), {list(), list()}) -> emqx_mgmt_api:match_spec_and_filter().
|
|
query_username(_Tab, {_QString, FuzzyQString}) ->
|
|
#{
|
|
match_spec => emqx_authz_mnesia:list_username_rules(),
|
|
fuzzy_fun => fuzzy_filter_fun(FuzzyQString)
|
|
}.
|
|
|
|
-spec query_clientid(atom(), {list(), list()}) -> emqx_mgmt_api:match_spec_and_filter().
|
|
query_clientid(_Tab, {_QString, FuzzyQString}) ->
|
|
#{
|
|
match_spec => emqx_authz_mnesia:list_clientid_rules(),
|
|
fuzzy_fun => fuzzy_filter_fun(FuzzyQString)
|
|
}.
|
|
|
|
%% Fuzzy username funcs
|
|
fuzzy_filter_fun([]) ->
|
|
undefined;
|
|
fuzzy_filter_fun(Fuzzy) ->
|
|
{fun ?MODULE:run_fuzzy_filter/2, [Fuzzy]}.
|
|
|
|
run_fuzzy_filter(_, []) ->
|
|
true;
|
|
run_fuzzy_filter(
|
|
E = [{username, Username}, _Rule],
|
|
[{username, like, UsernameSubStr} | Fuzzy]
|
|
) ->
|
|
binary:match(Username, UsernameSubStr) /= nomatch andalso run_fuzzy_filter(E, Fuzzy);
|
|
run_fuzzy_filter(
|
|
E = [{clientid, ClientId}, _Rule],
|
|
[{clientid, like, ClientIdSubStr} | Fuzzy]
|
|
) ->
|
|
binary:match(ClientId, ClientIdSubStr) /= nomatch andalso run_fuzzy_filter(E, Fuzzy).
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% format funcs
|
|
|
|
%% format rule from api
|
|
format_rules(Rules) when is_list(Rules) ->
|
|
lists:foldl(
|
|
fun(
|
|
#{
|
|
<<"topic">> := Topic,
|
|
<<"action">> := Action,
|
|
<<"permission">> := Permission
|
|
},
|
|
AccIn
|
|
) when
|
|
?PUBSUB(Action) andalso
|
|
?ALLOW_DENY(Permission)
|
|
->
|
|
AccIn ++ [{atom(Permission), atom(Action), Topic}]
|
|
end,
|
|
[],
|
|
Rules
|
|
).
|
|
|
|
%% format result from mnesia tab
|
|
format_result([{username, Username}, {rules, Rules}]) ->
|
|
#{
|
|
username => Username,
|
|
rules => [
|
|
#{
|
|
topic => Topic,
|
|
action => Action,
|
|
permission => Permission
|
|
}
|
|
|| {Permission, Action, Topic} <- Rules
|
|
]
|
|
};
|
|
format_result([{clientid, ClientID}, {rules, Rules}]) ->
|
|
#{
|
|
clientid => ClientID,
|
|
rules => [
|
|
#{
|
|
topic => Topic,
|
|
action => Action,
|
|
permission => Permission
|
|
}
|
|
|| {Permission, Action, Topic} <- Rules
|
|
]
|
|
}.
|
|
atom(B) when is_binary(B) ->
|
|
try
|
|
binary_to_existing_atom(B, utf8)
|
|
catch
|
|
_Error:_Expection -> binary_to_atom(B)
|
|
end;
|
|
atom(A) when is_atom(A) -> A.
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% Internal functions
|
|
%%--------------------------------------------------------------------
|
|
|
|
swagger_with_example({Ref, TypeP}, {_Name, _Type} = Example) ->
|
|
emqx_dashboard_swagger:schema_with_examples(
|
|
case TypeP of
|
|
?TYPE_REF -> ref(?MODULE, Ref);
|
|
?TYPE_ARRAY -> array(ref(?MODULE, Ref))
|
|
end,
|
|
rules_example(Example)
|
|
).
|
|
|
|
rules_example({ExampleName, ExampleType}) ->
|
|
{Summary, Example} =
|
|
case ExampleName of
|
|
username -> {<<"Username">>, ?USERNAME_RULES_EXAMPLE};
|
|
clientid -> {<<"ClientID">>, ?CLIENTID_RULES_EXAMPLE};
|
|
all -> {<<"All">>, ?ALL_RULES_EXAMPLE}
|
|
end,
|
|
Value =
|
|
case ExampleType of
|
|
?PAGE_QUERY_EXAMPLE ->
|
|
#{
|
|
data => [Example],
|
|
meta => ?META_EXAMPLE
|
|
};
|
|
?PUT_MAP_EXAMPLE ->
|
|
Example;
|
|
?POST_ARRAY_EXAMPLE ->
|
|
[Example]
|
|
end,
|
|
#{
|
|
'password_based:built_in_database' => #{
|
|
summary => Summary,
|
|
value => Value
|
|
}
|
|
}.
|
|
|
|
ensure_all_not_exists(Key, Type, Cfgs) ->
|
|
lists:foldl(
|
|
fun(#{Key := Id}, Acc) ->
|
|
case emqx_authz_mnesia:get_rules({Type, Id}) of
|
|
not_found ->
|
|
Acc;
|
|
_ ->
|
|
[Id | Acc]
|
|
end
|
|
end,
|
|
[],
|
|
Cfgs
|
|
).
|
|
|
|
binjoin([Bin]) ->
|
|
Bin;
|
|
binjoin(Bins) ->
|
|
binjoin(Bins, <<>>).
|
|
|
|
binjoin([H | T], Acc) ->
|
|
binjoin(T, <<H/binary, $,, Acc/binary>>);
|
|
binjoin([], Acc) ->
|
|
Acc.
|
|
|
|
binfmt(Fmt, Args) -> iolist_to_binary(io_lib:format(Fmt, Args)).
|