refactor: authz_api_sources spec
This commit is contained in:
parent
e72c07c31e
commit
000020617c
|
@ -1,5 +1,5 @@
|
||||||
##--------------------------------------------------------------------
|
##--------------------------------------------------------------------
|
||||||
## Emq X Rate Limiter
|
## EMQX Rate Limiter
|
||||||
##--------------------------------------------------------------------
|
##--------------------------------------------------------------------
|
||||||
|
|
||||||
limiter {
|
limiter {
|
||||||
|
|
|
@ -16,490 +16,184 @@
|
||||||
|
|
||||||
-module(emqx_authz_api_schema).
|
-module(emqx_authz_api_schema).
|
||||||
|
|
||||||
-export([definitions/0]).
|
-include_lib("typerefl/include/types.hrl").
|
||||||
|
-include_lib("emqx_connector/include/emqx_connector.hrl").
|
||||||
|
|
||||||
definitions() ->
|
-import(hoconsc, [mk/2, ref/1, ref/2, array/1, enum/1]).
|
||||||
Sources = #{
|
-import(emqx_schema, [mk_duration/2]).
|
||||||
'oneOf' => [ minirest:ref(<<"http">>)
|
|
||||||
, minirest:ref(<<"built-in-database">>)
|
-export([fields/1, authz_sources_types/1]).
|
||||||
, minirest:ref(<<"mongo_single">>)
|
|
||||||
, minirest:ref(<<"mongo_rs">>)
|
fields(http) ->
|
||||||
, minirest:ref(<<"mongo_sharded">>)
|
authz_common_fields(http)
|
||||||
, minirest:ref(<<"mysql">>)
|
++ [ {url, fun url/1}
|
||||||
, minirest:ref(<<"postgresql">>)
|
, {method, #{ type => enum([get, post])
|
||||||
, minirest:ref(<<"redis_single">>)
|
, default => get
|
||||||
, minirest:ref(<<"redis_sentinel">>)
|
, converter => fun to_bin/1}}
|
||||||
, minirest:ref(<<"redis_cluster">>)
|
, {headers, fun headers/1}
|
||||||
, minirest:ref(<<"file">>)
|
, {body, fun body/1}
|
||||||
]
|
, {request_timeout, mk_duration("Request timeout", #{default => "30s"})}]
|
||||||
},
|
++ maps:to_list(maps:without([ base_url
|
||||||
SSL = #{
|
, pool_type],
|
||||||
type => object,
|
maps:from_list(emqx_connector_http:fields(config))));
|
||||||
required => [enable],
|
fields('built-in-database') ->
|
||||||
properties => #{
|
authz_common_fields('built-in-database');
|
||||||
enable => #{type => boolean, example => true},
|
fields(mongo_single) ->
|
||||||
cacertfile => #{type => string},
|
authz_mongo_common_fields()
|
||||||
keyfile => #{type => string},
|
++ emqx_connector_mongo:fields(single);
|
||||||
certfile => #{type => string},
|
fields(mongo_rs) ->
|
||||||
verify => #{type => boolean, example => false}
|
authz_mongo_common_fields()
|
||||||
}
|
++ emqx_connector_mongo:fields(rs);
|
||||||
},
|
fields(mongo_sharded) ->
|
||||||
HTTP = #{
|
authz_mongo_common_fields()
|
||||||
type => object,
|
++ emqx_connector_mongo:fields(sharded);
|
||||||
required => [ type
|
fields(mysql) ->
|
||||||
, enable
|
authz_common_fields(mysql)
|
||||||
, method
|
++ [ {query, #{type => binary()}}]
|
||||||
, headers
|
++ emqx_connector_mysql:fields(config);
|
||||||
, request_timeout
|
fields(postgresql) ->
|
||||||
, connect_timeout
|
authz_common_fields(postgresql)
|
||||||
, max_retries
|
++ [ {query, #{type => binary()}}]
|
||||||
, retry_interval
|
++ proplists:delete(named_queries, emqx_connector_pgsql:fields(config));
|
||||||
, pool_type
|
fields(redis_single) ->
|
||||||
, pool_size
|
authz_redis_common_fields()
|
||||||
, enable_pipelining
|
++ emqx_connector_redis:fields(single);
|
||||||
, ssl
|
fields(redis_sentinel) ->
|
||||||
],
|
authz_redis_common_fields()
|
||||||
properties => #{
|
++ emqx_connector_redis:fields(sentinel);
|
||||||
type => #{
|
fields(redis_cluster) ->
|
||||||
type => string,
|
authz_redis_common_fields()
|
||||||
enum => [<<"http">>],
|
++ emqx_connector_redis:fields(cluster);
|
||||||
example => <<"http">>
|
fields(file) ->
|
||||||
},
|
authz_common_fields(file)
|
||||||
enable => #{
|
++ [ {rules, #{ type => binary()
|
||||||
type => boolean,
|
, example =>
|
||||||
example => true
|
|
||||||
},
|
|
||||||
url => #{
|
|
||||||
type => string,
|
|
||||||
example => <<"https://emqx.com">>
|
|
||||||
},
|
|
||||||
method => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"get">>, <<"post">>],
|
|
||||||
example => <<"get">>
|
|
||||||
},
|
|
||||||
headers => #{type => object},
|
|
||||||
body => #{type => object},
|
|
||||||
connect_timeout => #{type => string},
|
|
||||||
max_retries => #{type => integer},
|
|
||||||
retry_interval => #{type => string},
|
|
||||||
pool_type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"random">>, <<"hash">>],
|
|
||||||
example => <<"hash">>
|
|
||||||
},
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
enable_pipelining => #{type => boolean},
|
|
||||||
ssl => minirest:ref(<<"ssl">>)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MongoSingle= #{
|
|
||||||
type => object,
|
|
||||||
required => [ type
|
|
||||||
, enable
|
|
||||||
, collection
|
|
||||||
, selector
|
|
||||||
, mongo_type
|
|
||||||
, server
|
|
||||||
, pool_size
|
|
||||||
, username
|
|
||||||
, password
|
|
||||||
, auth_source
|
|
||||||
, database
|
|
||||||
, topology
|
|
||||||
, ssl
|
|
||||||
],
|
|
||||||
properties => #{
|
|
||||||
type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"mongodb">>],
|
|
||||||
example => <<"mongodb">>
|
|
||||||
},
|
|
||||||
enable => #{
|
|
||||||
type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
srv_record => #{type => boolean, example => false, default => false},
|
|
||||||
collection => #{type => string},
|
|
||||||
selector => #{type => object},
|
|
||||||
mongo_type => #{type => string,
|
|
||||||
enum => [<<"single">>],
|
|
||||||
example => <<"single">>},
|
|
||||||
server => #{type => string, example => <<"127.0.0.1:27017">>},
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
username => #{type => string},
|
|
||||||
password => #{type => string},
|
|
||||||
auth_source => #{type => string},
|
|
||||||
database => #{type => string},
|
|
||||||
topology => #{type => object,
|
|
||||||
properties => #{
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
max_overflow => #{type => integer},
|
|
||||||
overflow_ttl => #{type => string},
|
|
||||||
overflow_check_period => #{type => string},
|
|
||||||
local_threshold_ms => #{type => integer},
|
|
||||||
connect_timeout_ms => #{type => integer},
|
|
||||||
socket_timeout_ms => #{type => integer},
|
|
||||||
server_selection_timeout_ms => #{type => integer},
|
|
||||||
wait_queue_timeout_ms => #{type => integer},
|
|
||||||
heartbeat_frequency_ms => #{type => integer},
|
|
||||||
min_heartbeat_frequency_ms => #{type => integer}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ssl => minirest:ref(<<"ssl">>)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MongoRs= #{
|
|
||||||
type => object,
|
|
||||||
required => [ type
|
|
||||||
, enable
|
|
||||||
, collection
|
|
||||||
, selector
|
|
||||||
, mongo_type
|
|
||||||
, servers
|
|
||||||
, replica_set_name
|
|
||||||
, pool_size
|
|
||||||
, username
|
|
||||||
, password
|
|
||||||
, auth_source
|
|
||||||
, database
|
|
||||||
, topology
|
|
||||||
, ssl
|
|
||||||
],
|
|
||||||
properties => #{
|
|
||||||
type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"mongodb">>],
|
|
||||||
example => <<"mongodb">>
|
|
||||||
},
|
|
||||||
enable => #{
|
|
||||||
type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
srv_record => #{type => boolean, example => false, default => false},
|
|
||||||
collection => #{type => string},
|
|
||||||
selector => #{type => object},
|
|
||||||
mongo_type => #{type => string,
|
|
||||||
enum => [<<"rs">>],
|
|
||||||
example => <<"rs">>},
|
|
||||||
servers => #{type => string, example => <<"127.0.0.1:27017, 127.0.0.2:27017">>},
|
|
||||||
replica_set_name => #{type => string},
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
username => #{type => string},
|
|
||||||
password => #{type => string},
|
|
||||||
auth_source => #{type => string},
|
|
||||||
database => #{type => string},
|
|
||||||
topology => #{type => object,
|
|
||||||
properties => #{
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
max_overflow => #{type => integer},
|
|
||||||
overflow_ttl => #{type => string},
|
|
||||||
overflow_check_period => #{type => string},
|
|
||||||
local_threshold_ms => #{type => integer},
|
|
||||||
connect_timeout_ms => #{type => integer},
|
|
||||||
socket_timeout_ms => #{type => integer},
|
|
||||||
server_selection_timeout_ms => #{type => integer},
|
|
||||||
wait_queue_timeout_ms => #{type => integer},
|
|
||||||
heartbeat_frequency_ms => #{type => integer},
|
|
||||||
min_heartbeat_frequency_ms => #{type => integer}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ssl => minirest:ref(<<"ssl">>)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MongoSharded = #{
|
|
||||||
type => object,
|
|
||||||
required => [ type
|
|
||||||
, enable
|
|
||||||
, collection
|
|
||||||
, selector
|
|
||||||
, mongo_type
|
|
||||||
, servers
|
|
||||||
, pool_size
|
|
||||||
, username
|
|
||||||
, password
|
|
||||||
, auth_source
|
|
||||||
, database
|
|
||||||
, topology
|
|
||||||
, ssl
|
|
||||||
],
|
|
||||||
properties => #{
|
|
||||||
type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"mongodb">>],
|
|
||||||
example => <<"mongodb">>
|
|
||||||
},
|
|
||||||
enable => #{
|
|
||||||
type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
srv_record => #{type => boolean, example => false, default => false},
|
|
||||||
collection => #{type => string},
|
|
||||||
selector => #{type => object},
|
|
||||||
mongo_type => #{type => string,
|
|
||||||
enum => [<<"sharded">>],
|
|
||||||
example => <<"sharded">>},
|
|
||||||
servers => #{type => string,example => <<"127.0.0.1:27017, 127.0.0.2:27017">>},
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
username => #{type => string},
|
|
||||||
password => #{type => string},
|
|
||||||
auth_source => #{type => string},
|
|
||||||
database => #{type => string},
|
|
||||||
topology => #{type => object,
|
|
||||||
properties => #{
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
max_overflow => #{type => integer},
|
|
||||||
overflow_ttl => #{type => string},
|
|
||||||
overflow_check_period => #{type => string},
|
|
||||||
local_threshold_ms => #{type => integer},
|
|
||||||
connect_timeout_ms => #{type => integer},
|
|
||||||
socket_timeout_ms => #{type => integer},
|
|
||||||
server_selection_timeout_ms => #{type => integer},
|
|
||||||
wait_queue_timeout_ms => #{type => integer},
|
|
||||||
heartbeat_frequency_ms => #{type => integer},
|
|
||||||
min_heartbeat_frequency_ms => #{type => integer}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ssl => minirest:ref(<<"ssl">>)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Mysql = #{
|
|
||||||
type => object,
|
|
||||||
required => [ type
|
|
||||||
, enable
|
|
||||||
, query
|
|
||||||
, server
|
|
||||||
, database
|
|
||||||
, pool_size
|
|
||||||
, username
|
|
||||||
, password
|
|
||||||
, auto_reconnect
|
|
||||||
, ssl
|
|
||||||
],
|
|
||||||
properties => #{
|
|
||||||
type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"mysql">>],
|
|
||||||
example => <<"mysql">>
|
|
||||||
},
|
|
||||||
enable => #{
|
|
||||||
type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
query => #{type => string},
|
|
||||||
server => #{type => string,
|
|
||||||
example => <<"127.0.0.1:3306">>
|
|
||||||
},
|
|
||||||
database => #{type => string},
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
username => #{type => string},
|
|
||||||
password => #{type => string},
|
|
||||||
auto_reconnect => #{type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
ssl => minirest:ref(<<"ssl">>)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Pgsql = #{
|
|
||||||
type => object,
|
|
||||||
required => [ type
|
|
||||||
, enable
|
|
||||||
, query
|
|
||||||
, server
|
|
||||||
, database
|
|
||||||
, pool_size
|
|
||||||
, username
|
|
||||||
, password
|
|
||||||
, auto_reconnect
|
|
||||||
, ssl
|
|
||||||
],
|
|
||||||
properties => #{
|
|
||||||
type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"postgresql">>],
|
|
||||||
example => <<"postgresql">>
|
|
||||||
},
|
|
||||||
enable => #{
|
|
||||||
type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
query => #{type => string},
|
|
||||||
server => #{type => string,
|
|
||||||
example => <<"127.0.0.1:5432">>
|
|
||||||
},
|
|
||||||
database => #{type => string},
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
username => #{type => string},
|
|
||||||
password => #{type => string},
|
|
||||||
auto_reconnect => #{type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
ssl => minirest:ref(<<"ssl">>)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RedisSingle = #{
|
|
||||||
type => object,
|
|
||||||
required => [ type
|
|
||||||
, enable
|
|
||||||
, cmd
|
|
||||||
, server
|
|
||||||
, redis_type
|
|
||||||
, pool_size
|
|
||||||
, auto_reconnect
|
|
||||||
, ssl
|
|
||||||
],
|
|
||||||
properties => #{
|
|
||||||
type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"redis">>],
|
|
||||||
example => <<"redis">>
|
|
||||||
},
|
|
||||||
enable => #{
|
|
||||||
type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
cmd => #{
|
|
||||||
type => string,
|
|
||||||
example => <<"HGETALL mqtt_authz">>
|
|
||||||
},
|
|
||||||
server => #{type => string, example => <<"127.0.0.1:3306">>},
|
|
||||||
redis_type => #{type => string,
|
|
||||||
enum => [<<"single">>],
|
|
||||||
example => <<"single">>},
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
auto_reconnect => #{type => boolean, example => true},
|
|
||||||
password => #{type => string},
|
|
||||||
database => #{type => integer},
|
|
||||||
ssl => minirest:ref(<<"ssl">>)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RedisSentinel= #{
|
|
||||||
type => object,
|
|
||||||
required => [ type
|
|
||||||
, enable
|
|
||||||
, cmd
|
|
||||||
, servers
|
|
||||||
, redis_type
|
|
||||||
, sentinel
|
|
||||||
, pool_size
|
|
||||||
, auto_reconnect
|
|
||||||
, ssl
|
|
||||||
],
|
|
||||||
properties => #{
|
|
||||||
type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"redis">>],
|
|
||||||
example => <<"redis">>
|
|
||||||
},
|
|
||||||
enable => #{
|
|
||||||
type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
cmd => #{
|
|
||||||
type => string,
|
|
||||||
example => <<"HGETALL mqtt_authz">>
|
|
||||||
},
|
|
||||||
servers => #{type => string, example => <<"127.0.0.1:6379, 127.0.0.2:6379">>},
|
|
||||||
redis_type => #{type => string,
|
|
||||||
enum => [<<"sentinel">>],
|
|
||||||
example => <<"sentinel">>},
|
|
||||||
sentinel => #{type => string},
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
auto_reconnect => #{type => boolean, example => true},
|
|
||||||
password => #{type => string},
|
|
||||||
database => #{type => integer},
|
|
||||||
ssl => minirest:ref(<<"ssl">>)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RedisCluster= #{
|
|
||||||
type => object,
|
|
||||||
required => [ type
|
|
||||||
, enable
|
|
||||||
, cmd
|
|
||||||
, servers
|
|
||||||
, redis_type
|
|
||||||
, pool_size
|
|
||||||
, auto_reconnect
|
|
||||||
, ssl],
|
|
||||||
properties => #{
|
|
||||||
type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"redis">>],
|
|
||||||
example => <<"redis">>
|
|
||||||
},
|
|
||||||
enable => #{
|
|
||||||
type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
cmd => #{
|
|
||||||
type => string,
|
|
||||||
example => <<"HGETALL mqtt_authz">>
|
|
||||||
},
|
|
||||||
servers => #{type => string, example => <<"127.0.0.1:6379, 127.0.0.2:6379">>},
|
|
||||||
redis_type => #{type => string,
|
|
||||||
enum => [<<"cluster">>],
|
|
||||||
example => <<"cluster">>},
|
|
||||||
pool_size => #{type => integer},
|
|
||||||
auto_reconnect => #{type => boolean, example => true},
|
|
||||||
password => #{type => string},
|
|
||||||
database => #{type => integer},
|
|
||||||
ssl => minirest:ref(<<"ssl">>)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Mnesia = #{
|
|
||||||
type => object,
|
|
||||||
required => [type, enable],
|
|
||||||
properties => #{
|
|
||||||
type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"redis">>],
|
|
||||||
example => <<"redis">>
|
|
||||||
},
|
|
||||||
enable => #{
|
|
||||||
type => boolean,
|
|
||||||
example => true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
File = #{
|
|
||||||
type => object,
|
|
||||||
required => [type, enable, rules],
|
|
||||||
properties => #{
|
|
||||||
type => #{
|
|
||||||
type => string,
|
|
||||||
enum => [<<"redis">>],
|
|
||||||
example => <<"redis">>
|
|
||||||
},
|
|
||||||
enable => #{
|
|
||||||
type => boolean,
|
|
||||||
example => true
|
|
||||||
},
|
|
||||||
rules => #{
|
|
||||||
type => array,
|
|
||||||
items => #{
|
|
||||||
type => string,
|
|
||||||
example =>
|
|
||||||
<<"{allow,{username,\"^dashboard?\"},","subscribe,[\"$SYS/#\"]}.\n",
|
<<"{allow,{username,\"^dashboard?\"},","subscribe,[\"$SYS/#\"]}.\n",
|
||||||
"{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}.">>
|
"{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}.">>}}
|
||||||
}
|
%% The path will be deprecated, `acl.conf` will be fixed in subdir of `data`
|
||||||
},
|
, {path, #{ type => binary()
|
||||||
path => #{
|
, example => <<"acl.conf">>}}];
|
||||||
type => string,
|
fields(position) ->
|
||||||
example => <<"/path/to/authorizaiton_rules.conf">>
|
[ { position
|
||||||
}
|
, mk( hoconsc:union([binary(), map()])
|
||||||
}
|
, #{ desc => <<"Where to place the source">>
|
||||||
},
|
, required => true
|
||||||
[ #{<<"sources">> => Sources}
|
, in => body
|
||||||
, #{<<"ssl">> => SSL}
|
, example => #{<<"before">> => <<"file">>}})}].
|
||||||
, #{<<"http">> => HTTP}
|
|
||||||
, #{<<"built-in-database">> => Mnesia}
|
%%------------------------------------------------------------------------------
|
||||||
, #{<<"mongo_single">> => MongoSingle}
|
%% http type funcs
|
||||||
, #{<<"mongo_rs">> => MongoRs}
|
|
||||||
, #{<<"mongo_sharded">> => MongoSharded}
|
url(type) -> binary();
|
||||||
, #{<<"mysql">> => Mysql}
|
url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")];
|
||||||
, #{<<"postgresql">> => Pgsql}
|
url(nullable) -> false;
|
||||||
, #{<<"redis_single">> => RedisSingle}
|
url(_) -> undefined.
|
||||||
, #{<<"redis_sentinel">> => RedisSentinel}
|
|
||||||
, #{<<"redis_cluster">> => RedisCluster}
|
headers(type) -> map();
|
||||||
, #{<<"file">> => File}
|
headers(converter) ->
|
||||||
|
fun(Headers) ->
|
||||||
|
maps:merge(default_headers(), transform_header_name(Headers))
|
||||||
|
end;
|
||||||
|
headers(default) -> default_headers();
|
||||||
|
headers(_) -> undefined.
|
||||||
|
|
||||||
|
body(type) -> map();
|
||||||
|
body(validator) -> [fun check_body/1];
|
||||||
|
body(_) -> 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=5">>
|
||||||
|
}.
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
%% body
|
||||||
|
|
||||||
|
check_body(Body) ->
|
||||||
|
lists:all(
|
||||||
|
fun erlang:is_binary/1,
|
||||||
|
maps:values(Body)).
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% MonogDB type funcs
|
||||||
|
|
||||||
|
authz_mongo_common_fields() ->
|
||||||
|
authz_common_fields(mongodb) ++
|
||||||
|
[ {collection, fun collection/1}
|
||||||
|
, {selector, fun selector/1}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
collection(type) -> binary();
|
||||||
|
collection(_) -> undefined.
|
||||||
|
|
||||||
|
selector(type) -> map();
|
||||||
|
selector(_) -> undefined.
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% Redis type funcs
|
||||||
|
|
||||||
|
authz_redis_common_fields() ->
|
||||||
|
authz_common_fields(redis) ++
|
||||||
|
[ {cmd, #{ type => binary()
|
||||||
|
, example => <<"HGETALL mqtt_authz">>}}].
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% Authz api type funcs
|
||||||
|
|
||||||
|
authz_common_fields(Type) when is_atom(Type)->
|
||||||
|
[ {enable, fun enable/1}
|
||||||
|
, {type, #{ type => enum([Type])
|
||||||
|
, default => Type
|
||||||
|
, in => body
|
||||||
|
, converter => fun to_bin/1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
].
|
||||||
|
|
||||||
|
enable(type) -> boolean();
|
||||||
|
enable(default) -> true;
|
||||||
|
enable(desc) -> "Set to <code>false</code> to disable this auth provider";
|
||||||
|
enable(_) -> undefined.
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% Internal funcs
|
||||||
|
|
||||||
|
authz_sources_types(Type) ->
|
||||||
|
case Type of
|
||||||
|
simple -> [mongodb, redis];
|
||||||
|
detailed -> [ mongo_single
|
||||||
|
, mongo_rs
|
||||||
|
, mongo_sharded
|
||||||
|
, redis_single
|
||||||
|
, redis_sentinel
|
||||||
|
, redis_cluster]
|
||||||
|
end
|
||||||
|
++
|
||||||
|
[ http
|
||||||
|
, '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).
|
||||||
|
|
||||||
|
to_bin(List) when is_list(List) -> list_to_binary(List);
|
||||||
|
to_bin(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8);
|
||||||
|
to_bin(X) -> X.
|
||||||
|
|
|
@ -18,9 +18,15 @@
|
||||||
|
|
||||||
-behaviour(minirest_api).
|
-behaviour(minirest_api).
|
||||||
|
|
||||||
|
-include_lib("typerefl/include/types.hrl").
|
||||||
-include("emqx_authz.hrl").
|
-include("emqx_authz.hrl").
|
||||||
-include_lib("emqx/include/logger.hrl").
|
-include_lib("emqx/include/logger.hrl").
|
||||||
|
|
||||||
|
-import(hoconsc, [mk/1, mk/2, ref/1, ref/2, array/1, enum/1]).
|
||||||
|
|
||||||
|
-define(BAD_REQUEST, 'BAD_REQUEST').
|
||||||
|
-define(NOT_FOUND, 'NOT_FOUND').
|
||||||
|
|
||||||
-define(EXAMPLE_REDIS,
|
-define(EXAMPLE_REDIS,
|
||||||
#{type=> redis,
|
#{type=> redis,
|
||||||
enable => true,
|
enable => true,
|
||||||
|
@ -44,290 +50,117 @@
|
||||||
|
|
||||||
-define(IS_TRUE(Val), ((Val =:= true) or (Val =:= <<"true">>))).
|
-define(IS_TRUE(Val), ((Val =:= true) or (Val =:= <<"true">>))).
|
||||||
|
|
||||||
|
-define(API_SCHEMA_MODULE, emqx_authz_api_schema).
|
||||||
|
|
||||||
-export([ get_raw_sources/0
|
-export([ get_raw_sources/0
|
||||||
, get_raw_source/1
|
, get_raw_source/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ api_spec/0
|
-export([ api_spec/0
|
||||||
, sources/2
|
, paths/0
|
||||||
|
, schema/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
-export([ sources/2
|
||||||
, source/2
|
, source/2
|
||||||
, move_source/2
|
, move_source/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
api_spec() ->
|
api_spec() ->
|
||||||
{[ sources_api()
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
|
||||||
, source_api()
|
|
||||||
, move_source_api()
|
|
||||||
], definitions()}.
|
|
||||||
|
|
||||||
definitions() -> emqx_authz_api_schema:definitions().
|
paths() ->
|
||||||
|
[ "/authorization/sources"
|
||||||
|
, "/authorization/sources/:type"
|
||||||
|
, "/authorization/sources/:type/move"].
|
||||||
|
|
||||||
sources_api() ->
|
%%--------------------------------------------------------------------
|
||||||
Metadata = #{
|
%% Schema for each URI
|
||||||
get => #{
|
%%--------------------------------------------------------------------
|
||||||
description => "List authorization sources",
|
|
||||||
responses => #{
|
|
||||||
<<"200">> => #{
|
|
||||||
description => <<"OK">>,
|
|
||||||
content => #{
|
|
||||||
'application/json' => #{
|
|
||||||
schema => #{
|
|
||||||
type => object,
|
|
||||||
required => [sources],
|
|
||||||
properties => #{sources => #{
|
|
||||||
type => array,
|
|
||||||
items => minirest:ref(<<"sources">>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
examples => #{
|
|
||||||
sources => #{
|
|
||||||
summary => <<"Sources">>,
|
|
||||||
value => jsx:encode(?EXAMPLE_RETURNED)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
post => #{
|
|
||||||
description => "Add new source",
|
|
||||||
'requestBody' => #{
|
|
||||||
content => #{
|
|
||||||
'application/json' => #{
|
|
||||||
schema => minirest:ref(<<"sources">>),
|
|
||||||
examples => #{
|
|
||||||
redis => #{
|
|
||||||
summary => <<"Redis">>,
|
|
||||||
value => jsx:encode(?EXAMPLE_REDIS)
|
|
||||||
},
|
|
||||||
file => #{
|
|
||||||
summary => <<"File">>,
|
|
||||||
value => jsx:encode(?EXAMPLE_FILE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
responses => #{
|
|
||||||
<<"204">> => #{description => <<"Created">>},
|
|
||||||
<<"400">> => emqx_mgmt_util:bad_request()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
put => #{
|
|
||||||
description => "Update all sources",
|
|
||||||
'requestBody' => #{
|
|
||||||
content => #{
|
|
||||||
'application/json' => #{
|
|
||||||
schema => #{
|
|
||||||
type => array,
|
|
||||||
items => minirest:ref(<<"sources">>)
|
|
||||||
},
|
|
||||||
examples => #{
|
|
||||||
redis => #{
|
|
||||||
summary => <<"Redis">>,
|
|
||||||
value => jsx:encode(?EXAMPLE_REDIS)
|
|
||||||
},
|
|
||||||
file => #{
|
|
||||||
summary => <<"File">>,
|
|
||||||
value => jsx:encode(?EXAMPLE_FILE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
responses => #{
|
|
||||||
<<"204">> => #{description => <<"Created">>},
|
|
||||||
<<"400">> => emqx_mgmt_util:bad_request()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{"/authorization/sources", Metadata, sources}.
|
|
||||||
|
|
||||||
source_api() ->
|
schema("/authorization/sources") ->
|
||||||
Metadata = #{
|
#{ 'operationId' => sources
|
||||||
get => #{
|
, get =>
|
||||||
description => "List authorization sources",
|
#{ description => <<"List all authorization sources">>
|
||||||
parameters => [
|
, responses =>
|
||||||
#{
|
#{ 200 => mk( array(hoconsc:union([ref(?API_SCHEMA_MODULE, Type) || Type <- authz_sources_types(detailed)]))
|
||||||
name => type,
|
, #{desc => <<"Authorization source">>})
|
||||||
in => path,
|
|
||||||
schema => #{
|
|
||||||
type => string,
|
|
||||||
enum => [ <<"file">>
|
|
||||||
, <<"http">>
|
|
||||||
, <<"mongodb">>
|
|
||||||
, <<"mysql">>
|
|
||||||
, <<"postgresql">>
|
|
||||||
, <<"redis">>
|
|
||||||
, <<"built-in-database">>
|
|
||||||
]
|
|
||||||
},
|
|
||||||
required => true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
responses => #{
|
|
||||||
<<"200">> => #{
|
|
||||||
description => <<"OK">>,
|
|
||||||
content => #{
|
|
||||||
'application/json' => #{
|
|
||||||
schema => minirest:ref(<<"sources">>),
|
|
||||||
examples => #{
|
|
||||||
redis => #{
|
|
||||||
summary => <<"Redis">>,
|
|
||||||
value => jsx:encode(?EXAMPLE_REDIS)
|
|
||||||
},
|
|
||||||
file => #{
|
|
||||||
summary => <<"File">>,
|
|
||||||
value => jsx:encode(?EXAMPLE_FILE)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
, post =>
|
||||||
|
#{ description => <<"Add a new source">>
|
||||||
|
, 'requestBody' => mk( hoconsc:union([ref(?API_SCHEMA_MODULE, Type) || Type <- authz_sources_types(detailed)])
|
||||||
|
, #{desc => <<"Source config">>})
|
||||||
|
, responses =>
|
||||||
|
#{ 204 => <<"Authorization source created successfully">>
|
||||||
|
, 400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad Request">>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
, put =>
|
||||||
<<"404">> => emqx_mgmt_util:bad_request(<<"Not Found">>)
|
#{ description => <<"Update all sources">>
|
||||||
}
|
, 'requestBody' => mk( array(hoconsc:union([ref(?API_SCHEMA_MODULE, Type) || Type <- authz_sources_types(detailed)]))
|
||||||
},
|
, #{desc => <<"Sources">>})
|
||||||
put => #{
|
, responses =>
|
||||||
description => "Update source",
|
#{ 204 => <<"Authorization source updated successfully">>
|
||||||
parameters => [
|
, 400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad Request">>)
|
||||||
#{
|
|
||||||
name => type,
|
|
||||||
in => path,
|
|
||||||
schema => #{
|
|
||||||
type => string,
|
|
||||||
enum => [ <<"file">>
|
|
||||||
, <<"http">>
|
|
||||||
, <<"mongodb">>
|
|
||||||
, <<"mysql">>
|
|
||||||
, <<"postgresql">>
|
|
||||||
, <<"redis">>
|
|
||||||
, <<"built-in-database">>
|
|
||||||
]
|
|
||||||
},
|
|
||||||
required => true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'requestBody' => #{
|
|
||||||
content => #{
|
|
||||||
'application/json' => #{
|
|
||||||
schema => minirest:ref(<<"sources">>),
|
|
||||||
examples => #{
|
|
||||||
redis => #{
|
|
||||||
summary => <<"Redis">>,
|
|
||||||
value => jsx:encode(?EXAMPLE_REDIS)
|
|
||||||
},
|
|
||||||
file => #{
|
|
||||||
summary => <<"File">>,
|
|
||||||
value => jsx:encode(?EXAMPLE_FILE)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
schema("/authorization/sources/:type") ->
|
||||||
|
#{ 'operationId' => source
|
||||||
|
, get =>
|
||||||
|
#{ description => <<"Get a authorization source">>
|
||||||
|
, parameters => parameters_field()
|
||||||
|
, responses =>
|
||||||
|
#{ 200 => mk( hoconsc:union([ref(?API_SCHEMA_MODULE, Type) || Type <- authz_sources_types(detailed)])
|
||||||
|
, #{desc => <<"Authorization source">>})
|
||||||
|
, 404 => emqx_dashboard_swagger:error_codes([?NOT_FOUND], <<"Not Found">>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
, put =>
|
||||||
responses => #{
|
#{ description => <<"Update source">>
|
||||||
<<"204">> => #{description => <<"No Content">>},
|
, parameters => parameters_field()
|
||||||
<<"404">> => emqx_mgmt_util:bad_request(<<"Not Found">>),
|
, 'requestBody' => mk( hoconsc:union([ref(?API_SCHEMA_MODULE, Type) || Type <- authz_sources_types(detailed)]))
|
||||||
<<"400">> => emqx_mgmt_util:bad_request()
|
, responses =>
|
||||||
}
|
#{ 204 => <<"Authorization source updated successfully">>
|
||||||
},
|
, 400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad Request">>)
|
||||||
delete => #{
|
, 404 => emqx_dashboard_swagger:error_codes([?NOT_FOUND], <<"Not Found">>)
|
||||||
description => "Delete source",
|
|
||||||
parameters => [
|
|
||||||
#{
|
|
||||||
name => type,
|
|
||||||
in => path,
|
|
||||||
schema => #{
|
|
||||||
type => string,
|
|
||||||
enum => [ <<"file">>
|
|
||||||
, <<"http">>
|
|
||||||
, <<"mongodb">>
|
|
||||||
, <<"mysql">>
|
|
||||||
, <<"postgresql">>
|
|
||||||
, <<"redis">>
|
|
||||||
, <<"built-in-database">>
|
|
||||||
]
|
|
||||||
},
|
|
||||||
required => true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
responses => #{
|
|
||||||
<<"204">> => #{description => <<"Deleted">>},
|
|
||||||
<<"400">> => emqx_mgmt_util:bad_request()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
, delete =>
|
||||||
{"/authorization/sources/:type", Metadata, source}.
|
#{ description => <<"Delete source">>
|
||||||
|
, parameters => parameters_field()
|
||||||
|
, responses =>
|
||||||
|
#{ 204 => <<"Deleted successfully">>
|
||||||
|
, 400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad Request">>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
schema("/authorization/sources/:type/move") ->
|
||||||
|
#{ 'operationId' => move_source
|
||||||
|
, post =>
|
||||||
|
#{ description => <<"Change the order of sources">>
|
||||||
|
, parameters => parameters_field()
|
||||||
|
, 'requestBody' =>
|
||||||
|
emqx_dashboard_swagger:schema_with_examples(
|
||||||
|
ref(?API_SCHEMA_MODULE, position),
|
||||||
|
position_example())
|
||||||
|
, responses =>
|
||||||
|
#{ 204 => <<"No Content">>
|
||||||
|
, 400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad Request">>)
|
||||||
|
, 404 => emqx_dashboard_swagger:error_codes([?NOT_FOUND], <<"Not Found">>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.
|
||||||
|
|
||||||
move_source_api() ->
|
|
||||||
Metadata = #{
|
|
||||||
post => #{
|
|
||||||
description => "Change the order of sources",
|
|
||||||
parameters => [
|
|
||||||
#{
|
|
||||||
name => type,
|
|
||||||
in => path,
|
|
||||||
schema => #{
|
|
||||||
type => string,
|
|
||||||
enum => [ <<"file">>
|
|
||||||
, <<"http">>
|
|
||||||
, <<"mongodb">>
|
|
||||||
, <<"mysql">>
|
|
||||||
, <<"postgresql">>
|
|
||||||
, <<"redis">>
|
|
||||||
, <<"built-in-database">>
|
|
||||||
]
|
|
||||||
},
|
|
||||||
required => true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'requestBody' => #{
|
|
||||||
content => #{
|
|
||||||
'application/json' => #{
|
|
||||||
schema => #{
|
|
||||||
type => object,
|
|
||||||
required => [position],
|
|
||||||
properties => #{
|
|
||||||
position => #{
|
|
||||||
'oneOf' => [
|
|
||||||
#{type => string,
|
|
||||||
enum => [<<"top">>, <<"bottom">>]
|
|
||||||
},
|
|
||||||
#{type => object,
|
|
||||||
required => ['after'],
|
|
||||||
properties => #{
|
|
||||||
'after' => #{
|
|
||||||
type => string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
#{type => object,
|
|
||||||
required => ['before'],
|
|
||||||
properties => #{
|
|
||||||
'before' => #{
|
|
||||||
type => string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
responses => #{
|
|
||||||
<<"204">> => #{
|
|
||||||
description => <<"No Content">>
|
|
||||||
},
|
|
||||||
<<"404">> => emqx_mgmt_util:bad_request(<<"Not Found">>),
|
|
||||||
<<"400">> => emqx_mgmt_util:bad_request()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{"/authorization/sources/:type/move", Metadata, move_source}.
|
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Operation functions
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
sources(Method, #{bindings := #{type := Type} = Bindings } = Req)
|
||||||
|
when is_atom(Type) ->
|
||||||
|
sources(Method, Req#{bindings => Bindings#{type => bin(Type)}});
|
||||||
sources(get, _) ->
|
sources(get, _) ->
|
||||||
Sources = lists:foldl(fun (#{<<"type">> := <<"file">>,
|
Sources = lists:foldl(fun (#{<<"type">> := <<"file">>,
|
||||||
<<"enable">> := Enable, <<"path">> := Path}, AccIn) ->
|
<<"enable">> := Enable, <<"path">> := Path}, AccIn) ->
|
||||||
|
@ -364,6 +197,9 @@ sources(put, #{body := Body}) when is_list(Body) ->
|
||||||
end || Source <- Body],
|
end || Source <- Body],
|
||||||
update_config(?CMD_REPLACE, NBody).
|
update_config(?CMD_REPLACE, NBody).
|
||||||
|
|
||||||
|
source(Method, #{bindings := #{type := Type} = Bindings } = Req)
|
||||||
|
when is_atom(Type) ->
|
||||||
|
source(Method, Req#{bindings => Bindings#{type => bin(Type)}});
|
||||||
source(get, #{bindings := #{type := Type}}) ->
|
source(get, #{bindings := #{type := Type}}) ->
|
||||||
case get_raw_source(Type) of
|
case get_raw_source(Type) of
|
||||||
[] -> {404, #{message => <<"Not found ", Type/binary>>}};
|
[] -> {404, #{message => <<"Not found ", Type/binary>>}};
|
||||||
|
@ -390,6 +226,9 @@ source(put, #{bindings := #{type := <<"file">>}, body := #{<<"type">> := <<"file
|
||||||
<<"enable">> => Enable,
|
<<"enable">> => Enable,
|
||||||
<<"path">> => Filename}) of
|
<<"path">> => Filename}) of
|
||||||
{ok, _} -> {204};
|
{ok, _} -> {204};
|
||||||
|
{error, {emqx_conf_schema, _}} ->
|
||||||
|
{400, #{code => <<"BAD_REQUEST">>,
|
||||||
|
message => <<"BAD_SCHEMA">>}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{400, #{code => <<"BAD_REQUEST">>,
|
{400, #{code => <<"BAD_REQUEST">>,
|
||||||
message => bin(Reason)}}
|
message => bin(Reason)}}
|
||||||
|
@ -399,17 +238,27 @@ source(put, #{bindings := #{type := Type}, body := Body}) when is_map(Body) ->
|
||||||
source(delete, #{bindings := #{type := Type}}) ->
|
source(delete, #{bindings := #{type := Type}}) ->
|
||||||
update_config({?CMD_DELETE, Type}, #{}).
|
update_config({?CMD_DELETE, Type}, #{}).
|
||||||
|
|
||||||
|
move_source(Method, #{bindings := #{type := Type} = Bindings } = Req)
|
||||||
|
when is_atom(Type) ->
|
||||||
|
move_source(Method, Req#{bindings => Bindings#{type => bin(Type)}});
|
||||||
move_source(post, #{bindings := #{type := Type}, body := #{<<"position">> := Position}}) ->
|
move_source(post, #{bindings := #{type := Type}, body := #{<<"position">> := Position}}) ->
|
||||||
case emqx_authz:move(Type, Position) of
|
case emqx_authz:move(Type, Position) of
|
||||||
{ok, _} -> {204};
|
{ok, _} -> {204};
|
||||||
{error, not_found_source} ->
|
{error, not_found_source} ->
|
||||||
{404, #{code => <<"NOT_FOUND">>,
|
{404, #{code => <<"NOT_FOUND">>,
|
||||||
message => <<"source ", Type/binary, " not found">>}};
|
message => <<"source ", Type/binary, " not found">>}};
|
||||||
|
{error, {emqx_conf_schema, _}} ->
|
||||||
|
{400, #{code => <<"BAD_REQUEST">>,
|
||||||
|
message => <<"BAD_SCHEMA">>}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{400, #{code => <<"BAD_REQUEST">>,
|
{400, #{code => <<"BAD_REQUEST">>,
|
||||||
message => bin(Reason)}}
|
message => bin(Reason)}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Internal functions
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
get_raw_sources() ->
|
get_raw_sources() ->
|
||||||
RawSources = emqx:get_raw_config([authorization, sources], []),
|
RawSources = emqx:get_raw_config([authorization, sources], []),
|
||||||
Schema = #{roots => emqx_authz_schema:fields("authorization"), fields => #{}},
|
Schema = #{roots => emqx_authz_schema:fields("authorization"), fields => #{}},
|
||||||
|
@ -449,6 +298,10 @@ update_config(Cmd, Sources) ->
|
||||||
{error, {post_config_update, emqx_authz, Reason}} ->
|
{error, {post_config_update, emqx_authz, Reason}} ->
|
||||||
{400, #{code => <<"BAD_REQUEST">>,
|
{400, #{code => <<"BAD_REQUEST">>,
|
||||||
message => bin(Reason)}};
|
message => bin(Reason)}};
|
||||||
|
%% TODO: The `Reason` may cann't be trans to json term. (i.e. ecpool start failed)
|
||||||
|
{error, {emqx_conf_schema, _}} ->
|
||||||
|
{400, #{code => <<"BAD_REQUEST">>,
|
||||||
|
message => <<"BAD_SCHEMA">>}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{400, #{code => <<"BAD_REQUEST">>,
|
{400, #{code => <<"BAD_REQUEST">>,
|
||||||
message => bin(Reason)}}
|
message => bin(Reason)}}
|
||||||
|
@ -489,8 +342,21 @@ do_write_file(Filename, Bytes) ->
|
||||||
error(Reason)
|
error(Reason)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
bin(Term) ->
|
bin(List) when is_list(List) -> list_to_binary(List);
|
||||||
erlang:iolist_to_binary(io_lib:format("~p", [Term])).
|
bin(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8);
|
||||||
|
bin(X) -> X.
|
||||||
|
|
||||||
acl_conf_file() ->
|
acl_conf_file() ->
|
||||||
emqx_authz:acl_conf_file().
|
emqx_authz:acl_conf_file().
|
||||||
|
|
||||||
|
parameters_field() ->
|
||||||
|
[ {type, mk( enum(?API_SCHEMA_MODULE:authz_sources_types(simple))
|
||||||
|
, #{in => path, desc => <<"Authorization type">>})
|
||||||
|
}
|
||||||
|
].
|
||||||
|
|
||||||
|
position_example() ->
|
||||||
|
#{<<"position">> => #{<<"before">> => <<"file">>}}.
|
||||||
|
|
||||||
|
authz_sources_types(Type) ->
|
||||||
|
emqx_authz_api_schema:authz_sources_types(Type).
|
||||||
|
|
Loading…
Reference in New Issue