Merge pull request #11392 from lafirest/feat/ldap_authz
feat(ldap-authz): integrate the LDAP authorization
This commit is contained in:
commit
2b03436552
|
@ -19,7 +19,8 @@
|
|||
-export([
|
||||
hash/2,
|
||||
hash_data/2,
|
||||
check_pass/3
|
||||
check_pass/3,
|
||||
compare_secure/2
|
||||
]).
|
||||
|
||||
-export_type([
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_authn_enterprise).
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
%% -*- mode: erlang -*-
|
||||
{application, emqx_authz, [
|
||||
{description, "An OTP application"},
|
||||
{vsn, "0.1.24"},
|
||||
{vsn, "0.1.25"},
|
||||
{registered, []},
|
||||
{mod, {emqx_authz_app, []}},
|
||||
{applications, [
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
-behaviour(emqx_config_handler).
|
||||
-behaviour(emqx_config_backup).
|
||||
|
||||
-dialyzer({nowarn_function, [authz_module/1]}).
|
||||
|
||||
-include("emqx_authz.hrl").
|
||||
-include_lib("emqx/include/logger.hrl").
|
||||
-include_lib("emqx/include/emqx_hooks.hrl").
|
||||
|
@ -571,7 +573,12 @@ find_action_in_hooks() ->
|
|||
authz_module(built_in_database) ->
|
||||
emqx_authz_mnesia;
|
||||
authz_module(Type) ->
|
||||
list_to_existing_atom("emqx_authz_" ++ atom_to_list(Type)).
|
||||
case emqx_authz_enterprise:is_enterprise_module(Type) of
|
||||
{ok, Module} ->
|
||||
Module;
|
||||
_ ->
|
||||
list_to_existing_atom("emqx_authz_" ++ atom_to_list(Type))
|
||||
end.
|
||||
|
||||
type(#{type := Type}) -> type(Type);
|
||||
type(#{<<"type">> := Type}) -> type(Type);
|
||||
|
@ -591,8 +598,7 @@ type(built_in_database) -> built_in_database;
|
|||
type(<<"built_in_database">>) -> built_in_database;
|
||||
type(client_info) -> client_info;
|
||||
type(<<"client_info">>) -> client_info;
|
||||
%% should never happen if the input is type-checked by hocon schema
|
||||
type(Unknown) -> throw({unknown_authz_source_type, Unknown}).
|
||||
type(MaybeEnterprise) -> emqx_authz_enterprise:type(MaybeEnterprise).
|
||||
|
||||
maybe_write_files(#{<<"type">> := <<"file">>} = Source) ->
|
||||
write_acl_file(Source);
|
||||
|
|
|
@ -95,7 +95,9 @@ fields(position) ->
|
|||
in => body
|
||||
}
|
||||
)}
|
||||
].
|
||||
];
|
||||
fields(MaybeEnterprise) ->
|
||||
emqx_authz_enterprise:fields(MaybeEnterprise).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% http type funcs
|
||||
|
@ -283,7 +285,7 @@ authz_sources_types(Type) ->
|
|||
mysql,
|
||||
postgresql,
|
||||
file
|
||||
].
|
||||
] ++ emqx_authz_enterprise:authz_sources_types().
|
||||
|
||||
to_list(A) when is_atom(A) ->
|
||||
atom_to_list(A);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------
|
||||
-module(emqx_authz_enterprise).
|
||||
|
||||
-export([
|
||||
type_names/0,
|
||||
fields/1,
|
||||
is_enterprise_module/1,
|
||||
authz_sources_types/0,
|
||||
type/1,
|
||||
desc/1
|
||||
]).
|
||||
|
||||
-if(?EMQX_RELEASE_EDITION == ee).
|
||||
|
||||
%% type name set
|
||||
type_names() ->
|
||||
[ldap].
|
||||
|
||||
%% type -> type schema
|
||||
fields(ldap) ->
|
||||
emqx_ldap_authz:fields(config).
|
||||
|
||||
%% type -> type module
|
||||
is_enterprise_module(ldap) ->
|
||||
{ok, emqx_ldap_authz};
|
||||
is_enterprise_module(_) ->
|
||||
false.
|
||||
|
||||
%% api sources set
|
||||
authz_sources_types() ->
|
||||
[ldap].
|
||||
|
||||
%% atom-able name -> type
|
||||
type(<<"ldap">>) -> ldap;
|
||||
type(ldap) -> ldap;
|
||||
type(Unknown) -> throw({unknown_authz_source_type, Unknown}).
|
||||
|
||||
desc(ldap) ->
|
||||
emqx_ldap_authz:description();
|
||||
desc(_) ->
|
||||
undefined.
|
||||
|
||||
-else.
|
||||
|
||||
-dialyzer({nowarn_function, [fields/1, type/1, desc/1]}).
|
||||
|
||||
type_names() ->
|
||||
[].
|
||||
|
||||
fields(Any) ->
|
||||
error({invalid_field, Any}).
|
||||
|
||||
is_enterprise_module(_) ->
|
||||
false.
|
||||
|
||||
authz_sources_types() ->
|
||||
[].
|
||||
|
||||
%% should never happen if the input is type-checked by hocon schema
|
||||
type(Unknown) -> throw({unknown_authz_source_type, Unknown}).
|
||||
|
||||
desc(_) ->
|
||||
undefined.
|
||||
-endif.
|
|
@ -43,7 +43,8 @@
|
|||
-export([
|
||||
headers_no_content_type/1,
|
||||
headers/1,
|
||||
default_authz/0
|
||||
default_authz/0,
|
||||
authz_common_fields/1
|
||||
]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
|
@ -64,7 +65,8 @@ type_names() ->
|
|||
redis_single,
|
||||
redis_sentinel,
|
||||
redis_cluster
|
||||
].
|
||||
] ++
|
||||
emqx_authz_enterprise:type_names().
|
||||
|
||||
namespace() -> authz.
|
||||
|
||||
|
@ -176,7 +178,9 @@ fields("node_error") ->
|
|||
[
|
||||
node_name(),
|
||||
{"error", ?HOCON(string(), #{desc => ?DESC("node_error")})}
|
||||
].
|
||||
];
|
||||
fields(MaybeEnterprise) ->
|
||||
emqx_authz_enterprise:fields(MaybeEnterprise).
|
||||
|
||||
common_field() ->
|
||||
[
|
||||
|
@ -220,8 +224,8 @@ desc(redis_sentinel) ->
|
|||
?DESC(redis_sentinel);
|
||||
desc(redis_cluster) ->
|
||||
?DESC(redis_cluster);
|
||||
desc(_) ->
|
||||
undefined.
|
||||
desc(MaybeEnterprise) ->
|
||||
emqx_authz_enterprise:desc(MaybeEnterprise).
|
||||
|
||||
authz_common_fields(Type) ->
|
||||
[
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
{deps, [
|
||||
{emqx_connector, {path, "../../apps/emqx_connector"}},
|
||||
{emqx_resource, {path, "../../apps/emqx_resource"}},
|
||||
{emqx_authn, {path, "../../apps/emqx_authn"}}
|
||||
{emqx_authn, {path, "../../apps/emqx_authn"}},
|
||||
{emqx_authz, {path, "../../apps/emqx_authz"}}
|
||||
]}.
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
{applications, [
|
||||
kernel,
|
||||
stdlib,
|
||||
emqx_authn
|
||||
emqx_authn,
|
||||
emqx_authz
|
||||
]},
|
||||
{env, []},
|
||||
{modules, []},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_ldap_authn).
|
||||
|
@ -47,7 +47,7 @@ tags() ->
|
|||
|
||||
%% used for config check when the schema module is resolved
|
||||
roots() ->
|
||||
[{?CONF_NS, hoconsc:mk(hoconsc:ref(?MODULE, mysql))}].
|
||||
[{?CONF_NS, hoconsc:mk(hoconsc:ref(?MODULE, ldap))}].
|
||||
|
||||
fields(ldap) ->
|
||||
[
|
||||
|
@ -73,7 +73,7 @@ is_superuser_attribute(desc) -> ?DESC(?FUNCTION_NAME);
|
|||
is_superuser_attribute(default) -> <<"isSuperuser">>;
|
||||
is_superuser_attribute(_) -> undefined.
|
||||
|
||||
query_timeout(type) -> emqx_schema:duration_ms();
|
||||
query_timeout(type) -> emqx_schema:timeout_duration_ms();
|
||||
query_timeout(desc) -> ?DESC(?FUNCTION_NAME);
|
||||
query_timeout(default) -> <<"5s">>;
|
||||
query_timeout(_) -> undefined.
|
||||
|
@ -173,7 +173,7 @@ ensure_password(
|
|||
undefined ->
|
||||
{error, no_password};
|
||||
[LDAPPassword | _] ->
|
||||
extract_hash_algorithm(LDAPPassword, Password, fun try_decode_passowrd/4, Entry, State)
|
||||
extract_hash_algorithm(LDAPPassword, Password, fun try_decode_password/4, Entry, State)
|
||||
end.
|
||||
|
||||
%% RFC 2307 format password
|
||||
|
@ -207,7 +207,7 @@ is_valid_algorithm(HashType, PasswordHash, Password, Entry, State) ->
|
|||
end.
|
||||
|
||||
%% this password is in LDIF format which is base64 encoding
|
||||
try_decode_passowrd(LDAPPassword, Password, Entry, State) ->
|
||||
try_decode_password(LDAPPassword, Password, Entry, State) ->
|
||||
case safe_base64_decode(LDAPPassword) of
|
||||
{ok, Decode} ->
|
||||
extract_hash_algorithm(
|
||||
|
@ -279,9 +279,7 @@ hash_password(Algorithm, Salt, suffix, Password) ->
|
|||
hash_password(Algorithm, Data) ->
|
||||
crypto:hash(Algorithm, Data).
|
||||
|
||||
compare_password(hash, PasswordHash, PasswordHash) ->
|
||||
true;
|
||||
compare_password(hash, LDAPPasswordHash, PasswordHash) ->
|
||||
emqx_passwd:compare_secure(LDAPPasswordHash, PasswordHash);
|
||||
compare_password(base64, Base64HashData, PasswordHash) ->
|
||||
Base64HashData =:= base64:encode(PasswordHash);
|
||||
compare_password(_, _, _) ->
|
||||
false.
|
||||
emqx_passwd:compare_secure(Base64HashData, base64:encode(PasswordHash)).
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% 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_ldap_authz).
|
||||
|
||||
-include_lib("emqx_authz/include/emqx_authz.hrl").
|
||||
-include_lib("emqx/include/emqx.hrl").
|
||||
-include_lib("hocon/include/hoconsc.hrl").
|
||||
-include_lib("emqx/include/logger.hrl").
|
||||
-include_lib("emqx/include/emqx_placeholder.hrl").
|
||||
-include_lib("eldap/include/eldap.hrl").
|
||||
|
||||
-behaviour(emqx_authz).
|
||||
|
||||
-define(PREPARE_KEY, ?MODULE).
|
||||
|
||||
%% AuthZ Callbacks
|
||||
-export([
|
||||
description/0,
|
||||
create/1,
|
||||
update/1,
|
||||
destroy/1,
|
||||
authorize/4
|
||||
]).
|
||||
|
||||
-export([fields/1]).
|
||||
|
||||
-ifdef(TEST).
|
||||
-compile(export_all).
|
||||
-compile(nowarn_export_all).
|
||||
-endif.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Hocon Schema
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
fields(config) ->
|
||||
emqx_authz_schema:authz_common_fields(ldap) ++
|
||||
[
|
||||
{publish_attribute, attribute_meta(publish_attribute, <<"mqttPublishTopic">>)},
|
||||
{subscribe_attribute, attribute_meta(subscribe_attribute, <<"mqttSubscriptionTopic">>)},
|
||||
{all_attribute, attribute_meta(all_attribute, <<"mqttPubSubTopic">>)},
|
||||
{query_timeout,
|
||||
?HOCON(
|
||||
emqx_schema:timeout_duration_ms(),
|
||||
#{
|
||||
desc => ?DESC(query_timeout),
|
||||
default => <<"5s">>
|
||||
}
|
||||
)}
|
||||
] ++
|
||||
emqx_ldap:fields(config).
|
||||
|
||||
attribute_meta(Name, Default) ->
|
||||
?HOCON(
|
||||
string(),
|
||||
#{
|
||||
default => Default,
|
||||
desc => ?DESC(Name)
|
||||
}
|
||||
).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% AuthZ Callbacks
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
description() ->
|
||||
"AuthZ with LDAP".
|
||||
|
||||
create(Source) ->
|
||||
ResourceId = emqx_authz_utils:make_resource_id(?MODULE),
|
||||
{ok, _Data} = emqx_authz_utils:create_resource(ResourceId, emqx_ldap, Source),
|
||||
Annotations = new_annotations(#{id => ResourceId}, Source),
|
||||
Source#{annotations => Annotations}.
|
||||
|
||||
update(Source) ->
|
||||
case emqx_authz_utils:update_resource(emqx_ldap, Source) of
|
||||
{error, Reason} ->
|
||||
error({load_config_error, Reason});
|
||||
{ok, Id} ->
|
||||
Annotations = new_annotations(#{id => Id}, Source),
|
||||
Source#{annotations => Annotations}
|
||||
end.
|
||||
|
||||
destroy(#{annotations := #{id := Id}}) ->
|
||||
ok = emqx_resource:remove_local(Id).
|
||||
|
||||
authorize(
|
||||
Client,
|
||||
Action,
|
||||
Topic,
|
||||
#{
|
||||
query_timeout := QueryTimeout,
|
||||
annotations := #{id := ResourceID} = Annotations
|
||||
}
|
||||
) ->
|
||||
Attrs = select_attrs(Action, Annotations),
|
||||
case emqx_resource:simple_sync_query(ResourceID, {query, Client, Attrs, QueryTimeout}) of
|
||||
{ok, []} ->
|
||||
nomatch;
|
||||
{ok, [Entry | _]} ->
|
||||
do_authorize(Action, Topic, Attrs, Entry);
|
||||
{error, Reason} ->
|
||||
?SLOG(error, #{
|
||||
msg => "query_ldap_error",
|
||||
reason => Reason,
|
||||
resource_id => ResourceID
|
||||
}),
|
||||
nomatch
|
||||
end.
|
||||
|
||||
do_authorize(Action, Topic, [Attr | T], Entry) ->
|
||||
Topics = proplists:get_value(Attr, Entry#eldap_entry.attributes, []),
|
||||
case match_topic(Topic, Topics) of
|
||||
true ->
|
||||
{matched, allow};
|
||||
false ->
|
||||
do_authorize(Action, Topic, T, Entry)
|
||||
end;
|
||||
do_authorize(_Action, _Topic, [], _Entry) ->
|
||||
nomatch.
|
||||
|
||||
new_annotations(Init, Source) ->
|
||||
lists:foldl(
|
||||
fun(Attr, Acc) ->
|
||||
Acc#{
|
||||
Attr =>
|
||||
case maps:get(Attr, Source) of
|
||||
Value when is_binary(Value) ->
|
||||
erlang:binary_to_list(Value);
|
||||
Value ->
|
||||
Value
|
||||
end
|
||||
}
|
||||
end,
|
||||
Init,
|
||||
[publish_attribute, subscribe_attribute, all_attribute]
|
||||
).
|
||||
|
||||
select_attrs(#{action_type := publish}, #{publish_attribute := Pub, all_attribute := All}) ->
|
||||
[Pub, All];
|
||||
select_attrs(_, #{subscribe_attribute := Sub, all_attribute := All}) ->
|
||||
[Sub, All].
|
||||
|
||||
match_topic(Target, Topics) ->
|
||||
lists:any(
|
||||
fun(Topic) ->
|
||||
emqx_topic:match(Target, erlang:list_to_binary(Topic))
|
||||
end,
|
||||
Topics
|
||||
).
|
|
@ -27,5 +27,5 @@ dn : {token, {dn, TokenLine}}.
|
|||
Erlang code.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Header "%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------".
|
||||
|
||||
Nonterminals
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_ldap_SUITE).
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_ldap_authn_SUITE).
|
||||
|
||||
-compile(nowarn_export_all).
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------
|
||||
-module(emqx_ldap_authz_SUITE).
|
||||
|
||||
-compile(nowarn_export_all).
|
||||
-compile(export_all).
|
||||
|
||||
-include("emqx_authz.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-include_lib("common_test/include/ct.hrl").
|
||||
|
||||
-define(LDAP_HOST, "ldap").
|
||||
-define(LDAP_DEFAULT_PORT, 389).
|
||||
-define(LDAP_RESOURCE, <<"emqx_ldap_authz_SUITE">>).
|
||||
|
||||
all() ->
|
||||
emqx_authz_test_lib:all_with_table_case(?MODULE, t_run_case, cases()).
|
||||
|
||||
groups() ->
|
||||
emqx_authz_test_lib:table_groups(t_run_case, cases()).
|
||||
|
||||
init_per_suite(Config) ->
|
||||
ok = stop_apps([emqx_resource]),
|
||||
case emqx_common_test_helpers:is_tcp_server_available(?LDAP_HOST, ?LDAP_DEFAULT_PORT) of
|
||||
true ->
|
||||
ok = emqx_common_test_helpers:start_apps(
|
||||
[emqx_conf, emqx_authz],
|
||||
fun set_special_configs/1
|
||||
),
|
||||
ok = start_apps([emqx_resource]),
|
||||
ok = create_ldap_resource(),
|
||||
Config;
|
||||
false ->
|
||||
{skip, no_ldap}
|
||||
end.
|
||||
|
||||
end_per_suite(_Config) ->
|
||||
ok = emqx_authz_test_lib:restore_authorizers(),
|
||||
ok = emqx_resource:remove_local(?LDAP_RESOURCE),
|
||||
ok = stop_apps([emqx_resource]),
|
||||
ok = emqx_common_test_helpers:stop_apps([emqx_conf, emqx_authz]).
|
||||
|
||||
init_per_group(Group, Config) ->
|
||||
[{test_case, emqx_authz_test_lib:get_case(Group, cases())} | Config].
|
||||
end_per_group(_Group, _Config) ->
|
||||
ok.
|
||||
|
||||
init_per_testcase(_TestCase, Config) ->
|
||||
ok = emqx_authz_test_lib:reset_authorizers(),
|
||||
Config.
|
||||
end_per_testcase(_TestCase, _Config) ->
|
||||
_ = emqx_authz:set_feature_available(rich_actions, true),
|
||||
ok.
|
||||
|
||||
set_special_configs(emqx_authz) ->
|
||||
ok = emqx_authz_test_lib:reset_authorizers();
|
||||
set_special_configs(_) ->
|
||||
ok.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Testcases
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
t_run_case(Config) ->
|
||||
Case = ?config(test_case, Config),
|
||||
ok = setup_authz_source(),
|
||||
ok = emqx_authz_test_lib:run_checks(Case).
|
||||
|
||||
t_create_invalid(_Config) ->
|
||||
ok = setup_authz_source(),
|
||||
BadConfig = maps:merge(
|
||||
raw_ldap_authz_config(),
|
||||
#{<<"server">> => <<"255.255.255.255:33333">>}
|
||||
),
|
||||
{ok, _} = emqx_authz:update(?CMD_REPLACE, [BadConfig]),
|
||||
|
||||
[_] = emqx_authz:lookup().
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Case
|
||||
%%------------------------------------------------------------------------------
|
||||
cases() ->
|
||||
[
|
||||
#{
|
||||
name => simpe_publish,
|
||||
client_info => #{username => <<"mqttuser0001">>},
|
||||
checks => [
|
||||
{allow, ?AUTHZ_PUBLISH, <<"mqttuser0001/pub/1">>},
|
||||
{allow, ?AUTHZ_PUBLISH, <<"mqttuser0001/pub/+">>},
|
||||
{allow, ?AUTHZ_PUBLISH, <<"mqttuser0001/pub/#">>}
|
||||
]
|
||||
},
|
||||
#{
|
||||
name => simpe_subscribe,
|
||||
client_info => #{username => <<"mqttuser0001">>},
|
||||
checks => [
|
||||
{allow, ?AUTHZ_SUBSCRIBE, <<"mqttuser0001/sub/1">>},
|
||||
{allow, ?AUTHZ_SUBSCRIBE, <<"mqttuser0001/sub/+">>},
|
||||
{allow, ?AUTHZ_SUBSCRIBE, <<"mqttuser0001/sub/#">>}
|
||||
]
|
||||
},
|
||||
|
||||
#{
|
||||
name => simpe_pubsub,
|
||||
client_info => #{username => <<"mqttuser0001">>},
|
||||
checks => [
|
||||
{allow, ?AUTHZ_PUBLISH, <<"mqttuser0001/pubsub/1">>},
|
||||
{allow, ?AUTHZ_PUBLISH, <<"mqttuser0001/pubsub/+">>},
|
||||
{allow, ?AUTHZ_PUBLISH, <<"mqttuser0001/pubsub/#">>},
|
||||
|
||||
{allow, ?AUTHZ_SUBSCRIBE, <<"mqttuser0001/pubsub/1">>},
|
||||
{allow, ?AUTHZ_SUBSCRIBE, <<"mqttuser0001/pubsub/+">>},
|
||||
{allow, ?AUTHZ_SUBSCRIBE, <<"mqttuser0001/pubsub/#">>}
|
||||
]
|
||||
},
|
||||
|
||||
#{
|
||||
name => simpe_unmatched,
|
||||
client_info => #{username => <<"mqttuser0001">>},
|
||||
checks => [
|
||||
{deny, ?AUTHZ_PUBLISH, <<"mqttuser0001/req/mqttuser0001/+">>},
|
||||
{deny, ?AUTHZ_PUBLISH, <<"mqttuser0001/req/mqttuser0002/+">>},
|
||||
{deny, ?AUTHZ_SUBSCRIBE, <<"mqttuser0001/req/+/mqttuser0002">>}
|
||||
]
|
||||
}
|
||||
].
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Helpers
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
setup_authz_source() ->
|
||||
setup_config(#{}).
|
||||
|
||||
raw_ldap_authz_config() ->
|
||||
#{
|
||||
<<"enable">> => <<"true">>,
|
||||
<<"type">> => <<"ldap">>,
|
||||
<<"server">> => ldap_server(),
|
||||
<<"base_object">> => <<"uid=${username},ou=testdevice,dc=emqx,dc=io">>,
|
||||
<<"username">> => <<"cn=root,dc=emqx,dc=io">>,
|
||||
<<"password">> => <<"public">>,
|
||||
<<"pool_size">> => 8
|
||||
}.
|
||||
|
||||
setup_config(SpecialParams) ->
|
||||
emqx_authz_test_lib:setup_config(
|
||||
raw_ldap_authz_config(),
|
||||
SpecialParams
|
||||
).
|
||||
|
||||
ldap_server() ->
|
||||
iolist_to_binary(io_lib:format("~s:~B", [?LDAP_HOST, ?LDAP_DEFAULT_PORT])).
|
||||
|
||||
ldap_config() ->
|
||||
emqx_ldap_SUITE:ldap_config([]).
|
||||
|
||||
start_apps(Apps) ->
|
||||
lists:foreach(fun application:ensure_all_started/1, Apps).
|
||||
|
||||
stop_apps(Apps) ->
|
||||
lists:foreach(fun application:stop/1, Apps).
|
||||
|
||||
create_ldap_resource() ->
|
||||
{ok, _} = emqx_resource:create_local(
|
||||
?LDAP_RESOURCE,
|
||||
?RESOURCE_GROUP,
|
||||
emqx_ldap,
|
||||
ldap_config(),
|
||||
#{}
|
||||
),
|
||||
ok.
|
|
@ -1,5 +1,5 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_ldap_filter_SUITE).
|
||||
|
|
|
@ -1 +1 @@
|
|||
Integrated the LDAP as a new authenticator.
|
||||
Integrated LDAP as a new authenticator.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Integrated LDAP as a authorization source.
|
|
@ -10,7 +10,7 @@ password_attribute.label:
|
|||
"""Password Attribute"""
|
||||
|
||||
is_superuser_attribute.desc:
|
||||
"""Indicates which attribute is used to represent whether the user is a super user."""
|
||||
"""Indicates which attribute is used to represent whether the user is a superuser."""
|
||||
|
||||
is_superuser_attribute.label:
|
||||
"""IsSuperuser Attribute"""
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
emqx_ldap_authz {
|
||||
|
||||
publish_attribute.desc:
|
||||
"""Indicates which attribute is used to represent the allowed topics list of the `publish`."""
|
||||
|
||||
publish_attribute.label:
|
||||
"""Publish Attribute"""
|
||||
|
||||
subscribe_attribute.desc:
|
||||
"""Indicates which attribute is used to represent the allowed topics list of the `subscribe`."""
|
||||
|
||||
subscribe_attribute.label:
|
||||
"""Subscribe Attribute"""
|
||||
|
||||
all_attribute.desc:
|
||||
"""Indicates which attribute is used to represent the both allowed topics list of `publish` and `subscribe`."""
|
||||
|
||||
all_attribute.label:
|
||||
"""All Attribute"""
|
||||
|
||||
query_timeout.desc:
|
||||
"""Timeout for the LDAP query."""
|
||||
|
||||
query_timeout.label:
|
||||
"""Query Timeout"""
|
||||
|
||||
}
|
Loading…
Reference in New Issue