fix(authz): refine authz-http api with default headers
This commit is contained in:
parent
c67e565755
commit
341973880d
|
@ -0,0 +1,20 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2022 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.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
%% config root name all auth providers have to agree on.
|
||||||
|
-define(EMQX_AUTHORIZATION_CONFIG_ROOT_NAME, "authorization").
|
||||||
|
-define(EMQX_AUTHORIZATION_CONFIG_ROOT_NAME_ATOM, authorization).
|
||||||
|
-define(EMQX_AUTHORIZATION_CONFIG_ROOT_NAME_BINARY, <<"authorization">>).
|
|
@ -24,6 +24,7 @@
|
||||||
-elvis([{elvis_style, invalid_dynamic_call, disable}]).
|
-elvis([{elvis_style, invalid_dynamic_call, disable}]).
|
||||||
|
|
||||||
-include("emqx_authentication.hrl").
|
-include("emqx_authentication.hrl").
|
||||||
|
-include("emqx_access_control.hrl").
|
||||||
-include_lib("typerefl/include/types.hrl").
|
-include_lib("typerefl/include/types.hrl").
|
||||||
|
|
||||||
-type duration() :: integer().
|
-type duration() :: integer().
|
||||||
|
@ -159,9 +160,9 @@ roots(high) ->
|
||||||
)},
|
)},
|
||||||
%% NOTE: authorization schema here is only to keep emqx app prue
|
%% NOTE: authorization schema here is only to keep emqx app prue
|
||||||
%% the full schema for EMQX node is injected in emqx_conf_schema.
|
%% the full schema for EMQX node is injected in emqx_conf_schema.
|
||||||
{"authorization",
|
{?EMQX_AUTHORIZATION_CONFIG_ROOT_NAME,
|
||||||
sc(
|
sc(
|
||||||
ref("authorization"),
|
ref(?EMQX_AUTHORIZATION_CONFIG_ROOT_NAME),
|
||||||
#{}
|
#{}
|
||||||
)}
|
)}
|
||||||
];
|
];
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
%% limitations under the License.
|
%% limitations under the License.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-include_lib("emqx/include/emqx_access_control.hrl").
|
||||||
|
|
||||||
-define(APP, emqx_authz).
|
-define(APP, emqx_authz).
|
||||||
|
|
||||||
-define(ALLOW_DENY(A),
|
-define(ALLOW_DENY(A),
|
||||||
|
@ -45,6 +47,11 @@
|
||||||
|
|
||||||
-define(RE_PLACEHOLDER, "\\$\\{[a-z0-9_]+\\}").
|
-define(RE_PLACEHOLDER, "\\$\\{[a-z0-9_]+\\}").
|
||||||
|
|
||||||
|
%% has to be the same as the root field name defined in emqx_schema
|
||||||
|
-define(CONF_NS, ?EMQX_AUTHORIZATION_CONFIG_ROOT_NAME).
|
||||||
|
-define(CONF_NS_ATOM, ?EMQX_AUTHORIZATION_CONFIG_ROOT_NAME_ATOM).
|
||||||
|
-define(CONF_NS_BINARY, ?EMQX_AUTHORIZATION_CONFIG_ROOT_NAME_BINARY).
|
||||||
|
|
||||||
%% API examples
|
%% API examples
|
||||||
-define(USERNAME_RULES_EXAMPLE, #{
|
-define(USERNAME_RULES_EXAMPLE, #{
|
||||||
username => user1,
|
username => user1,
|
||||||
|
|
|
@ -16,36 +16,32 @@
|
||||||
|
|
||||||
-module(emqx_authz_api_schema).
|
-module(emqx_authz_api_schema).
|
||||||
|
|
||||||
|
-include("emqx_authz.hrl").
|
||||||
-include_lib("typerefl/include/types.hrl").
|
-include_lib("typerefl/include/types.hrl").
|
||||||
-include_lib("emqx_connector/include/emqx_connector.hrl").
|
-include_lib("emqx_connector/include/emqx_connector.hrl").
|
||||||
|
|
||||||
-import(hoconsc, [mk/2, enum/1]).
|
-import(hoconsc, [mk/2, enum/1]).
|
||||||
-import(emqx_schema, [mk_duration/2]).
|
-import(emqx_schema, [mk_duration/2]).
|
||||||
|
|
||||||
-export([fields/1, authz_sources_types/1]).
|
-export([
|
||||||
|
fields/1,
|
||||||
|
authz_sources_types/1
|
||||||
|
]).
|
||||||
|
|
||||||
fields(http) ->
|
%%------------------------------------------------------------------------------
|
||||||
authz_common_fields(http) ++
|
%% Hocon Schema
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
fields(http_get) ->
|
||||||
[
|
[
|
||||||
{url, fun url/1},
|
{method, #{type => get, default => get, required => true}},
|
||||||
{method, #{
|
{headers, fun headers_no_content_type/1}
|
||||||
type => enum([get, post]),
|
] ++ authz_http_common_fields();
|
||||||
default => get,
|
fields(http_post) ->
|
||||||
required => true
|
|
||||||
}},
|
|
||||||
{headers, fun headers/1},
|
|
||||||
{body, map([{fuzzy, term(), binary()}])},
|
|
||||||
{request_timeout, mk_duration("Request timeout", #{default => "30s"})}
|
|
||||||
] ++
|
|
||||||
maps:to_list(
|
|
||||||
maps:without(
|
|
||||||
[
|
[
|
||||||
base_url,
|
{method, #{type => post, default => post, required => true}},
|
||||||
pool_type
|
{headers, fun headers/1}
|
||||||
],
|
] ++ authz_http_common_fields();
|
||||||
maps:from_list(emqx_connector_http:fields(config))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
fields(built_in_database) ->
|
fields(built_in_database) ->
|
||||||
authz_common_fields(built_in_database);
|
authz_common_fields(built_in_database);
|
||||||
fields(mongo_single) ->
|
fields(mongo_single) ->
|
||||||
|
@ -101,6 +97,23 @@ fields(position) ->
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% http type funcs
|
%% http type funcs
|
||||||
|
|
||||||
|
authz_http_common_fields() ->
|
||||||
|
authz_common_fields(http) ++
|
||||||
|
[
|
||||||
|
{url, fun url/1},
|
||||||
|
{body, map([{fuzzy, term(), binary()}])},
|
||||||
|
{request_timeout, mk_duration("Request timeout", #{default => "30s"})}
|
||||||
|
] ++
|
||||||
|
maps:to_list(
|
||||||
|
maps:without(
|
||||||
|
[
|
||||||
|
base_url,
|
||||||
|
pool_type
|
||||||
|
],
|
||||||
|
maps:from_list(emqx_connector_http:fields(config))
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
url(type) -> binary();
|
url(type) -> binary();
|
||||||
url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")];
|
url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")];
|
||||||
url(required) -> true;
|
url(required) -> true;
|
||||||
|
@ -119,6 +132,19 @@ headers(default) ->
|
||||||
headers(_) ->
|
headers(_) ->
|
||||||
undefined.
|
undefined.
|
||||||
|
|
||||||
|
headers_no_content_type(type) ->
|
||||||
|
map();
|
||||||
|
headers_no_content_type(desc) ->
|
||||||
|
"List of HTTP headers.";
|
||||||
|
headers_no_content_type(converter) ->
|
||||||
|
fun(Headers) ->
|
||||||
|
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
|
%% headers
|
||||||
default_headers() ->
|
default_headers() ->
|
||||||
maps:put(
|
maps:put(
|
||||||
|
@ -208,9 +234,11 @@ enable(_) -> undefined.
|
||||||
authz_sources_types(Type) ->
|
authz_sources_types(Type) ->
|
||||||
case Type of
|
case Type of
|
||||||
simple ->
|
simple ->
|
||||||
[mongodb, redis];
|
[http, mongodb, redis];
|
||||||
detailed ->
|
detailed ->
|
||||||
[
|
[
|
||||||
|
http_get,
|
||||||
|
http_post,
|
||||||
mongo_single,
|
mongo_single,
|
||||||
mongo_rs,
|
mongo_rs,
|
||||||
mongo_sharded,
|
mongo_sharded,
|
||||||
|
@ -220,7 +248,6 @@ authz_sources_types(Type) ->
|
||||||
]
|
]
|
||||||
end ++
|
end ++
|
||||||
[
|
[
|
||||||
http,
|
|
||||||
built_in_database,
|
built_in_database,
|
||||||
mysql,
|
mysql,
|
||||||
postgresql,
|
postgresql,
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
-module(emqx_authz_schema).
|
-module(emqx_authz_schema).
|
||||||
|
|
||||||
|
-include("emqx_authz.hrl").
|
||||||
-include_lib("typerefl/include/types.hrl").
|
-include_lib("typerefl/include/types.hrl").
|
||||||
-include_lib("emqx_connector/include/emqx_connector.hrl").
|
-include_lib("emqx_connector/include/emqx_connector.hrl").
|
||||||
|
|
||||||
|
@ -40,9 +41,6 @@
|
||||||
headers/1
|
headers/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-import(emqx_schema, [mk_duration/2]).
|
|
||||||
-include_lib("hocon/include/hoconsc.hrl").
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Hocon Schema
|
%% Hocon Schema
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -197,7 +195,9 @@ http_common_fields() ->
|
||||||
[
|
[
|
||||||
{url, fun url/1},
|
{url, fun url/1},
|
||||||
{request_timeout,
|
{request_timeout,
|
||||||
mk_duration("Request timeout", #{default => "30s", desc => "Request timeout."})},
|
emqx_schema:mk_duration("Request timeout", #{
|
||||||
|
default => "30s", desc => "Request timeout."
|
||||||
|
})},
|
||||||
{body, #{type => map(), required => false, desc => "HTTP request body."}}
|
{body, #{type => map(), required => false, desc => "HTTP request body."}}
|
||||||
] ++
|
] ++
|
||||||
maps:to_list(
|
maps:to_list(
|
||||||
|
@ -232,8 +232,7 @@ mongo_common_fields() ->
|
||||||
|
|
||||||
validations() ->
|
validations() ->
|
||||||
[
|
[
|
||||||
{check_ssl_opts, fun check_ssl_opts/1},
|
{check_ssl_opts, fun check_ssl_opts/1}
|
||||||
{check_headers, fun check_headers/1}
|
|
||||||
].
|
].
|
||||||
|
|
||||||
headers(type) ->
|
headers(type) ->
|
||||||
|
@ -259,6 +258,13 @@ headers_no_content_type(converter) ->
|
||||||
end;
|
end;
|
||||||
headers_no_content_type(default) ->
|
headers_no_content_type(default) ->
|
||||||
default_headers_no_content_type();
|
default_headers_no_content_type();
|
||||||
|
headers_no_content_type(validator) ->
|
||||||
|
fun(Headers) ->
|
||||||
|
case lists:keyfind(<<"content-type">>, 1, Headers) of
|
||||||
|
false -> ok;
|
||||||
|
_ -> {error, do_not_include_content_type}
|
||||||
|
end
|
||||||
|
end;
|
||||||
headers_no_content_type(_) ->
|
headers_no_content_type(_) ->
|
||||||
undefined.
|
undefined.
|
||||||
|
|
||||||
|
@ -297,6 +303,7 @@ transform_header_name(Headers) ->
|
||||||
Headers
|
Headers
|
||||||
).
|
).
|
||||||
|
|
||||||
|
%% TODO: fix me, not work
|
||||||
check_ssl_opts(Conf) ->
|
check_ssl_opts(Conf) ->
|
||||||
case hocon_maps:get("config.url", Conf) of
|
case hocon_maps:get("config.url", Conf) of
|
||||||
undefined ->
|
undefined ->
|
||||||
|
@ -315,25 +322,6 @@ check_ssl_opts(Conf) ->
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
check_headers(Conf) ->
|
|
||||||
case hocon_maps:get("config.method", Conf) of
|
|
||||||
undefined ->
|
|
||||||
true;
|
|
||||||
Method0 ->
|
|
||||||
Method = to_bin(Method0),
|
|
||||||
Headers = hocon_maps:get("config.headers", Conf),
|
|
||||||
case Method of
|
|
||||||
<<"post">> ->
|
|
||||||
true;
|
|
||||||
_ when Headers =:= undefined -> true;
|
|
||||||
_ when is_list(Headers) ->
|
|
||||||
case lists:member(<<"content-type">>, Headers) of
|
|
||||||
false -> true;
|
|
||||||
true -> {Method0, do_not_include_content_type}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end.
|
|
||||||
|
|
||||||
union_array(Item) when is_list(Item) ->
|
union_array(Item) when is_list(Item) ->
|
||||||
hoconsc:array(hoconsc:union(Item)).
|
hoconsc:array(hoconsc:union(Item)).
|
||||||
|
|
||||||
|
@ -376,10 +364,3 @@ to_list(A) when is_atom(A) ->
|
||||||
atom_to_list(A);
|
atom_to_list(A);
|
||||||
to_list(B) when is_binary(B) ->
|
to_list(B) when is_binary(B) ->
|
||||||
binary_to_list(B).
|
binary_to_list(B).
|
||||||
|
|
||||||
to_bin(A) when is_atom(A) ->
|
|
||||||
atom_to_binary(A);
|
|
||||||
to_bin(B) when is_binary(B) ->
|
|
||||||
B;
|
|
||||||
to_bin(L) when is_list(L) ->
|
|
||||||
list_to_binary(L).
|
|
||||||
|
|
Loading…
Reference in New Issue