diff --git a/apps/emqx/include/emqx_access_control.hrl b/apps/emqx/include/emqx_access_control.hrl new file mode 100644 index 000000000..4d5ba8179 --- /dev/null +++ b/apps/emqx/include/emqx_access_control.hrl @@ -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">>). diff --git a/apps/emqx/src/emqx_schema.erl b/apps/emqx/src/emqx_schema.erl index 3595fd999..04f20cf0d 100644 --- a/apps/emqx/src/emqx_schema.erl +++ b/apps/emqx/src/emqx_schema.erl @@ -24,6 +24,7 @@ -elvis([{elvis_style, invalid_dynamic_call, disable}]). -include("emqx_authentication.hrl"). +-include("emqx_access_control.hrl"). -include_lib("typerefl/include/types.hrl"). -type duration() :: integer(). @@ -159,9 +160,9 @@ roots(high) -> )}, %% NOTE: authorization schema here is only to keep emqx app prue %% the full schema for EMQX node is injected in emqx_conf_schema. - {"authorization", + {?EMQX_AUTHORIZATION_CONFIG_ROOT_NAME, sc( - ref("authorization"), + ref(?EMQX_AUTHORIZATION_CONFIG_ROOT_NAME), #{} )} ]; diff --git a/apps/emqx_authz/include/emqx_authz.hrl b/apps/emqx_authz/include/emqx_authz.hrl index a3fe2d1f9..5c7602658 100644 --- a/apps/emqx_authz/include/emqx_authz.hrl +++ b/apps/emqx_authz/include/emqx_authz.hrl @@ -14,6 +14,8 @@ %% limitations under the License. %%-------------------------------------------------------------------- +-include_lib("emqx/include/emqx_access_control.hrl"). + -define(APP, emqx_authz). -define(ALLOW_DENY(A), @@ -45,6 +47,11 @@ -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 -define(USERNAME_RULES_EXAMPLE, #{ username => user1, diff --git a/apps/emqx_authz/src/emqx_authz_api_schema.erl b/apps/emqx_authz/src/emqx_authz_api_schema.erl index badf029b0..b4ea40ccc 100644 --- a/apps/emqx_authz/src/emqx_authz_api_schema.erl +++ b/apps/emqx_authz/src/emqx_authz_api_schema.erl @@ -16,36 +16,32 @@ -module(emqx_authz_api_schema). +-include("emqx_authz.hrl"). -include_lib("typerefl/include/types.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]). +-export([ + fields/1, + authz_sources_types/1 +]). -fields(http) -> - authz_common_fields(http) ++ - [ - {url, fun url/1}, - {method, #{ - type => enum([get, post]), - default => get, - 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, - pool_type - ], - maps:from_list(emqx_connector_http:fields(config)) - ) - ); +%%------------------------------------------------------------------------------ +%% Hocon Schema +%%------------------------------------------------------------------------------ + +fields(http_get) -> + [ + {method, #{type => get, default => get, required => true}}, + {headers, fun headers_no_content_type/1} + ] ++ authz_http_common_fields(); +fields(http_post) -> + [ + {method, #{type => post, default => post, required => true}}, + {headers, fun headers/1} + ] ++ authz_http_common_fields(); fields(built_in_database) -> authz_common_fields(built_in_database); fields(mongo_single) -> @@ -101,6 +97,23 @@ fields(position) -> %%------------------------------------------------------------------------------ %% 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(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")]; url(required) -> true; @@ -119,6 +132,19 @@ headers(default) -> headers(_) -> 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 default_headers() -> maps:put( @@ -208,9 +234,11 @@ enable(_) -> undefined. authz_sources_types(Type) -> case Type of simple -> - [mongodb, redis]; + [http, mongodb, redis]; detailed -> [ + http_get, + http_post, mongo_single, mongo_rs, mongo_sharded, @@ -220,7 +248,6 @@ authz_sources_types(Type) -> ] end ++ [ - http, built_in_database, mysql, postgresql, diff --git a/apps/emqx_authz/src/emqx_authz_schema.erl b/apps/emqx_authz/src/emqx_authz_schema.erl index 936a9c74f..011b1585d 100644 --- a/apps/emqx_authz/src/emqx_authz_schema.erl +++ b/apps/emqx_authz/src/emqx_authz_schema.erl @@ -16,6 +16,7 @@ -module(emqx_authz_schema). +-include("emqx_authz.hrl"). -include_lib("typerefl/include/types.hrl"). -include_lib("emqx_connector/include/emqx_connector.hrl"). @@ -40,9 +41,6 @@ headers/1 ]). --import(emqx_schema, [mk_duration/2]). --include_lib("hocon/include/hoconsc.hrl"). - %%-------------------------------------------------------------------- %% Hocon Schema %%-------------------------------------------------------------------- @@ -197,7 +195,9 @@ http_common_fields() -> [ {url, fun url/1}, {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."}} ] ++ maps:to_list( @@ -232,8 +232,7 @@ mongo_common_fields() -> validations() -> [ - {check_ssl_opts, fun check_ssl_opts/1}, - {check_headers, fun check_headers/1} + {check_ssl_opts, fun check_ssl_opts/1} ]. headers(type) -> @@ -259,6 +258,13 @@ headers_no_content_type(converter) -> end; headers_no_content_type(default) -> 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(_) -> undefined. @@ -297,6 +303,7 @@ transform_header_name(Headers) -> Headers ). +%% TODO: fix me, not work check_ssl_opts(Conf) -> case hocon_maps:get("config.url", Conf) of undefined -> @@ -315,25 +322,6 @@ check_ssl_opts(Conf) -> 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) -> hoconsc:array(hoconsc:union(Item)). @@ -376,10 +364,3 @@ to_list(A) when is_atom(A) -> atom_to_list(A); to_list(B) when is_binary(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).