| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- %%--------------------------------------------------------------------
- %% 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_schema).
- -include("emqx_authz.hrl").
- -include_lib("hocon/include/hoconsc.hrl").
- -include_lib("emqx_connector/include/emqx_connector.hrl").
- -import(hoconsc, [mk/2, enum/1]).
- -import(emqx_schema, [mk_duration/2]).
- -export([
- fields/1,
- authz_sources_types/1
- ]).
- %%------------------------------------------------------------------------------
- %% Hocon Schema
- %%------------------------------------------------------------------------------
- fields(file) ->
- authz_common_fields(file) ++
- [
- {rules, #{
- type => binary(),
- required => true,
- example =>
- <<
- "{allow,{username,{re,\"^dashboard$\"}},subscribe,[\"$SYS/#\"]}.\n",
- "{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}."
- >>,
- desc => ?DESC(rules)
- }}
- ];
- fields(http_get) ->
- [
- {method, #{type => get, default => get, required => true, desc => ?DESC(method)}},
- {headers, fun headers_no_content_type/1}
- ] ++ authz_http_common_fields();
- fields(http_post) ->
- [
- {method, #{type => post, default => post, required => true, desc => ?DESC(method)}},
- {headers, fun headers/1}
- ] ++ authz_http_common_fields();
- fields(built_in_database) ->
- authz_common_fields(built_in_database);
- fields(mongo_single) ->
- authz_mongo_common_fields() ++
- emqx_mongodb:fields(single);
- fields(mongo_rs) ->
- authz_mongo_common_fields() ++
- emqx_mongodb:fields(rs);
- fields(mongo_sharded) ->
- authz_mongo_common_fields() ++
- emqx_mongodb:fields(sharded);
- fields(mysql) ->
- authz_common_fields(mysql) ++
- [{query, query()}] ++
- proplists:delete(prepare_statement, emqx_mysql:fields(config));
- fields(postgresql) ->
- authz_common_fields(postgresql) ++
- [{query, query()}] ++
- proplists:delete(prepare_statement, emqx_connector_pgsql:fields(config));
- fields(redis_single) ->
- authz_redis_common_fields() ++
- emqx_redis:fields(single);
- fields(redis_sentinel) ->
- authz_redis_common_fields() ++
- emqx_redis:fields(sentinel);
- fields(redis_cluster) ->
- authz_redis_common_fields() ++
- emqx_redis:fields(cluster);
- fields(position) ->
- [
- {position,
- mk(
- string(),
- #{
- desc => ?DESC(position),
- required => true,
- in => body
- }
- )}
- ].
- %%------------------------------------------------------------------------------
- %% http type funcs
- authz_http_common_fields() ->
- authz_common_fields(http) ++
- [
- {url, fun url/1},
- {body,
- hoconsc:mk(map([{fuzzy, term(), binary()}]), #{
- required => false, desc => ?DESC(body)
- })},
- {request_timeout,
- mk_duration("Request timeout", #{
- required => false, default => <<"30s">>, desc => ?DESC(request_timeout)
- })}
- ] ++
- maps:to_list(
- maps:without(
- [
- pool_type
- ],
- maps:from_list(emqx_connector_http:fields(config))
- )
- ).
- url(type) -> binary();
- url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")];
- url(required) -> true;
- url(desc) -> ?DESC(?FUNCTION_NAME);
- url(_) -> undefined.
- headers(type) ->
- map();
- headers(desc) ->
- ?DESC(?FUNCTION_NAME);
- headers(converter) ->
- fun(Headers) ->
- maps:merge(default_headers(), transform_header_name(Headers))
- end;
- headers(default) ->
- default_headers();
- headers(_) ->
- undefined.
- headers_no_content_type(type) ->
- map();
- headers_no_content_type(desc) ->
- ?DESC(?FUNCTION_NAME);
- headers_no_content_type(converter) ->
- fun(Headers) ->
- maps:without(
- [<<"content-type">>],
- maps:merge(default_headers_no_content_type(), transform_header_name(Headers))
- )
- end;
- headers_no_content_type(default) ->
- default_headers_no_content_type();
- headers_no_content_type(_) ->
- undefined.
- %% headers
- default_headers() ->
- maps:put(
- <<"content-type">>,
- <<"application/json">>,
- default_headers_no_content_type()
- ).
- default_headers_no_content_type() ->
- #{
- <<"accept">> => <<"application/json">>,
- <<"cache-control">> => <<"no-cache">>,
- <<"connection">> => <<"keep-alive">>,
- <<"keep-alive">> => <<"timeout=30, max=1000">>
- }.
- transform_header_name(Headers) ->
- maps:fold(
- fun(K0, V, Acc) ->
- K = list_to_binary(string:to_lower(to_list(K0))),
- maps:put(K, V, Acc)
- end,
- #{},
- Headers
- ).
- %%------------------------------------------------------------------------------
- %% MonogDB type funcs
- authz_mongo_common_fields() ->
- authz_common_fields(mongodb) ++
- [
- {collection, fun collection/1},
- {filter, fun filter/1}
- ].
- collection(type) -> binary();
- collection(desc) -> ?DESC(?FUNCTION_NAME);
- collection(required) -> true;
- collection(_) -> undefined.
- filter(type) ->
- map();
- filter(desc) ->
- ?DESC(?FUNCTION_NAME);
- filter(required) ->
- false;
- filter(default) ->
- #{};
- filter(_) ->
- undefined.
- %%------------------------------------------------------------------------------
- %% Redis type funcs
- authz_redis_common_fields() ->
- authz_common_fields(redis) ++
- [
- {cmd,
- mk(binary(), #{
- required => true,
- desc => ?DESC(cmd),
- example => <<"HGETALL mqtt_authz">>
- })}
- ].
- %%------------------------------------------------------------------------------
- %% Authz api type funcs
- authz_common_fields(Type) when is_atom(Type) ->
- [
- {enable, fun enable/1},
- {type, #{
- type => Type,
- default => Type,
- required => true,
- desc => ?DESC(type),
- in => body
- }}
- ].
- enable(type) -> boolean();
- enable(default) -> true;
- enable(desc) -> ?DESC(?FUNCTION_NAME);
- enable(_) -> undefined.
- %%------------------------------------------------------------------------------
- %% Authz DB query
- query() ->
- #{
- type => binary(),
- desc => ?DESC(query),
- required => true,
- validator => fun(S) ->
- case size(S) > 0 of
- true -> ok;
- _ -> {error, "Request query"}
- end
- end
- }.
- %%------------------------------------------------------------------------------
- %% Internal funcs
- authz_sources_types(Type) ->
- case Type of
- simple ->
- [http, mongodb, redis];
- detailed ->
- [
- http_get,
- http_post,
- mongo_single,
- mongo_rs,
- mongo_sharded,
- redis_single,
- redis_sentinel,
- redis_cluster
- ]
- end ++
- [
- built_in_database,
- mysql,
- postgresql,
- file
- ].
- to_list(A) when is_atom(A) ->
- atom_to_list(A);
- to_list(B) when is_binary(B) ->
- binary_to_list(B).
|