feat(authentication): add new apis
This commit is contained in:
parent
c323113068
commit
54106790c7
|
@ -1,5 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
%%
|
||||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
%% you may not use this file except in compliance with the License.
|
%% you may not use this file except in compliance with the License.
|
||||||
|
@ -29,13 +29,15 @@
|
||||||
-export([ create_chain/1
|
-export([ create_chain/1
|
||||||
, delete_chain/1
|
, delete_chain/1
|
||||||
, lookup_chain/1
|
, lookup_chain/1
|
||||||
, add_services_to_chain/2
|
, list_chains/0
|
||||||
, delete_services_from_chain/2
|
, add_services/2
|
||||||
|
, delete_services/2
|
||||||
|
, update_service/3
|
||||||
, lookup_service/2
|
, lookup_service/2
|
||||||
, list_services/1
|
, list_services/1
|
||||||
, move_service_to_the_front_of_chain/2
|
, move_service_to_the_front/2
|
||||||
, move_service_to_the_end_of_chain/2
|
, move_service_to_the_end/2
|
||||||
, move_service_to_the_nth_of_chain/3
|
, move_service_to_the_nth/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ import_user_credentials/4
|
-export([ import_user_credentials/4
|
||||||
|
@ -135,7 +137,7 @@ register_service_types([{_App, Mod, #{name := Name,
|
||||||
register_service_types(Types, [ServiceType | Acc]).
|
register_service_types(Types, [ServiceType | Acc]).
|
||||||
|
|
||||||
create_chain(Params = #{chain_id := ChainID}) ->
|
create_chain(Params = #{chain_id := ChainID}) ->
|
||||||
ServiceParams = maps:get(service_params, Params, []),
|
ServiceParams = maps:get(services, Params, []),
|
||||||
case validate_service_params(ServiceParams) of
|
case validate_service_params(ServiceParams) of
|
||||||
{ok, NServiceParams} ->
|
{ok, NServiceParams} ->
|
||||||
trans(
|
trans(
|
||||||
|
@ -167,7 +169,7 @@ delete_chain(ChainID) ->
|
||||||
[] ->
|
[] ->
|
||||||
{error, {not_found, {chain, ChainID}}};
|
{error, {not_found, {chain, ChainID}}};
|
||||||
[#chain{services = Services}] ->
|
[#chain{services = Services}] ->
|
||||||
ok = delete_services(Services),
|
ok = delete_services_(Services),
|
||||||
mnesia:delete(?CHAIN_TAB, ChainID, write)
|
mnesia:delete(?CHAIN_TAB, ChainID, write)
|
||||||
end
|
end
|
||||||
end).
|
end).
|
||||||
|
@ -180,7 +182,11 @@ lookup_chain(ChainID) ->
|
||||||
{ok, serialize_chain(Chain)}
|
{ok, serialize_chain(Chain)}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
add_services_to_chain(ChainID, ServiceParams) ->
|
list_chains() ->
|
||||||
|
Chains = ets:tab2list(?CHAIN_TAB),
|
||||||
|
[serialize_chain(Chain) || Chain <- Chains].
|
||||||
|
|
||||||
|
add_services(ChainID, ServiceParams) ->
|
||||||
case validate_service_params(ServiceParams) of
|
case validate_service_params(ServiceParams) of
|
||||||
{ok, NServiceParams} ->
|
{ok, NServiceParams} ->
|
||||||
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
||||||
|
@ -203,13 +209,13 @@ add_services_to_chain(ChainID, ServiceParams) ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
delete_services_from_chain(ChainID, ServiceNames) ->
|
delete_services(ChainID, ServiceNames) ->
|
||||||
case no_duplicate_names(ServiceNames) of
|
case no_duplicate_names(ServiceNames) of
|
||||||
ok ->
|
ok ->
|
||||||
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
||||||
case extract_services(ServiceNames, Services) of
|
case extract_services(ServiceNames, Services) of
|
||||||
{ok, Extracted, Rest} ->
|
{ok, Extracted, Rest} ->
|
||||||
ok = delete_services(Extracted),
|
ok = delete_services_(Extracted),
|
||||||
NChain = Chain#chain{services = Rest},
|
NChain = Chain#chain{services = Rest},
|
||||||
mnesia:write(?CHAIN_TAB, NChain, write);
|
mnesia:write(?CHAIN_TAB, NChain, write);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
@ -221,6 +227,31 @@ delete_services_from_chain(ChainID, ServiceNames) ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
update_service(ChainID, ServiceName, NewParams) ->
|
||||||
|
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
||||||
|
case proplists:get_value(ServiceName, Services, undefined) of
|
||||||
|
undefined ->
|
||||||
|
{error, {not_found, {service, ServiceName}}};
|
||||||
|
#service{type = Type,
|
||||||
|
provider = Provider,
|
||||||
|
params = OriginalParams,
|
||||||
|
state = State} = Service ->
|
||||||
|
Params = maps:merge(OriginalParams, NewParams),
|
||||||
|
{ok, #service_type{params_spec = ParamsSpec}} = find_service_type(Type),
|
||||||
|
NParams = emqx_rule_validator:validate_params(Params, ParamsSpec),
|
||||||
|
case Provider:update(ChainID, ServiceName, NParams, State) of
|
||||||
|
{ok, NState} ->
|
||||||
|
NService = Service#service{params = Params,
|
||||||
|
state = NState},
|
||||||
|
NServices = lists:keyreplace(ServiceName, 1, Services, [{ServiceName, NService}]),
|
||||||
|
mnesia:write(?CHAIN_TAB, Chain#chain{services = NServices}, write);
|
||||||
|
{error, Reason} ->
|
||||||
|
{error, Reason}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
update_chain(ChainID, UpdateFun).
|
||||||
|
|
||||||
lookup_service(ChainID, ServiceName) ->
|
lookup_service(ChainID, ServiceName) ->
|
||||||
case mnesia:dirty_read(?CHAIN_TAB, ChainID) of
|
case mnesia:dirty_read(?CHAIN_TAB, ChainID) of
|
||||||
[] ->
|
[] ->
|
||||||
|
@ -242,9 +273,9 @@ list_services(ChainID) ->
|
||||||
{ok, [serialize_service(Service) || Service <- Services]}
|
{ok, [serialize_service(Service) || Service <- Services]}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
move_service_to_the_front_of_chain(ChainID, ServiceName) ->
|
move_service_to_the_front(ChainID, ServiceName) ->
|
||||||
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
||||||
case move_service_to_the_front(ServiceName, Services) of
|
case move_service_to_the_front_(ServiceName, Services) of
|
||||||
{ok, NServices} ->
|
{ok, NServices} ->
|
||||||
NChain = Chain#chain{services = NServices},
|
NChain = Chain#chain{services = NServices},
|
||||||
mnesia:write(?CHAIN_TAB, NChain, write);
|
mnesia:write(?CHAIN_TAB, NChain, write);
|
||||||
|
@ -254,9 +285,9 @@ move_service_to_the_front_of_chain(ChainID, ServiceName) ->
|
||||||
end,
|
end,
|
||||||
update_chain(ChainID, UpdateFun).
|
update_chain(ChainID, UpdateFun).
|
||||||
|
|
||||||
move_service_to_the_end_of_chain(ChainID, ServiceName) ->
|
move_service_to_the_end(ChainID, ServiceName) ->
|
||||||
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
||||||
case move_service_to_the_end(ServiceName, Services) of
|
case move_service_to_the_end_(ServiceName, Services) of
|
||||||
{ok, NServices} ->
|
{ok, NServices} ->
|
||||||
NChain = Chain#chain{services = NServices},
|
NChain = Chain#chain{services = NServices},
|
||||||
mnesia:write(?CHAIN_TAB, NChain, write);
|
mnesia:write(?CHAIN_TAB, NChain, write);
|
||||||
|
@ -266,9 +297,9 @@ move_service_to_the_end_of_chain(ChainID, ServiceName) ->
|
||||||
end,
|
end,
|
||||||
update_chain(ChainID, UpdateFun).
|
update_chain(ChainID, UpdateFun).
|
||||||
|
|
||||||
move_service_to_the_nth_of_chain(ChainID, ServiceName, N) ->
|
move_service_to_the_nth(ChainID, ServiceName, N) ->
|
||||||
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
UpdateFun = fun(Chain = #chain{services = Services}) ->
|
||||||
case move_service_to_nth(ServiceName, Services, N) of
|
case move_service_to_the_nth_(ServiceName, Services, N) of
|
||||||
{ok, NServices} ->
|
{ok, NServices} ->
|
||||||
NChain = Chain#chain{services = NServices},
|
NChain = Chain#chain{services = NServices},
|
||||||
mnesia:write(?CHAIN_TAB, NChain, write);
|
mnesia:write(?CHAIN_TAB, NChain, write);
|
||||||
|
@ -380,15 +411,15 @@ create_services(ChainID, [#{name := Name,
|
||||||
state = State},
|
state = State},
|
||||||
create_services(ChainID, More, [{Name, Service} | Acc]);
|
create_services(ChainID, More, [{Name, Service} | Acc]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
delete_services(Acc),
|
delete_services_(Acc),
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
delete_services([]) ->
|
delete_services_([]) ->
|
||||||
ok;
|
ok;
|
||||||
delete_services([{_, #service{provider = Provider, state = State}} | More]) ->
|
delete_services_([{_, #service{provider = Provider, state = State}} | More]) ->
|
||||||
Provider:destroy(State),
|
Provider:destroy(State),
|
||||||
delete_services(More).
|
delete_services_(More).
|
||||||
|
|
||||||
extract_services(ServiceNames, Services) ->
|
extract_services(ServiceNames, Services) ->
|
||||||
extract_services(ServiceNames, Services, []).
|
extract_services(ServiceNames, Services, []).
|
||||||
|
@ -403,43 +434,43 @@ extract_services([ServiceName | More], Services, Acc) ->
|
||||||
{error, {not_found, {service, ServiceName}}}
|
{error, {not_found, {service, ServiceName}}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
move_service_to_the_front(ServiceName, Services) ->
|
move_service_to_the_front_(ServiceName, Services) ->
|
||||||
move_service_to_the_front(ServiceName, Services, []).
|
move_service_to_the_front_(ServiceName, Services, []).
|
||||||
|
|
||||||
move_service_to_the_front(ServiceName, [], _) ->
|
move_service_to_the_front_(ServiceName, [], _) ->
|
||||||
{error, {not_found, {service, ServiceName}}};
|
{error, {not_found, {service, ServiceName}}};
|
||||||
move_service_to_the_front(ServiceName, [{ServiceName, _} = Service | More], Passed) ->
|
move_service_to_the_front_(ServiceName, [{ServiceName, _} = Service | More], Passed) ->
|
||||||
{ok, [Service | (lists:reverse(Passed) ++ More)]};
|
{ok, [Service | (lists:reverse(Passed) ++ More)]};
|
||||||
move_service_to_the_front(ServiceName, [Service | More], Passed) ->
|
move_service_to_the_front_(ServiceName, [Service | More], Passed) ->
|
||||||
move_service_to_the_front(ServiceName, More, [Service | Passed]).
|
move_service_to_the_front_(ServiceName, More, [Service | Passed]).
|
||||||
|
|
||||||
move_service_to_the_end(ServiceName, Services) ->
|
move_service_to_the_end_(ServiceName, Services) ->
|
||||||
move_service_to_the_end(ServiceName, Services, []).
|
move_service_to_the_end_(ServiceName, Services, []).
|
||||||
|
|
||||||
move_service_to_the_end(ServiceName, [], _) ->
|
move_service_to_the_end_(ServiceName, [], _) ->
|
||||||
{error, {not_found, {service, ServiceName}}};
|
{error, {not_found, {service, ServiceName}}};
|
||||||
move_service_to_the_end(ServiceName, [{ServiceName, _} = Service | More], Passed) ->
|
move_service_to_the_end_(ServiceName, [{ServiceName, _} = Service | More], Passed) ->
|
||||||
{ok, lists:reverse(Passed) ++ More ++ [Service]};
|
{ok, lists:reverse(Passed) ++ More ++ [Service]};
|
||||||
move_service_to_the_end(ServiceName, [Service | More], Passed) ->
|
move_service_to_the_end_(ServiceName, [Service | More], Passed) ->
|
||||||
move_service_to_the_end(ServiceName, More, [Service | Passed]).
|
move_service_to_the_end_(ServiceName, More, [Service | Passed]).
|
||||||
|
|
||||||
move_service_to_nth(ServiceName, Services, N)
|
move_service_to_the_nth_(ServiceName, Services, N)
|
||||||
when N =< length(Services) andalso N > 0 ->
|
when N =< length(Services) andalso N > 0 ->
|
||||||
move_service_to_nth(ServiceName, Services, N, []);
|
move_service_to_the_nth_(ServiceName, Services, N, []);
|
||||||
move_service_to_nth(_, _, _) ->
|
move_service_to_the_nth_(_, _, _) ->
|
||||||
{error, out_of_range}.
|
{error, out_of_range}.
|
||||||
|
|
||||||
move_service_to_nth(ServiceName, [], _, _) ->
|
move_service_to_the_nth_(ServiceName, [], _, _) ->
|
||||||
{error, {not_found, {service, ServiceName}}};
|
{error, {not_found, {service, ServiceName}}};
|
||||||
move_service_to_nth(ServiceName, [{ServiceName, _} = Service | More], N, Passed)
|
move_service_to_the_nth_(ServiceName, [{ServiceName, _} = Service | More], N, Passed)
|
||||||
when N =< length(Passed) ->
|
when N =< length(Passed) ->
|
||||||
{L1, L2} = lists:split(N - 1, lists:reverse(Passed)),
|
{L1, L2} = lists:split(N - 1, lists:reverse(Passed)),
|
||||||
{ok, L1 ++ [Service] ++ L2 ++ More};
|
{ok, L1 ++ [Service] ++ L2 ++ More};
|
||||||
move_service_to_nth(ServiceName, [{ServiceName, _} = Service | More], N, Passed) ->
|
move_service_to_the_nth_(ServiceName, [{ServiceName, _} = Service | More], N, Passed) ->
|
||||||
{L1, L2} = lists:split(N - length(Passed) - 1, More),
|
{L1, L2} = lists:split(N - length(Passed) - 1, More),
|
||||||
{ok, lists:reverse(Passed) ++ L1 ++ [Service] ++ L2};
|
{ok, lists:reverse(Passed) ++ L1 ++ [Service] ++ L2};
|
||||||
move_service_to_nth(ServiceName, [Service | More], N, Passed) ->
|
move_service_to_the_nth_(ServiceName, [Service | More], N, Passed) ->
|
||||||
move_service_to_nth(ServiceName, More, N, [Service | Passed]).
|
move_service_to_the_nth_(ServiceName, More, N, [Service | Passed]).
|
||||||
|
|
||||||
update_chain(ChainID, UpdateFun) ->
|
update_chain(ChainID, UpdateFun) ->
|
||||||
trans(
|
trans(
|
||||||
|
@ -478,7 +509,6 @@ serialize_chain(#chain{id = ID,
|
||||||
services => [serialize_service(Service) || Service <- Services],
|
services => [serialize_service(Service) || Service <- Services],
|
||||||
created_at => CreatedAt}.
|
created_at => CreatedAt}.
|
||||||
|
|
||||||
|
|
||||||
serialize_service({_, #service{name = Name,
|
serialize_service({_, #service{name = Name,
|
||||||
type = Type,
|
type = Type,
|
||||||
params = Params}}) ->
|
params = Params}}) ->
|
||||||
|
|
|
@ -0,0 +1,245 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2021 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_authentication_api).
|
||||||
|
|
||||||
|
-export([ create_chain/2
|
||||||
|
, delete_chain/2
|
||||||
|
, lookup_chain/2
|
||||||
|
, list_chains/2
|
||||||
|
, add_services/2
|
||||||
|
, delete_services/2
|
||||||
|
, update_service/2
|
||||||
|
, lookup_service/2
|
||||||
|
, list_services/2
|
||||||
|
, move_service/2
|
||||||
|
, import_user_credentials/2
|
||||||
|
, add_user_creadential/2
|
||||||
|
]).
|
||||||
|
|
||||||
|
-import(minirest, [return/1]).
|
||||||
|
|
||||||
|
-rest_api(#{name => list_chains,
|
||||||
|
method => 'GET',
|
||||||
|
path => "/authentication/chains",
|
||||||
|
func => list_chains,
|
||||||
|
descr => "List all chains"
|
||||||
|
}).
|
||||||
|
|
||||||
|
-rest_api(#{name => create_chain,
|
||||||
|
method => 'POST',
|
||||||
|
path => "/authentication/chains",
|
||||||
|
func => create_chain,
|
||||||
|
descr => "Create a chain"
|
||||||
|
}).
|
||||||
|
|
||||||
|
create_chain(_Binding, Params = #{chain_id := ChainID}) ->
|
||||||
|
case emqx_authentication:create_chain(Params) of
|
||||||
|
{ok, ChainID} ->
|
||||||
|
return({ok, ChainID});
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
create_chain(_Binding, _Params) ->
|
||||||
|
return({error, serialize_error({missing_parameter, chain_id})}).
|
||||||
|
|
||||||
|
delete_chain(_Binding, #{chain_id := ChainID}) ->
|
||||||
|
case emqx_authentication:delete_chain(ChainID) of
|
||||||
|
ok ->
|
||||||
|
return(ok);
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end.
|
||||||
|
|
||||||
|
lookup_chain(_Binding, #{chain_id := ChainID}) ->
|
||||||
|
case emqx_authentication:lookup_chain(ChainID) of
|
||||||
|
{ok, Chain} ->
|
||||||
|
return({ok, Chain});
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
lookup_chain(_Binding, _Params) ->
|
||||||
|
return({error, serialize_error({missing_parameter, chain_id})}).
|
||||||
|
|
||||||
|
list_chains(_Binding, _Params) ->
|
||||||
|
emqx_authentication:list_chains().
|
||||||
|
|
||||||
|
add_services(_Binding, Params = #{chain_id := ChainID}) ->
|
||||||
|
case maps:get(services, Params, []) of
|
||||||
|
[] -> return(ok);
|
||||||
|
Services ->
|
||||||
|
case emqx_authentication:add_services(ChainID, Services) of
|
||||||
|
ok ->
|
||||||
|
return(ok);
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
add_services(_Binding, _Params) ->
|
||||||
|
return({error, serialize_error({missing_parameter, chain_id})}).
|
||||||
|
|
||||||
|
delete_services(_Binding, #{chain_id := ChainID,
|
||||||
|
service_names := ServiceNames}) ->
|
||||||
|
case emqx_authentication:delete_services(ChainID, ServiceNames) of
|
||||||
|
ok ->
|
||||||
|
return(ok);
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
delete_services(_Binding, #{chain_id := _}) ->
|
||||||
|
return({error, serialize_error({missing_parameter, service_names})});
|
||||||
|
delete_services(_Binding, #{service_names := _}) ->
|
||||||
|
return({error, serialize_error({missing_parameter, chain_id})}).
|
||||||
|
|
||||||
|
%% TODO: better input parameters
|
||||||
|
update_service(_Binding, #{chain_id := ChainID,
|
||||||
|
service_name := ServiceName,
|
||||||
|
service_params := Params}) ->
|
||||||
|
case emqx_authentication:update_service(ChainID, ServiceName, Params) of
|
||||||
|
ok ->
|
||||||
|
return(ok);
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
update_service(_Binding, #{chain_id := _}) ->
|
||||||
|
return({error, serialize_error({missing_parameter, service_name})});
|
||||||
|
update_service(_Binding, #{service_name := _}) ->
|
||||||
|
return({error, serialize_error({missing_parameter, chain_id})}).
|
||||||
|
|
||||||
|
lookup_service(_Binding, #{chain_id := ChainID,
|
||||||
|
service_name := ServiceName}) ->
|
||||||
|
case emqx_authentication:lookup_service(ChainID, ServiceName) of
|
||||||
|
{ok, Service} ->
|
||||||
|
return({ok, Service});
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
lookup_service(_Binding, #{chain_id := _}) ->
|
||||||
|
return({error, serialize_error({missing_parameter, service_name})});
|
||||||
|
lookup_service(_Binding, #{service_name := _}) ->
|
||||||
|
return({error, serialize_error({missing_parameter, chain_id})}).
|
||||||
|
|
||||||
|
list_services(_Binding, #{chain_id := ChainID}) ->
|
||||||
|
case emqx_authentication:list_services(ChainID) of
|
||||||
|
{ok, Service} ->
|
||||||
|
return({ok, Service});
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
list_services(_Binding, _Params) ->
|
||||||
|
return({error, serialize_error({missing_parameter, chain_id})}).
|
||||||
|
|
||||||
|
move_service(_Binding, #{chain_id := ChainID,
|
||||||
|
service_name := ServiceName,
|
||||||
|
to := <<"the front">>}) ->
|
||||||
|
case emqx_authenticaiton:move_service_to_the_front(ChainID, ServiceName) of
|
||||||
|
ok ->
|
||||||
|
return(ok);
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
move_service(_Binding, #{chain_id := ChainID,
|
||||||
|
service_name := ServiceName,
|
||||||
|
to := <<"the end">>}) ->
|
||||||
|
case emqx_authenticaiton:move_service_to_the_end(ChainID, ServiceName) of
|
||||||
|
ok ->
|
||||||
|
return(ok);
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
move_service(_Binding, #{chain_id := ChainID,
|
||||||
|
service_name := ServiceName,
|
||||||
|
to := N}) when is_number(N) ->
|
||||||
|
case emqx_authenticaiton:move_service_to_the_nth(ChainID, ServiceName, N) of
|
||||||
|
ok ->
|
||||||
|
return(ok);
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
move_service(_Binding, Params) ->
|
||||||
|
Missed = get_missed_params(Params, [chain_id, service_name, to]),
|
||||||
|
return({error, serialize_error({missing_parameter, Missed})}).
|
||||||
|
|
||||||
|
import_user_credentials(_Binding, #{chain_id := ChainID,
|
||||||
|
service_name := ServiceName,
|
||||||
|
filename := Filename,
|
||||||
|
file_format := FileFormat}) ->
|
||||||
|
case emqx_authentication:import_user_credentials(ChainID, ServiceName, Filename, FileFormat) of
|
||||||
|
ok ->
|
||||||
|
return(ok);
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
import_user_credentials(_Binding, Params) ->
|
||||||
|
Missed = get_missed_params(Params, [chain_id, service_name, filename, file_format]),
|
||||||
|
return({error, serialize_error({missing_parameter, Missed})}).
|
||||||
|
|
||||||
|
add_user_creadential(_Binding, #{chain_id := ChainID,
|
||||||
|
service_name := ServiceName,
|
||||||
|
credential := Credential}) ->
|
||||||
|
case emqx_authentication:add_user_creadentials(ChainID, ServiceName, Credential) of
|
||||||
|
ok ->
|
||||||
|
return(ok);
|
||||||
|
{error, Reason} ->
|
||||||
|
return({error, serialize_error(Reason)})
|
||||||
|
end;
|
||||||
|
add_user_creadential(_Binding, Params) ->
|
||||||
|
Missed = get_missed_params(Params, [chain_id, service_name, credential]),
|
||||||
|
return({error, serialize_error({missing_parameter, Missed})}).
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% Internal functions
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
serialize_error(Reason) when not is_map(Reason) ->
|
||||||
|
Error = serialize_error_(Reason),
|
||||||
|
emqx_json:encode(Error).
|
||||||
|
|
||||||
|
serialize_error_({already_exists, {Type, ID}}) ->
|
||||||
|
#{code => "ALREADY_EXISTS",
|
||||||
|
message => io_lib:format("~p ~p already exists", [serialize_type(Type), ID])};
|
||||||
|
serialize_error_({not_found, {Type, ID}}) ->
|
||||||
|
#{code => "NOT_FOUND",
|
||||||
|
message => io_lib:format("~p ~p not found", [serialize_type(Type), ID])};
|
||||||
|
serialize_error_({duplicate, Name}) ->
|
||||||
|
#{code => "INVALID_PARAMETER",
|
||||||
|
message => io_lib:format("Service name ~p is duplicated", [Name])};
|
||||||
|
serialize_error_({missing_parameter, Names = [_ | Rest]}) ->
|
||||||
|
Format = ["~p," || _ <- Rest] ++ ["~p"],
|
||||||
|
NFormat = binary_to_list(iolist_to_binary(Format)),
|
||||||
|
#{code => "MISSING_PARAMETER",
|
||||||
|
message => io_lib:format("The input parameters " ++ NFormat ++ " that are mandatory for processing this request are not supplied.", Names)};
|
||||||
|
serialize_error_({missing_parameter, Name}) ->
|
||||||
|
#{code => "MISSING_PARAMETER",
|
||||||
|
message => io_lib:format("The input parameter ~p that is mandatory for processing this request is not supplied.", [Name])};
|
||||||
|
serialize_error_(_) ->
|
||||||
|
#{code => "UNKNOWN_ERROR"}.
|
||||||
|
|
||||||
|
serialize_type(service) ->
|
||||||
|
"Service";
|
||||||
|
serialize_type(chain) ->
|
||||||
|
"Chain";
|
||||||
|
serialize_type(service_type) ->
|
||||||
|
"Service type".
|
||||||
|
|
||||||
|
get_missed_params(Actual, Expected) ->
|
||||||
|
Keys = lists:fold(fun(Key, Acc) ->
|
||||||
|
case maps:is_key(Key, Actual) of
|
||||||
|
true -> Acc;
|
||||||
|
false -> [Key | Acc]
|
||||||
|
end
|
||||||
|
end, [], Expected),
|
||||||
|
lists:reverse(Keys).
|
|
@ -1,5 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
%%
|
||||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
%% you may not use this file except in compliance with the License.
|
%% you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
%%
|
||||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
%% you may not use this file except in compliance with the License.
|
%% you may not use this file except in compliance with the License.
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
-include("emqx_authentication.hrl").
|
-include("emqx_authentication.hrl").
|
||||||
|
|
||||||
-export([ create/3
|
-export([ create/3
|
||||||
|
, update/4
|
||||||
, authenticate/2
|
, authenticate/2
|
||||||
, destroy/1
|
, destroy/1
|
||||||
]).
|
]).
|
||||||
|
@ -88,6 +89,9 @@ create(ChainID, ServiceName, #{<<"user_identity_type">> := Type,
|
||||||
password_hash_algorithm => binary_to_atom(Algorithm, utf8)},
|
password_hash_algorithm => binary_to_atom(Algorithm, utf8)},
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
|
update(ChainID, ServiceName, Params, _State) ->
|
||||||
|
create(ChainID, ServiceName, Params).
|
||||||
|
|
||||||
authenticate(ClientInfo = #{password := Password},
|
authenticate(ClientInfo = #{password := Password},
|
||||||
#{user_group := UserGroup,
|
#{user_group := UserGroup,
|
||||||
user_identity_type := Type,
|
user_identity_type := Type,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved.
|
%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
%%
|
%%
|
||||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
%% you may not use this file except in compliance with the License.
|
%% you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -38,7 +38,7 @@ end_per_suite(_) ->
|
||||||
t_chain(_) ->
|
t_chain(_) ->
|
||||||
ChainID = <<"mychain">>,
|
ChainID = <<"mychain">>,
|
||||||
ChainParams = #{chain_id => ChainID,
|
ChainParams = #{chain_id => ChainID,
|
||||||
service_params => []},
|
services => []},
|
||||||
?assertEqual({ok, ChainID}, ?AUTH:create_chain(ChainParams)),
|
?assertEqual({ok, ChainID}, ?AUTH:create_chain(ChainParams)),
|
||||||
?assertEqual({error, {already_exists, {chain, ChainID}}}, ?AUTH:create_chain(ChainParams)),
|
?assertEqual({error, {already_exists, {chain, ChainID}}}, ?AUTH:create_chain(ChainParams)),
|
||||||
?assertMatch({ok, #{id := ChainID, services := []}}, ?AUTH:lookup_chain(ChainID)),
|
?assertMatch({ok, #{id := ChainID, services := []}}, ?AUTH:lookup_chain(ChainID)),
|
||||||
|
@ -55,30 +55,30 @@ t_service(_) ->
|
||||||
user_identity_type => <<"username">>,
|
user_identity_type => <<"username">>,
|
||||||
password_hash_algorithm => <<"sha256">>}},
|
password_hash_algorithm => <<"sha256">>}},
|
||||||
ChainParams = #{chain_id => ChainID,
|
ChainParams = #{chain_id => ChainID,
|
||||||
service_params => [ServiceParams1]},
|
services => [ServiceParams1]},
|
||||||
?assertEqual({ok, ChainID}, ?AUTH:create_chain(ChainParams)),
|
?assertEqual({ok, ChainID}, ?AUTH:create_chain(ChainParams)),
|
||||||
Service1 = ServiceParams1,
|
Service1 = ServiceParams1,
|
||||||
?assertMatch({ok, #{id := ChainID, services := [Service1]}}, ?AUTH:lookup_chain(ChainID)),
|
?assertMatch({ok, #{id := ChainID, services := [Service1]}}, ?AUTH:lookup_chain(ChainID)),
|
||||||
?assertEqual({ok, Service1}, ?AUTH:lookup_service(ChainID, ServiceName1)),
|
?assertEqual({ok, Service1}, ?AUTH:lookup_service(ChainID, ServiceName1)),
|
||||||
?assertEqual({ok, [Service1]}, ?AUTH:list_services(ChainID)),
|
?assertEqual({ok, [Service1]}, ?AUTH:list_services(ChainID)),
|
||||||
?assertEqual({error, {already_exists, {service, ServiceName1}}}, ?AUTH:add_services_to_chain(ChainID, [ServiceParams1])),
|
?assertEqual({error, {already_exists, {service, ServiceName1}}}, ?AUTH:add_services(ChainID, [ServiceParams1])),
|
||||||
ServiceName2 = <<"myservice2">>,
|
ServiceName2 = <<"myservice2">>,
|
||||||
ServiceParams2 = ServiceParams1#{name => ServiceName2},
|
ServiceParams2 = ServiceParams1#{name => ServiceName2},
|
||||||
?assertEqual(ok, ?AUTH:add_services_to_chain(ChainID, [ServiceParams2])),
|
?assertEqual(ok, ?AUTH:add_services(ChainID, [ServiceParams2])),
|
||||||
Service2 = ServiceParams2,
|
Service2 = ServiceParams2,
|
||||||
?assertMatch({ok, #{id := ChainID, services := [Service1, Service2]}}, ?AUTH:lookup_chain(ChainID)),
|
?assertMatch({ok, #{id := ChainID, services := [Service1, Service2]}}, ?AUTH:lookup_chain(ChainID)),
|
||||||
?assertEqual({ok, Service2}, ?AUTH:lookup_service(ChainID, ServiceName2)),
|
?assertEqual({ok, Service2}, ?AUTH:lookup_service(ChainID, ServiceName2)),
|
||||||
?assertEqual({ok, [Service1, Service2]}, ?AUTH:list_services(ChainID)),
|
?assertEqual({ok, [Service1, Service2]}, ?AUTH:list_services(ChainID)),
|
||||||
|
|
||||||
?assertEqual(ok, ?AUTH:move_service_to_the_front_of_chain(ChainID, ServiceName2)),
|
?assertEqual(ok, ?AUTH:move_service_to_the_front(ChainID, ServiceName2)),
|
||||||
?assertEqual({ok, [Service2, Service1]}, ?AUTH:list_services(ChainID)),
|
?assertEqual({ok, [Service2, Service1]}, ?AUTH:list_services(ChainID)),
|
||||||
?assertEqual(ok, ?AUTH:move_service_to_the_end_of_chain(ChainID, ServiceName2)),
|
?assertEqual(ok, ?AUTH:move_service_to_the_end(ChainID, ServiceName2)),
|
||||||
?assertEqual({ok, [Service1, Service2]}, ?AUTH:list_services(ChainID)),
|
?assertEqual({ok, [Service1, Service2]}, ?AUTH:list_services(ChainID)),
|
||||||
?assertEqual(ok, ?AUTH:move_service_to_the_nth_of_chain(ChainID, ServiceName2, 1)),
|
?assertEqual(ok, ?AUTH:move_service_to_the_nth(ChainID, ServiceName2, 1)),
|
||||||
?assertEqual({ok, [Service2, Service1]}, ?AUTH:list_services(ChainID)),
|
?assertEqual({ok, [Service2, Service1]}, ?AUTH:list_services(ChainID)),
|
||||||
?assertEqual({error, out_of_range}, ?AUTH:move_service_to_the_nth_of_chain(ChainID, ServiceName2, 3)),
|
?assertEqual({error, out_of_range}, ?AUTH:move_service_to_the_nth(ChainID, ServiceName2, 3)),
|
||||||
?assertEqual({error, out_of_range}, ?AUTH:move_service_to_the_nth_of_chain(ChainID, ServiceName2, 0)),
|
?assertEqual({error, out_of_range}, ?AUTH:move_service_to_the_nth(ChainID, ServiceName2, 0)),
|
||||||
?assertEqual(ok, ?AUTH:delete_services_from_chain(ChainID, [ServiceName1, ServiceName2])),
|
?assertEqual(ok, ?AUTH:delete_services(ChainID, [ServiceName1, ServiceName2])),
|
||||||
?assertEqual({ok, []}, ?AUTH:list_services(ChainID)),
|
?assertEqual({ok, []}, ?AUTH:list_services(ChainID)),
|
||||||
?assertEqual(ok, ?AUTH:delete_chain(ChainID)),
|
?assertEqual(ok, ?AUTH:delete_chain(ChainID)),
|
||||||
ok.
|
ok.
|
||||||
|
@ -92,7 +92,7 @@ t_mnesia_service(_) ->
|
||||||
user_identity_type => <<"username">>,
|
user_identity_type => <<"username">>,
|
||||||
password_hash_algorithm => <<"sha256">>}},
|
password_hash_algorithm => <<"sha256">>}},
|
||||||
ChainParams = #{chain_id => ChainID,
|
ChainParams = #{chain_id => ChainID,
|
||||||
service_params => [ServiceParams]},
|
services => [ServiceParams]},
|
||||||
?assertEqual({ok, ChainID}, ?AUTH:create_chain(ChainParams)),
|
?assertEqual({ok, ChainID}, ?AUTH:create_chain(ChainParams)),
|
||||||
UserCredential = #{user_identity => <<"myuser">>,
|
UserCredential = #{user_identity => <<"myuser">>,
|
||||||
password => <<"mypass">>},
|
password => <<"mypass">>},
|
||||||
|
@ -116,8 +116,8 @@ t_mnesia_service(_) ->
|
||||||
|
|
||||||
?assertEqual(ok, ?AUTH:add_user_credential(ChainID, ServiceName, UserCredential)),
|
?assertEqual(ok, ?AUTH:add_user_credential(ChainID, ServiceName, UserCredential)),
|
||||||
?assertMatch({ok, #{user_identity := <<"myuser">>}}, ?AUTH:lookup_user_credential(ChainID, ServiceName, <<"myuser">>)),
|
?assertMatch({ok, #{user_identity := <<"myuser">>}}, ?AUTH:lookup_user_credential(ChainID, ServiceName, <<"myuser">>)),
|
||||||
?assertEqual(ok, ?AUTH:delete_services_from_chain(ChainID, [ServiceName])),
|
?assertEqual(ok, ?AUTH:delete_services(ChainID, [ServiceName])),
|
||||||
?assertEqual(ok, ?AUTH:add_services_to_chain(ChainID, [ServiceParams])),
|
?assertEqual(ok, ?AUTH:add_services(ChainID, [ServiceParams])),
|
||||||
?assertMatch({error, not_found}, ?AUTH:lookup_user_credential(ChainID, ServiceName, <<"myuser">>)),
|
?assertMatch({error, not_found}, ?AUTH:lookup_user_credential(ChainID, ServiceName, <<"myuser">>)),
|
||||||
|
|
||||||
?assertEqual(ok, ?AUTH:delete_chain(ChainID)),
|
?assertEqual(ok, ?AUTH:delete_chain(ChainID)),
|
||||||
|
@ -133,7 +133,7 @@ t_import(_) ->
|
||||||
user_identity_type => <<"username">>,
|
user_identity_type => <<"username">>,
|
||||||
password_hash_algorithm => <<"sha256">>}},
|
password_hash_algorithm => <<"sha256">>}},
|
||||||
ChainParams = #{chain_id => ChainID,
|
ChainParams = #{chain_id => ChainID,
|
||||||
service_params => [ServiceParams]},
|
services => [ServiceParams]},
|
||||||
?assertEqual({ok, ChainID}, ?AUTH:create_chain(ChainParams)),
|
?assertEqual({ok, ChainID}, ?AUTH:create_chain(ChainParams)),
|
||||||
Dir = code:lib_dir(emqx_authentication, test),
|
Dir = code:lib_dir(emqx_authentication, test),
|
||||||
?assertEqual(ok, ?AUTH:import_user_credentials(ChainID, ServiceName, filename:join([Dir, "data/user-credentials.json"]), json)),
|
?assertEqual(ok, ?AUTH:import_user_credentials(ChainID, ServiceName, filename:join([Dir, "data/user-credentials.json"]), json)),
|
||||||
|
@ -165,7 +165,7 @@ t_multi_mnesia_service(_) ->
|
||||||
user_identity_type => <<"clientid">>,
|
user_identity_type => <<"clientid">>,
|
||||||
password_hash_algorithm => <<"sha256">>}},
|
password_hash_algorithm => <<"sha256">>}},
|
||||||
ChainParams = #{chain_id => ChainID,
|
ChainParams = #{chain_id => ChainID,
|
||||||
service_params => [ServiceParams1, ServiceParams2]},
|
services => [ServiceParams1, ServiceParams2]},
|
||||||
?assertEqual({ok, ChainID}, ?AUTH:create_chain(ChainParams)),
|
?assertEqual({ok, ChainID}, ?AUTH:create_chain(ChainParams)),
|
||||||
|
|
||||||
?assertEqual(ok, ?AUTH:add_user_credential(ChainID,
|
?assertEqual(ok, ?AUTH:add_user_credential(ChainID,
|
||||||
|
@ -181,7 +181,7 @@ t_multi_mnesia_service(_) ->
|
||||||
clientid => <<"myclient">>,
|
clientid => <<"myclient">>,
|
||||||
password => <<"mypass1">>},
|
password => <<"mypass1">>},
|
||||||
?assertEqual(ok, ?AUTH:authenticate(ClientInfo1)),
|
?assertEqual(ok, ?AUTH:authenticate(ClientInfo1)),
|
||||||
?assertEqual(ok, ?AUTH:move_service_to_the_front_of_chain(ChainID, ServiceName2)),
|
?assertEqual(ok, ?AUTH:move_service_to_the_front(ChainID, ServiceName2)),
|
||||||
?assertEqual({error, bad_password}, ?AUTH:authenticate(ClientInfo1)),
|
?assertEqual({error, bad_password}, ?AUTH:authenticate(ClientInfo1)),
|
||||||
ClientInfo2 = ClientInfo1#{password => <<"mypass2">>},
|
ClientInfo2 = ClientInfo1#{password => <<"mypass2">>},
|
||||||
?assertEqual(ok, ?AUTH:authenticate(ClientInfo2)),
|
?assertEqual(ok, ?AUTH:authenticate(ClientInfo2)),
|
||||||
|
|
Loading…
Reference in New Issue