|
@@ -78,6 +78,25 @@
|
|
|
-define(VER_1, <<"1">>).
|
|
-define(VER_1, <<"1">>).
|
|
|
-define(VER_2, <<"2">>).
|
|
-define(VER_2, <<"2">>).
|
|
|
|
|
|
|
|
|
|
+-type chain_name() :: atom().
|
|
|
|
|
+-type authenticator_id() :: binary().
|
|
|
|
|
+-type position() :: top | bottom | {before, authenticator_id()}.
|
|
|
|
|
+-type update_request() :: {create_authenticator, chain_name(), map()}
|
|
|
|
|
+ | {delete_authenticator, chain_name(), authenticator_id()}
|
|
|
|
|
+ | {update_authenticator, chain_name(), authenticator_id(), map()}
|
|
|
|
|
+ | {move_authenticator, chain_name(), authenticator_id(), position()}.
|
|
|
|
|
+-type authn_type() :: atom() | {atom(), atom()}.
|
|
|
|
|
+-type provider() :: module().
|
|
|
|
|
+
|
|
|
|
|
+-type chain() :: #{name := chain_name(),
|
|
|
|
|
+ authenticators := [authenticator()]}.
|
|
|
|
|
+
|
|
|
|
|
+-type authenticator() :: #{id := authenticator_id(),
|
|
|
|
|
+ provider := provider(),
|
|
|
|
|
+ enable := boolean(),
|
|
|
|
|
+ state := map()}.
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
-type config() :: #{atom() => term()}.
|
|
-type config() :: #{atom() => term()}.
|
|
|
-type state() :: #{atom() => term()}.
|
|
-type state() :: #{atom() => term()}.
|
|
|
-type extra() :: #{is_superuser := boolean(),
|
|
-type extra() :: #{is_superuser := boolean(),
|
|
@@ -128,7 +147,12 @@
|
|
|
-callback update_user(UserID, UserInfo, State)
|
|
-callback update_user(UserID, UserInfo, State)
|
|
|
-> {ok, User}
|
|
-> {ok, User}
|
|
|
| {error, term()}
|
|
| {error, term()}
|
|
|
- when UserID::binary, UserInfo::map(), State::state(), User::user_info().
|
|
|
|
|
|
|
+ when UserID::binary(), UserInfo::map(), State::state(), User::user_info().
|
|
|
|
|
+
|
|
|
|
|
+-callback lookup_user(UserID, UserInfo, State)
|
|
|
|
|
+ -> {ok, User}
|
|
|
|
|
+ | {error, term()}
|
|
|
|
|
+ when UserID::binary(), UserInfo::map(), State::state(), User::user_info().
|
|
|
|
|
|
|
|
-callback list_users(State)
|
|
-callback list_users(State)
|
|
|
-> {ok, Users}
|
|
-> {ok, Users}
|
|
@@ -138,6 +162,7 @@
|
|
|
, add_user/2
|
|
, add_user/2
|
|
|
, delete_user/2
|
|
, delete_user/2
|
|
|
, update_user/3
|
|
, update_user/3
|
|
|
|
|
+ , lookup_user/3
|
|
|
, list_users/1
|
|
, list_users/1
|
|
|
]).
|
|
]).
|
|
|
|
|
|
|
@@ -159,6 +184,8 @@ authentication(_) -> undefined.
|
|
|
%% Callbacks of config handler
|
|
%% Callbacks of config handler
|
|
|
%%------------------------------------------------------------------------------
|
|
%%------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
+-spec pre_config_update(update_request(), emqx_config:raw_config())
|
|
|
|
|
+ -> {ok, map() | list()} | {error, term()}.
|
|
|
pre_config_update(UpdateReq, OldConfig) ->
|
|
pre_config_update(UpdateReq, OldConfig) ->
|
|
|
case do_pre_config_update(UpdateReq, to_list(OldConfig)) of
|
|
case do_pre_config_update(UpdateReq, to_list(OldConfig)) of
|
|
|
{error, Reason} -> {error, Reason};
|
|
{error, Reason} -> {error, Reason};
|
|
@@ -185,22 +212,22 @@ do_pre_config_update({move_authenticator, _ChainName, AuthenticatorID, Position}
|
|
|
{error, Reason} -> {error, Reason};
|
|
{error, Reason} -> {error, Reason};
|
|
|
{ok, Part1, [Found | Part2]} ->
|
|
{ok, Part1, [Found | Part2]} ->
|
|
|
case Position of
|
|
case Position of
|
|
|
- <<"top">> ->
|
|
|
|
|
|
|
+ top ->
|
|
|
{ok, [Found | Part1] ++ Part2};
|
|
{ok, [Found | Part1] ++ Part2};
|
|
|
- <<"bottom">> ->
|
|
|
|
|
|
|
+ bottom ->
|
|
|
{ok, Part1 ++ Part2 ++ [Found]};
|
|
{ok, Part1 ++ Part2 ++ [Found]};
|
|
|
- <<"before:", Before/binary>> ->
|
|
|
|
|
|
|
+ {before, Before} ->
|
|
|
case split_by_id(Before, Part1 ++ Part2) of
|
|
case split_by_id(Before, Part1 ++ Part2) of
|
|
|
{error, Reason} ->
|
|
{error, Reason} ->
|
|
|
{error, Reason};
|
|
{error, Reason};
|
|
|
{ok, NPart1, [NFound | NPart2]} ->
|
|
{ok, NPart1, [NFound | NPart2]} ->
|
|
|
{ok, NPart1 ++ [Found, NFound | NPart2]}
|
|
{ok, NPart1 ++ [Found, NFound | NPart2]}
|
|
|
- end;
|
|
|
|
|
- _ ->
|
|
|
|
|
- {error, {invalid_parameter, position}}
|
|
|
|
|
|
|
+ end
|
|
|
end
|
|
end
|
|
|
end.
|
|
end.
|
|
|
|
|
|
|
|
|
|
+-spec post_config_update(update_request(), map() | list(), emqx_config:raw_config(), emqx_config:app_envs())
|
|
|
|
|
+ -> ok | {ok, map()} | {error, term()}.
|
|
|
post_config_update(UpdateReq, NewConfig, OldConfig, AppEnvs) ->
|
|
post_config_update(UpdateReq, NewConfig, OldConfig, AppEnvs) ->
|
|
|
do_post_config_update(UpdateReq, check_config(to_list(NewConfig)), OldConfig, AppEnvs).
|
|
do_post_config_update(UpdateReq, check_config(to_list(NewConfig)), OldConfig, AppEnvs).
|
|
|
|
|
|
|
@@ -220,13 +247,7 @@ do_post_config_update({update_authenticator, ChainName, AuthenticatorID, _Config
|
|
|
update_authenticator(ChainName, AuthenticatorID, NConfig);
|
|
update_authenticator(ChainName, AuthenticatorID, NConfig);
|
|
|
|
|
|
|
|
do_post_config_update({move_authenticator, ChainName, AuthenticatorID, Position}, _NewConfig, _OldConfig, _AppEnvs) ->
|
|
do_post_config_update({move_authenticator, ChainName, AuthenticatorID, Position}, _NewConfig, _OldConfig, _AppEnvs) ->
|
|
|
- NPosition = case Position of
|
|
|
|
|
- <<"top">> -> top;
|
|
|
|
|
- <<"bottom">> -> bottom;
|
|
|
|
|
- <<"before:", Before/binary>> ->
|
|
|
|
|
- {before, Before}
|
|
|
|
|
- end,
|
|
|
|
|
- move_authenticator(ChainName, AuthenticatorID, NPosition).
|
|
|
|
|
|
|
+ move_authenticator(ChainName, AuthenticatorID, Position).
|
|
|
|
|
|
|
|
check_config(Config) ->
|
|
check_config(Config) ->
|
|
|
#{authentication := CheckedConfig} = hocon_schema:check_plain(emqx_authentication,
|
|
#{authentication := CheckedConfig} = hocon_schema:check_plain(emqx_authentication,
|
|
@@ -269,6 +290,7 @@ do_authenticate([#authenticator{provider = Provider, state = State} | More], Cre
|
|
|
%% APIs
|
|
%% APIs
|
|
|
%%------------------------------------------------------------------------------
|
|
%%------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
+-spec initialize_authentication(chain_name(), [#{binary() => term()}]) -> ok.
|
|
|
initialize_authentication(_, []) ->
|
|
initialize_authentication(_, []) ->
|
|
|
ok;
|
|
ok;
|
|
|
initialize_authentication(ChainName, AuthenticatorsConfig) ->
|
|
initialize_authentication(ChainName, AuthenticatorsConfig) ->
|
|
@@ -283,43 +305,56 @@ initialize_authentication(ChainName, AuthenticatorsConfig) ->
|
|
|
end
|
|
end
|
|
|
end, CheckedConfig).
|
|
end, CheckedConfig).
|
|
|
|
|
|
|
|
|
|
+-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
|
|
|
start_link() ->
|
|
start_link() ->
|
|
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
|
|
|
|
|
|
|
|
|
+-spec stop() -> ok.
|
|
|
stop() ->
|
|
stop() ->
|
|
|
gen_server:stop(?MODULE).
|
|
gen_server:stop(?MODULE).
|
|
|
|
|
|
|
|
|
|
+-spec get_refs() -> {ok, Refs} when Refs :: [{authn_type(), module()}].
|
|
|
get_refs() ->
|
|
get_refs() ->
|
|
|
gen_server:call(?MODULE, get_refs).
|
|
gen_server:call(?MODULE, get_refs).
|
|
|
|
|
|
|
|
|
|
+-spec add_provider(authn_type(), module()) -> ok.
|
|
|
add_provider(AuthNType, Provider) ->
|
|
add_provider(AuthNType, Provider) ->
|
|
|
gen_server:call(?MODULE, {add_provider, AuthNType, Provider}).
|
|
gen_server:call(?MODULE, {add_provider, AuthNType, Provider}).
|
|
|
|
|
|
|
|
|
|
+-spec remove_provider(authn_type()) -> ok.
|
|
|
remove_provider(AuthNType) ->
|
|
remove_provider(AuthNType) ->
|
|
|
gen_server:call(?MODULE, {remove_provider, AuthNType}).
|
|
gen_server:call(?MODULE, {remove_provider, AuthNType}).
|
|
|
|
|
|
|
|
|
|
+-spec create_chain(chain_name()) -> {ok, chain()} | {error, term()}.
|
|
|
create_chain(Name) ->
|
|
create_chain(Name) ->
|
|
|
gen_server:call(?MODULE, {create_chain, Name}).
|
|
gen_server:call(?MODULE, {create_chain, Name}).
|
|
|
|
|
|
|
|
|
|
+-spec delete_chain(chain_name()) -> ok | {error, term()}.
|
|
|
delete_chain(Name) ->
|
|
delete_chain(Name) ->
|
|
|
gen_server:call(?MODULE, {delete_chain, Name}).
|
|
gen_server:call(?MODULE, {delete_chain, Name}).
|
|
|
|
|
|
|
|
|
|
+-spec lookup_chain(chain_name()) -> {ok, chain()} | {error, term()}.
|
|
|
lookup_chain(Name) ->
|
|
lookup_chain(Name) ->
|
|
|
gen_server:call(?MODULE, {lookup_chain, Name}).
|
|
gen_server:call(?MODULE, {lookup_chain, Name}).
|
|
|
|
|
|
|
|
|
|
+-spec list_chains() -> {ok, [chain()]}.
|
|
|
list_chains() ->
|
|
list_chains() ->
|
|
|
Chains = ets:tab2list(?CHAINS_TAB),
|
|
Chains = ets:tab2list(?CHAINS_TAB),
|
|
|
{ok, [serialize_chain(Chain) || Chain <- Chains]}.
|
|
{ok, [serialize_chain(Chain) || Chain <- Chains]}.
|
|
|
|
|
|
|
|
|
|
+-spec create_authenticator(chain_name(), config()) -> {ok, authenticator()} | {error, term()}.
|
|
|
create_authenticator(ChainName, Config) ->
|
|
create_authenticator(ChainName, Config) ->
|
|
|
gen_server:call(?MODULE, {create_authenticator, ChainName, Config}).
|
|
gen_server:call(?MODULE, {create_authenticator, ChainName, Config}).
|
|
|
|
|
|
|
|
|
|
+-spec delete_authenticator(chain_name(), authenticator_id()) -> ok | {error, term()}.
|
|
|
delete_authenticator(ChainName, AuthenticatorID) ->
|
|
delete_authenticator(ChainName, AuthenticatorID) ->
|
|
|
gen_server:call(?MODULE, {delete_authenticator, ChainName, AuthenticatorID}).
|
|
gen_server:call(?MODULE, {delete_authenticator, ChainName, AuthenticatorID}).
|
|
|
|
|
|
|
|
|
|
+-spec update_authenticator(chain_name(), authenticator_id(), config()) -> {ok, authenticator()} | {error, term()}.
|
|
|
update_authenticator(ChainName, AuthenticatorID, Config) ->
|
|
update_authenticator(ChainName, AuthenticatorID, Config) ->
|
|
|
gen_server:call(?MODULE, {update_authenticator, ChainName, AuthenticatorID, Config}).
|
|
gen_server:call(?MODULE, {update_authenticator, ChainName, AuthenticatorID, Config}).
|
|
|
|
|
|
|
|
|
|
+-spec lookup_authenticator(chain_name(), authenticator_id()) -> {ok, authenticator()} | {error, term()}.
|
|
|
lookup_authenticator(ChainName, AuthenticatorID) ->
|
|
lookup_authenticator(ChainName, AuthenticatorID) ->
|
|
|
case ets:lookup(?CHAINS_TAB, ChainName) of
|
|
case ets:lookup(?CHAINS_TAB, ChainName) of
|
|
|
[] ->
|
|
[] ->
|
|
@@ -333,6 +368,7 @@ lookup_authenticator(ChainName, AuthenticatorID) ->
|
|
|
end
|
|
end
|
|
|
end.
|
|
end.
|
|
|
|
|
|
|
|
|
|
+-spec list_authenticators(chain_name()) -> {ok, [authenticator()]} | {error, term()}.
|
|
|
list_authenticators(ChainName) ->
|
|
list_authenticators(ChainName) ->
|
|
|
case ets:lookup(?CHAINS_TAB, ChainName) of
|
|
case ets:lookup(?CHAINS_TAB, ChainName) of
|
|
|
[] ->
|
|
[] ->
|
|
@@ -341,28 +377,36 @@ list_authenticators(ChainName) ->
|
|
|
{ok, serialize_authenticators(Authenticators)}
|
|
{ok, serialize_authenticators(Authenticators)}
|
|
|
end.
|
|
end.
|
|
|
|
|
|
|
|
|
|
+-spec move_authenticator(chain_name(), authenticator_id(), position()) -> ok | {error, term()}.
|
|
|
move_authenticator(ChainName, AuthenticatorID, Position) ->
|
|
move_authenticator(ChainName, AuthenticatorID, Position) ->
|
|
|
gen_server:call(?MODULE, {move_authenticator, ChainName, AuthenticatorID, Position}).
|
|
gen_server:call(?MODULE, {move_authenticator, ChainName, AuthenticatorID, Position}).
|
|
|
|
|
|
|
|
|
|
+-spec import_users(chain_name(), authenticator_id(), binary()) -> ok | {error, term()}.
|
|
|
import_users(ChainName, AuthenticatorID, Filename) ->
|
|
import_users(ChainName, AuthenticatorID, Filename) ->
|
|
|
gen_server:call(?MODULE, {import_users, ChainName, AuthenticatorID, Filename}).
|
|
gen_server:call(?MODULE, {import_users, ChainName, AuthenticatorID, Filename}).
|
|
|
|
|
|
|
|
|
|
+-spec add_user(chain_name(), authenticator_id(), user_info()) -> {ok, user_info()} | {error, term()}.
|
|
|
add_user(ChainName, AuthenticatorID, UserInfo) ->
|
|
add_user(ChainName, AuthenticatorID, UserInfo) ->
|
|
|
gen_server:call(?MODULE, {add_user, ChainName, AuthenticatorID, UserInfo}).
|
|
gen_server:call(?MODULE, {add_user, ChainName, AuthenticatorID, UserInfo}).
|
|
|
|
|
|
|
|
|
|
+-spec delete_user(chain_name(), authenticator_id(), binary()) -> ok | {error, term()}.
|
|
|
delete_user(ChainName, AuthenticatorID, UserID) ->
|
|
delete_user(ChainName, AuthenticatorID, UserID) ->
|
|
|
gen_server:call(?MODULE, {delete_user, ChainName, AuthenticatorID, UserID}).
|
|
gen_server:call(?MODULE, {delete_user, ChainName, AuthenticatorID, UserID}).
|
|
|
|
|
|
|
|
|
|
+-spec update_user(chain_name(), authenticator_id(), binary(), map()) -> {ok, user_info()} | {error, term()}.
|
|
|
update_user(ChainName, AuthenticatorID, UserID, NewUserInfo) ->
|
|
update_user(ChainName, AuthenticatorID, UserID, NewUserInfo) ->
|
|
|
gen_server:call(?MODULE, {update_user, ChainName, AuthenticatorID, UserID, NewUserInfo}).
|
|
gen_server:call(?MODULE, {update_user, ChainName, AuthenticatorID, UserID, NewUserInfo}).
|
|
|
|
|
|
|
|
|
|
+-spec lookup_user(chain_name(), authenticator_id(), binary()) -> {ok, user_info()} | {error, term()}.
|
|
|
lookup_user(ChainName, AuthenticatorID, UserID) ->
|
|
lookup_user(ChainName, AuthenticatorID, UserID) ->
|
|
|
gen_server:call(?MODULE, {lookup_user, ChainName, AuthenticatorID, UserID}).
|
|
gen_server:call(?MODULE, {lookup_user, ChainName, AuthenticatorID, UserID}).
|
|
|
|
|
|
|
|
%% TODO: Support pagination
|
|
%% TODO: Support pagination
|
|
|
|
|
+-spec list_users(chain_name(), authenticator_id()) -> {ok, [user_info()]} | {error, term()}.
|
|
|
list_users(ChainName, AuthenticatorID) ->
|
|
list_users(ChainName, AuthenticatorID) ->
|
|
|
gen_server:call(?MODULE, {list_users, ChainName, AuthenticatorID}).
|
|
gen_server:call(?MODULE, {list_users, ChainName, AuthenticatorID}).
|
|
|
|
|
|
|
|
|
|
+-spec generate_id(config()) -> authenticator_id().
|
|
|
generate_id(#{mechanism := Mechanism0, backend := Backend0}) ->
|
|
generate_id(#{mechanism := Mechanism0, backend := Backend0}) ->
|
|
|
Mechanism = atom_to_binary(Mechanism0),
|
|
Mechanism = atom_to_binary(Mechanism0),
|
|
|
Backend = atom_to_binary(Backend0),
|
|
Backend = atom_to_binary(Backend0),
|
|
@@ -484,7 +528,7 @@ handle_call({update_authenticator, ChainName, AuthenticatorID, Config}, _From, S
|
|
|
{error, Reason}
|
|
{error, Reason}
|
|
|
end;
|
|
end;
|
|
|
false ->
|
|
false ->
|
|
|
- {error, mechanism_or_backend_change_is_not_alloed}
|
|
|
|
|
|
|
+ {error, change_of_authentication_type_is_not_allowed}
|
|
|
end
|
|
end
|
|
|
end
|
|
end
|
|
|
end,
|
|
end,
|
|
@@ -679,7 +723,7 @@ call_authenticator(ChainName, AuthenticatorID, Func, Args) ->
|
|
|
true ->
|
|
true ->
|
|
|
erlang:apply(Provider, Func, Args ++ [State]);
|
|
erlang:apply(Provider, Func, Args ++ [State]);
|
|
|
false ->
|
|
false ->
|
|
|
- {error, unsupported_feature}
|
|
|
|
|
|
|
+ {error, unsupported_operation}
|
|
|
end
|
|
end
|
|
|
end
|
|
end
|
|
|
end,
|
|
end,
|