refactor(gw): deps on emqx_dasboard_swagger

This commit is contained in:
JianBo He 2021-11-19 11:20:48 +08:00
parent 90a65b8d04
commit f033fad7b3
7 changed files with 597 additions and 321 deletions

View File

@ -65,6 +65,15 @@
, response_users_example/0
]).
%% export these funcs for gateway
-export([ list_users/3
, add_user/3
, delete_user/3
, find_user/3
, update_user/4
, serialize_error/1
]).
api_spec() ->
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).

View File

@ -18,21 +18,34 @@
-behaviour(minirest_api).
-include_lib("typerefl/include/types.hrl").
-define(BAD_REQUEST, 'BAD_REQUEST').
-define(NOT_FOUND, 'NOT_FOUND').
-define(INTERNAL_ERROR, 'INTERNAL_SERVER_ERROR').
-import(hoconsc, [mk/2, ref/2]).
-import(emqx_dashboard_swagger, [error_codes/2]).
-import(emqx_gateway_http,
[ return_http_error/2
, schema_bad_request/0
, schema_not_found/0
, schema_internal_error/0
, schema_no_content/0
, with_gateway/2
, with_authn/2
, checks/2
]).
%% minirest behaviour callbacks
-export([api_spec/0]).
%% minirest/dashbaord_swagger behaviour callbacks
-export([ api_spec/0
, paths/0
, schema/1
]).
%% http handlers
-export([authn/2]).
-export([ authn/2
, users/2
, users_insta/2
, import_users/2
]).
%% internal export for emqx_gateway_api_listeners module
-export([schema_authn/0]).
@ -42,10 +55,13 @@
%%--------------------------------------------------------------------
api_spec() ->
{metadata(apis()), []}.
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
apis() ->
[ {"/gateway/:name/authentication", authn}
paths() ->
[ "/gateway/:name/authentication"
, "/gateway/:name/authentication/users"
, "/gateway/:name/authentication/users/:uid"
, "/gateway/:name/authentication/import_users"
].
%%--------------------------------------------------------------------
@ -83,87 +99,245 @@ authn(delete, #{bindings := #{name := Name0}}) ->
{204}
end).
users(get, #{bindings := #{name := Name0}, query_string := Qs}) ->
with_authn(Name0, fun(_GwName, #{id := AuthId,
chain_name := ChainName}) ->
emqx_authn_api:list_users(ChainName, AuthId, page_pramas(Qs))
end);
users(post, #{bindings := #{name := Name0},
body := Body}) ->
with_authn(Name0, fun(_GwName, #{id := AuthId,
chain_name := ChainName}) ->
emqx_authn_api:add_user(ChainName, AuthId, Body)
end).
users_insta(get, #{bindings := #{name := Name0, uid := UserId}}) ->
with_authn(Name0, fun(_GwName, #{id := AuthId,
chain_name := ChainName}) ->
emqx_authn_api:find_user(ChainName, AuthId, UserId)
end);
users_insta(put, #{bindings := #{name := Name0, uid := UserId},
body := Body}) ->
with_authn(Name0, fun(_GwName, #{id := AuthId,
chain_name := ChainName}) ->
emqx_authn_api:update_user(ChainName, AuthId, UserId, Body)
end);
users_insta(delete, #{bindings := #{name := Name0, uid := UserId}}) ->
with_authn(Name0, fun(_GwName, #{id := AuthId,
chain_name := ChainName}) ->
emqx_authn_api:delete_user(ChainName, AuthId, UserId)
end).
import_users(post, #{bindings := #{name := Name0},
body := Body}) ->
with_authn(Name0, fun(_GwName, #{id := AuthId,
chain_name := ChainName}) ->
case maps:get(<<"filename">>, Body, undefined) of
undefined ->
emqx_authn_api:serialize_error({missing_parameter, filename});
Filename ->
case emqx_authentication:import_users(
ChainName, AuthId, Filename) of
ok -> {204};
{error, Reason} ->
emqx_authn_api:serialize_error(Reason)
end
end
end).
%%--------------------------------------------------------------------
%% Utils
page_pramas(Qs) ->
maps:with([<<"page">>, <<"limit">>], Qs).
%%--------------------------------------------------------------------
%% Swagger defines
%%--------------------------------------------------------------------
metadata(APIs) ->
metadata(APIs, []).
metadata([], APIAcc) ->
lists:reverse(APIAcc);
metadata([{Path, Fun}|More], APIAcc) ->
Methods = [get, post, put, delete, patch],
Mds = lists:foldl(fun(M, Acc) ->
try
Acc#{M => swagger(Path, M)}
catch
error : function_clause ->
Acc
end
end, #{}, Methods),
metadata(More, [{Path, Mds, Fun} | APIAcc]).
swagger("/gateway/:name/authentication", get) ->
#{ description => <<"Get the gateway authentication">>
, parameters => params_gateway_name_in_path()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"200">> => schema_authn()
, <<"204">> => schema_no_content()
}
schema("/gateway/:name/authentication") ->
#{ 'operationId' => authn,
get =>
#{ description => <<"Get the gateway authentication">>
, parameters => params_gateway_name_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 200 => schema_authn()
, 204 => <<"Authentication does not initiated">>
}
},
put =>
#{ description => <<"Update authentication for the gateway">>
, parameters => params_gateway_name_in_path()
, requestBody => schema_authn()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 204 => <<"Updated">> %% XXX: ??? return the updated object
}
},
post =>
#{ description => <<"Add authentication for the gateway">>
, parameters => params_gateway_name_in_path()
, requestBody => schema_authn()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 204 => <<"Added">>
}
},
delete =>
#{ description => <<"Remove the gateway authentication">>
, parameters => params_gateway_name_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 204 => <<"Deleted">>
}
}
};
swagger("/gateway/:name/authentication", put) ->
#{ description => <<"Update authentication for the gateway">>
, parameters => params_gateway_name_in_path()
, requestBody => schema_authn()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"204">> => schema_no_content()
}
schema("/gateway/:name/authentication/users") ->
#{ 'operationId' => users
, get =>
#{ description => <<"Get the users for the authentication">>
, parameters => params_gateway_name_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 200 => emqx_dashboard_swagger:schema_with_example(
ref(emqx_authn_api, response_user),
emqx_authn_api:response_user_examples())
}
},
post =>
#{ description => <<"Add user for the authentication">>
, parameters => params_gateway_name_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 201 => emqx_dashboard_swagger:schema_with_example(
ref(emqx_authn_api, response_user),
emqx_authn_api:response_user_examples())
}
}
};
swagger("/gateway/:name/authentication", post) ->
#{ description => <<"Add authentication for the gateway">>
, parameters => params_gateway_name_in_path()
, requestBody => schema_authn()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"204">> => schema_no_content()
}
schema("/gateway/:name/authentication/users/:uid") ->
#{ 'operationId' => users_insta
, get =>
#{ description => <<"Get user info from the gateway "
"authentication">>
, parameters => params_gateway_name_in_path() ++
params_userid_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 200 => emqx_dashboard_swagger:schema_with_example(
ref(emqx_authn_api, response_user),
emqx_authn_api:response_user_examples())
}
},
put =>
#{ description => <<"Update the user info for the gateway "
"authentication">>
, parameters => params_gateway_name_in_path() ++
params_userid_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 200 => emqx_dashboard_swagger:schema_with_example(
ref(emqx_authn_api, response_user),
emqx_authn_api:response_user_examples())
}
},
delete =>
#{ description => <<"Delete the user for the gateway "
"authentication">>
, parameters => params_gateway_name_in_path() ++
params_userid_in_path() ++
params_paging_in_qs()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 200 => emqx_dashboard_swagger:schema_with_example(
ref(emqx_authn_api, response_user),
emqx_authn_api:response_user_examples())
}
}
};
swagger("/gateway/:name/authentication", delete) ->
#{ description => <<"Remove the gateway authentication">>
, parameters => params_gateway_name_in_path()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"204">> => schema_no_content()
}
schema("/gateway/:name/authentication/import_users") ->
#{ 'operationId' => import_users
, post =>
#{ description => <<"Import users into the gateway authentication">>
, parameters => params_gateway_name_in_path()
, requestBody => emqx_dashboard_swagger:schema_with_examples(
ref(emqx_authn_api, request_import_users),
emqx_authn_api:request_import_users_examples()
)
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
%% XXX: Put a hint message into 204 return ?
, 204 => <<"Imported">>
}
}
}.
%%--------------------------------------------------------------------
%% params defines
params_gateway_name_in_path() ->
[#{ name => name
, in => path
, schema => #{type => string}
, required => true
}].
[{name,
mk(binary(),
#{ in => path
, desc => <<"Gateway Name">>
})}
].
params_userid_in_path() ->
[{uid, mk(binary(),
#{ in => path
, desc => <<"User ID">>
})}
].
params_paging_in_qs() ->
[{page, mk(integer(),
#{ in => query
, desc => <<"Page Number">>
})},
{limit, mk(integer(),
#{ in => query
, desc => <<"Page Limit">>
})}
].
%%--------------------------------------------------------------------
%% schemas
schema_authn() ->
#{ description => <<"OK">>
, content => #{
'application/json' => #{
schema => minirest:ref(<<"AuthenticatorInstance">>)
}}
}.
emqx_dashboard_swagger:schema_with_examples(
emqx_authn_schema:authenticator_type(),
emqx_authn_api:authenticator_examples()
).

View File

@ -18,20 +18,32 @@
-behaviour(minirest_api).
-include_lib("typerefl/include/types.hrl").
-define(BAD_REQUEST, 'BAD_REQUEST').
-define(NOT_FOUND, 'NOT_FOUND').
-define(INTERNAL_ERROR, 'INTERNAL_SERVER_ERROR').
-import(hoconsc, [mk/2, ref/1, ref/2]).
-import(emqx_dashboard_swagger, [error_codes/2]).
-import(emqx_gateway_http,
[ return_http_error/2
, schema_bad_request/0
, schema_not_found/0
, schema_internal_error/0
, schema_no_content/0
, with_gateway/2
, checks/2
]).
-import(emqx_gateway_api_authn, [schema_authn/0]).
%% minirest behaviour callbacks
-export([api_spec/0]).
%% minirest/dashbaord_swagger behaviour callbacks
-export([ api_spec/0
, paths/0
, schema/1
]).
-export([ roots/0
, fields/1
]).
%% http handlers
-export([ listeners/2
@ -44,12 +56,12 @@
%%--------------------------------------------------------------------
api_spec() ->
{metadata(apis()), []}.
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
apis() ->
[ {"/gateway/:name/listeners", listeners}
, {"/gateway/:name/listeners/:id", listeners_insta}
, {"/gateway/:name/listeners/:id/authentication", listeners_insta_authn}
paths() ->
[ "/gateway/:name/listeners"
, "/gateway/:name/listeners/:id"
, "/gateway/:name/listeners/:id/authentication"
].
%%--------------------------------------------------------------------
@ -149,219 +161,228 @@ listeners_insta_authn(delete, #{bindings := #{name := Name0,
%% Swagger defines
%%--------------------------------------------------------------------
metadata(APIs) ->
metadata(APIs, []).
metadata([], APIAcc) ->
lists:reverse(APIAcc);
metadata([{Path, Fun}|More], APIAcc) ->
Methods = [get, post, put, delete, patch],
Mds = lists:foldl(fun(M, Acc) ->
try
Acc#{M => swagger(Path, M)}
catch
error : function_clause ->
Acc
end
end, #{}, Methods),
metadata(More, [{Path, Mds, Fun} | APIAcc]).
swagger("/gateway/:name/listeners", get) ->
#{ description => <<"Get the gateway listeners">>
, parameters => params_gateway_name_in_path()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"200">> => schema_listener_list()
}
schema("/gateway/:name/listeners") ->
#{ 'operationId' => listeners,
get =>
#{ description => <<"Get the gateway listeners">>
, parameters => params_gateway_name_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 200 => emqx_dashboard_swagger:schema_with_examples(
hoconsc:array(ref(listener)),
examples_listener_list())
}
},
post =>
#{ description => <<"Create the gateway listener">>
, parameters => params_gateway_name_in_path()
, requestBody => emqx_dashboard_swagger:schema_with_examples(
ref(listener),
examples_listener())
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 204 => <<"Created">>
}
}
};
swagger("/gateway/:name/listeners", post) ->
#{ description => <<"Create the gateway listener">>
, parameters => params_gateway_name_in_path()
, requestBody => schema_listener()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"200">> => schema_listener_list()
}
schema("/gateway/:name/listeners/:id") ->
#{ 'operationId' => listeners_insta,
get =>
#{ description => <<"Get the gateway listener configurations">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 200 => emqx_dashboard_swagger:schema_with_examples(
ref(listener),
examples_listener())
}
},
delete =>
#{ description => <<"Delete the gateway listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 204 => <<"Deleted">>
}
},
put =>
#{ description => <<"Update the gateway listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, requestBody => emqx_dashboard_swagger:schema_with_examples(
ref(listener),
examples_listener())
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 200 => <<"Updated">>
}
}
};
swagger("/gateway/:name/listeners/:id", get) ->
#{ description => <<"Get the gateway listener configurations">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"200">> => schema_listener()
}
};
swagger("/gateway/:name/listeners/:id", delete) ->
#{ description => <<"Delete the gateway listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"204">> => schema_no_content()
}
};
swagger("/gateway/:name/listeners/:id", put) ->
#{ description => <<"Update the gateway listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, requestBody => schema_listener()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"200">> => schema_no_content()
}
};
swagger("/gateway/:name/listeners/:id/authentication", get) ->
#{ description => <<"Get the listener's authentication info">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"200">> => schema_authn()
, <<"204">> => schema_no_content()
}
};
swagger("/gateway/:name/listeners/:id/authentication", post) ->
#{ description => <<"Add authentication for the listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, requestBody => schema_authn()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"204">> => schema_no_content()
}
};
swagger("/gateway/:name/listeners/:id/authentication", put) ->
#{ description => <<"Update authentication for the listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, requestBody => schema_authn()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"204">> => schema_no_content()
}
};
swagger("/gateway/:name/listeners/:id/authentication", delete) ->
#{ description => <<"Remove authentication for the listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, responses =>
#{ <<"400">> => schema_bad_request()
, <<"404">> => schema_not_found()
, <<"500">> => schema_internal_error()
, <<"204">> => schema_no_content()
}
schema("/gateway/:name/listeners/:id/authentication") ->
#{ 'operationId' => listeners_insta_authn,
get =>
#{ description => <<"Get the listener's authentication info">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 200 => schema_authn()
, 204 => <<"Authentication does not initiated">>
}
},
post =>
#{ description => <<"Add authentication for the listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, requestBody => schema_authn()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 204 => <<"Added">>
}
},
put =>
#{ description => <<"Update authentication for the listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, requestBody => schema_authn()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 204 => <<"Updated">>
}
},
delete =>
#{ description => <<"Remove authentication for the listener">>
, parameters => params_gateway_name_in_path()
++ params_listener_id_in_path()
, responses =>
#{ 400 => error_codes([?BAD_REQUEST], <<"Bad Request">>)
, 404 => error_codes([?NOT_FOUND], <<"Not Found">>)
, 500 => error_codes([?INTERNAL_ERROR],
<<"Ineternal Server Error">>)
, 204 => <<"Deleted">>
}
}
}.
%%--------------------------------------------------------------------
%% params defines
params_gateway_name_in_path() ->
[#{ name => name
, in => path
, schema => #{type => string}
, required => true
}].
[{name,
mk(binary(),
#{ in => path
, desc => <<"Gateway Name">>
})}
].
params_listener_id_in_path() ->
[#{ name => id
, in => path
, schema => #{type => string}
, required => true
}].
[{id,
mk(binary(),
#{ in => path
, desc => <<"Listener ID">>
})}
].
%%--------------------------------------------------------------------
%% schemas
schema_listener_list() ->
emqx_mgmt_util:array_schema(
#{ type => object
, properties => properties_listener()
},
<<"Listener list">>
).
schema_listener() ->
emqx_mgmt_util:schema(
#{ type => object
, properties => properties_listener()
}
).
%%--------------------------------------------------------------------
%% properties
properties_listener() ->
emqx_mgmt_util:properties(
raw_properties_common_listener() ++
[ {tcp, object, raw_properties_tcp_opts()}
, {ssl, object, raw_properties_ssl_opts()}
, {udp, object, raw_properties_udp_opts()}
, {dtls, object, raw_properties_dtls_opts()}
]).
raw_properties_tcp_opts() ->
[ {active_n, integer, <<>>}
, {backlog, integer, <<>>}
, {buffer, string, <<>>}
, {recbuf, string, <<>>}
, {sndbuf, string, <<>>}
, {high_watermark, string, <<>>}
, {nodelay, boolean, <<>>}
, {reuseaddr, boolean, <<>>}
, {send_timeout, string, <<>>}
, {send_timeout_close, boolean, <<>>}
roots() ->
[ listener
].
raw_properties_ssl_opts() ->
[ {cacertfile, string, <<>>}
, {certfile, string, <<>>}
, {keyfile, string, <<>>}
, {verify, string, <<>>}
, {fail_if_no_peer_cert, boolean, <<>>}
, {server_name_indication, boolean, <<>>}
, {depth, integer, <<>>}
, {password, string, <<>>}
, {handshake_timeout, string, <<>>}
, {versions, {array, string}, <<>>}
, {ciphers, {array, string}, <<>>}
, {user_lookup_fun, string, <<>>}
, {reuse_sessions, boolean, <<>>}
, {secure_renegotiate, boolean, <<>>}
, {honor_cipher_order, boolean, <<>>}
, {dhfile, string, <<>>}
].
raw_properties_udp_opts() ->
[ {active_n, integer, <<>>}
, {buffer, string, <<>>}
, {recbuf, string, <<>>}
, {sndbuf, string, <<>>}
, {reuseaddr, boolean, <<>>}
].
raw_properties_dtls_opts() ->
fields(listener) ->
common_listener_opts() ++
[ {tcp,
mk(ref(tcp_listener_opts),
#{ nullable => {true, recursively}
, desc => <<"The tcp socket options for tcp or ssl listener">>
})}
, {ssl,
mk(ref(ssl_listener_opts),
#{ nullable => {true, recursively}
, desc => <<"The ssl socket options for ssl listener">>
})}
, {udp,
mk(ref(udp_listener_opts),
#{ nullable => {true, recursively}
, desc => <<"The udp socket options for udp or dtls listener">>
})}
, {dtls,
mk(ref(dtls_listener_opts),
#{ nullable => {true, recursively}
, desc => <<"The dtls socket options for dtls listener">>
})}
];
fields(tcp_listener_opts) ->
[ {active_n, mk(integer(), #{})}
, {backlog, mk(integer(), #{})}
, {buffer, mk(binary(), #{})}
, {recbuf, mk(binary(), #{})}
, {sndbuf, mk(binary(), #{})}
, {high_watermark, mk(binary(), #{})}
, {nodelay, mk(boolean(), #{})}
, {reuseaddr, boolean()}
, {send_timeout, binary()}
, {send_timeout_close, boolean()}
];
fields(ssl_listener_opts) ->
[ {cacertfile, binary()}
, {certfile, binary()}
, {keyfile, binary()}
, {verify, binary()}
, {fail_if_no_peer_cert, boolean()}
, {server_name_indication, boolean()}
, {depth, integer()}
, {password, binary()}
, {handshake_timeout, binary()}
, {versions, hoconsc:array(binary())}
, {ciphers, hoconsc:array(binary())}
, {user_lookup_fun, binary()}
, {reuse_sessions, boolean()}
, {secure_renegotiate, boolean()}
, {honor_cipher_order, boolean()}
, {dhfile, binary()}
];
fields(udp_listener_opts) ->
[ {active_n, integer()}
, {buffer, binary()}
, {recbuf, binary()}
, {sndbuf, binary()}
, {reuseaddr, boolean()}
];
fields(dtls_listener_opts) ->
Ls = lists_key_without(
[versions,ciphers,handshake_timeout], 1,
raw_properties_ssl_opts()
fields(ssl_listener_opts)
),
[ {versions, {array, string}, <<>>}
, {ciphers, {array, string}, <<>>}
[ {versions, hoconsc:array(binary())}
, {ciphers, hoconsc:array(binary())}
| Ls].
lists_key_without([], _N, L) ->
@ -369,23 +390,67 @@ lists_key_without([], _N, L) ->
lists_key_without([K|Ks], N, L) ->
lists_key_without(Ks, N, lists:keydelete(K, N, L)).
raw_properties_common_listener() ->
[ {enable, boolean, <<"Whether to enable this listener">>}
, {id, string, <<"Listener Id">>}
, {name, string, <<"Listener name">>}
, {type, string,
<<"Listener type. Enum: tcp, udp, ssl, dtls">>,
[<<"tcp">>, <<"ssl">>, <<"udp">>, <<"dtls">>]}
, {running, boolean, <<"Listener running status">>}
, {bind, string, <<"Listener bind address or port">>}
, {acceptors, integer, <<"Listener acceptors number">>}
, {access_rules, {array, string}, <<"Listener Access rules for client">>}
, {max_conn_rate, integer, <<"Max connection rate for the listener">>}
, {max_connections, integer, <<"Max connections for the listener">>}
, {mountpoint, string,
<<"The Mounpoint for clients of the listener. "
"The gateway-level mountpoint configuration can be overloaded "
"when it is not null or empty string">>}
common_listener_opts() ->
[ {enable,
mk(boolean(),
#{ nullable => true
, desc => <<"Whether to enable this listener">>})}
, {id,
mk(binary(),
#{ nullable => true
, desc => <<"Listener Id">>})}
, {name,
mk(binary(),
#{ nullable => true
, desc => <<"Listener name">>})}
, {type,
mk(hoconsc:enum([tcp, ssl, udp, dtls]),
#{ nullable => true
, desc => <<"Listener type. Enum: tcp, udp, ssl, dtls">>})}
, {running,
mk(boolean(),
#{ nullable => true
, desc => <<"Listener running status">>})}
, {bind,
mk(binary(),
#{ nullable => true
, desc => <<"Listener bind address or port">>})}
, {acceptors,
mk(integer(),
#{ nullable => true
, desc => <<"Listener acceptors number">>})}
, {access_rules,
mk(hoconsc:array(binary()),
#{ nullable => true
, desc => <<"Listener Access rules for client">>})}
, {max_conn_rate,
mk(integer(),
#{ nullable => true
, desc => <<"Max connection rate for the listener">>})}
, {max_connections,
mk(integer(),
#{ nullable => true
, desc => <<"Max connections for the listener">>})}
, {mountpoint,
mk(binary(),
#{ nullable => true
, desc =>
<<"The Mounpoint for clients of the listener. "
"The gateway-level mountpoint configuration can be overloaded "
"when it is not null or empty string">>})}
%% FIXME:
, {authentication, string, <<"NOT-SUPPORTED-NOW">>}
].
, {authentication,
mk(emqx_authn_schema:authenticator_type(),
#{ nullable => {true, recursively}
, desc => <<"The authenticatior for this listener">>
})}
].
%%--------------------------------------------------------------------
%% examples
examples_listener_list() ->
[examples_listener()].
examples_listener() ->
#{id => true}.

View File

@ -53,6 +53,7 @@
%% Utils for http, swagger, etc.
-export([ return_http_error/2
, with_gateway/2
, with_authn/2
, checks/2
, schema_bad_request/0
, schema_not_found/0
@ -159,14 +160,31 @@ remove_listener(ListenerId) ->
-spec authn(gateway_name()) -> map().
authn(GwName) ->
%% XXX: Need append chain-nanme, authenticator-id?
Path = [gateway, GwName, authentication],
emqx_map_lib:jsonable_map(emqx:get_config(Path)).
ChainName = emqx_gateway_utils:global_chain(GwName),
wrap_chain_name(
ChainName,
emqx_map_lib:jsonable_map(emqx:get_config(Path))
).
-spec authn(gateway_name(), binary()) -> map().
authn(GwName, ListenerId) ->
{_, Type, Name} = emqx_gateway_utils:parse_listener_id(ListenerId),
Path = [gateway, GwName, listeners, Type, Name, authentication],
emqx_map_lib:jsonable_map(emqx:get_config(Path)).
ChainName = emqx_gateway_utils:listener_chain(GwName, Type, Name),
wrap_chain_name(
ChainName,
emqx_map_lib:jsonable_map(emqx:get_config(Path))
).
wrap_chain_name(ChainName, Conf) ->
case emqx_authentication:list_authenticators(ChainName) of
{ok, [#{id := Id} | _]} ->
Conf#{chain_name => ChainName, id => Id};
_ ->
Conf
end.
-spec add_authn(gateway_name(), map()) -> ok.
add_authn(GwName, AuthConf) ->
@ -303,6 +321,13 @@ codestr(401) -> 'NOT_SUPPORTED_NOW';
codestr(404) -> 'RESOURCE_NOT_FOUND';
codestr(500) -> 'UNKNOW_ERROR'.
-spec with_authn(binary(), function()) -> any().
with_authn(GwName0, Fun) ->
with_gateway(GwName0, fun(GwName) ->
Authn = emqx_gateway_http:authn(GwName),
Fun(GwName, Authn)
end).
-spec with_gateway(binary(), function()) -> any().
with_gateway(GwName0, Fun) ->
try

View File

@ -219,23 +219,6 @@ detailed_gateway_info(State) ->
%% Internal funcs
%%--------------------------------------------------------------------
%% same with emqx_authentication:global_chain/1
global_chain(mqtt) ->
'mqtt:global';
global_chain('mqtt-sn') ->
'mqtt-sn:global';
global_chain(coap) ->
'coap:global';
global_chain(lwm2m) ->
'lwm2m:global';
global_chain(stomp) ->
'stomp:global';
global_chain(_) ->
'unknown:global'.
listener_chain(GwName, Type, LisName) ->
emqx_gateway_utils:listener_id(GwName, Type, LisName).
%% There are two layer authentication configs
%% stomp.authn
%% / \
@ -266,10 +249,11 @@ do_init_authn([_BadConf|More], Names) ->
authns(GwName, Config) ->
Listeners = maps:to_list(maps:get(listeners, Config, #{})),
lists:append(
[ [{listener_chain(GwName, LisType, LisName), authn_conf(Opts)}
[ [{emqx_gateway_utils:listener_chain(GwName, LisType, LisName),
authn_conf(Opts)}
|| {LisName, Opts} <- maps:to_list(LisNames) ]
|| {LisType, LisNames} <- Listeners])
++ [{global_chain(GwName), authn_conf(Config)}].
++ [{emqx_gateway_utils:global_chain(GwName), authn_conf(Config)}].
authn_conf(Conf) ->
maps:get(authentication, Conf, #{enable => false}).

View File

@ -34,6 +34,8 @@
, listener_id/3
, parse_listener_id/1
, is_running/2
, global_chain/1
, listener_chain/3
]).
-export([ stringfy/1
@ -159,6 +161,23 @@ is_running(ListenerId, #{<<"bind">> := ListenOn0}) ->
false
end.
%% same with emqx_authentication:global_chain/1
global_chain(mqtt) ->
'mqtt:global';
global_chain('mqtt-sn') ->
'mqtt-sn:global';
global_chain(coap) ->
'coap:global';
global_chain(lwm2m) ->
'lwm2m:global';
global_chain(stomp) ->
'stomp:global';
global_chain(_) ->
'unknown:global'.
listener_chain(GwName, Type, LisName) ->
listener_id(GwName, Type, LisName).
bin(A) when is_atom(A) ->
atom_to_binary(A);
bin(L) when is_list(L); is_binary(L) ->

View File

@ -164,7 +164,7 @@ t_random_test(_) ->
random_test_body() ->
Data = generate_random_binary(),
case catch parse(Data) of
{ok, _Msg} -> ok;
Msg when is_record(Msg, mqtt_sn_message) -> ok;
{'EXIT', {Err, _Stack}}
when Err =:= unkown_message_type;
Err =:= malformed_message_len;