Merge pull request #5679 from tigercl/chore/authn
chore(authn): update apis for user
This commit is contained in:
commit
f75778b037
|
@ -147,6 +147,6 @@
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-record(chain,
|
-record(chain,
|
||||||
{ name :: binary()
|
{ name :: atom()
|
||||||
, authenticators :: [#authenticator{}]
|
, authenticators :: [#authenticator{}]
|
||||||
}).
|
}).
|
|
@ -29,9 +29,9 @@
|
||||||
-spec(authenticate(emqx_types:clientinfo()) ->
|
-spec(authenticate(emqx_types:clientinfo()) ->
|
||||||
{ok, map()} | {ok, map(), binary()} | {continue, map()} | {continue, binary(), map()} | {error, term()}).
|
{ok, map()} | {ok, map(), binary()} | {continue, map()} | {continue, binary(), map()} | {error, term()}).
|
||||||
authenticate(Credential) ->
|
authenticate(Credential) ->
|
||||||
case run_hooks('client.authenticate', [Credential], {ok, #{superuser => false}}) of
|
case run_hooks('client.authenticate', [Credential], {ok, #{is_superuser => false}}) of
|
||||||
ok ->
|
ok ->
|
||||||
{ok, #{superuser => false}};
|
{ok, #{is_superuser => false}};
|
||||||
Other ->
|
Other ->
|
||||||
Other
|
Other
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
|
|
||||||
-type config() :: #{atom() => term()}.
|
-type config() :: #{atom() => term()}.
|
||||||
-type state() :: #{atom() => term()}.
|
-type state() :: #{atom() => term()}.
|
||||||
-type extra() :: #{superuser := boolean(),
|
-type extra() :: #{is_superuser := boolean(),
|
||||||
atom() => term()}.
|
atom() => term()}.
|
||||||
-type user_info() :: #{user_id := binary(),
|
-type user_info() :: #{user_id := binary(),
|
||||||
atom() => term()}.
|
atom() => term()}.
|
||||||
|
@ -473,7 +473,7 @@ handle_call({update_authenticator, ChainName, AuthenticatorID, Config}, _From, S
|
||||||
state = #{version := Version} = ST} = Authenticator ->
|
state = #{version := Version} = ST} = Authenticator ->
|
||||||
case AuthenticatorID =:= generate_id(Config) of
|
case AuthenticatorID =:= generate_id(Config) of
|
||||||
true ->
|
true ->
|
||||||
Unique = <<ChainName/binary, "/", AuthenticatorID/binary, ":", Version/binary>>,
|
Unique = unique(ChainName, AuthenticatorID, Version),
|
||||||
case Provider:update(Config#{'_unique' => Unique}, ST) of
|
case Provider:update(Config#{'_unique' => Unique}, ST) of
|
||||||
{ok, NewST} ->
|
{ok, NewST} ->
|
||||||
NewAuthenticator = Authenticator#authenticator{state = switch_version(NewST)},
|
NewAuthenticator = Authenticator#authenticator{state = switch_version(NewST)},
|
||||||
|
@ -575,17 +575,17 @@ split_by_id(ID, AuthenticatorsConfig) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
global_chain(mqtt) ->
|
global_chain(mqtt) ->
|
||||||
<<"mqtt:global">>;
|
'mqtt:global';
|
||||||
global_chain('mqtt-sn') ->
|
global_chain('mqtt-sn') ->
|
||||||
<<"mqtt-sn:global">>;
|
'mqtt-sn:global';
|
||||||
global_chain(coap) ->
|
global_chain(coap) ->
|
||||||
<<"coap:global">>;
|
'coap:global';
|
||||||
global_chain(lwm2m) ->
|
global_chain(lwm2m) ->
|
||||||
<<"lwm2m:global">>;
|
'lwm2m:global';
|
||||||
global_chain(stomp) ->
|
global_chain(stomp) ->
|
||||||
<<"stomp:global">>;
|
'stomp:global';
|
||||||
global_chain(_) ->
|
global_chain(_) ->
|
||||||
<<"unknown:global">>.
|
'unknown:global'.
|
||||||
|
|
||||||
may_hook(#{hooked := false} = State) ->
|
may_hook(#{hooked := false} = State) ->
|
||||||
case lists:any(fun(#chain{authenticators = []}) -> false;
|
case lists:any(fun(#chain{authenticators = []}) -> false;
|
||||||
|
@ -618,7 +618,7 @@ do_create_authenticator(ChainName, AuthenticatorID, #{enable := Enable} = Config
|
||||||
undefined ->
|
undefined ->
|
||||||
{error, no_available_provider};
|
{error, no_available_provider};
|
||||||
Provider ->
|
Provider ->
|
||||||
Unique = <<ChainName/binary, "/", AuthenticatorID/binary, ":", ?VER_1/binary>>,
|
Unique = unique(ChainName, AuthenticatorID, ?VER_1),
|
||||||
case Provider:create(Config#{'_unique' => Unique}) of
|
case Provider:create(Config#{'_unique' => Unique}) of
|
||||||
{ok, State} ->
|
{ok, State} ->
|
||||||
Authenticator = #authenticator{id = AuthenticatorID,
|
Authenticator = #authenticator{id = AuthenticatorID,
|
||||||
|
@ -704,6 +704,10 @@ serialize_authenticator(#authenticator{id = ID,
|
||||||
, state => State
|
, state => State
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
unique(ChainName, AuthenticatorID, Version) ->
|
||||||
|
NChainName = atom_to_binary(ChainName),
|
||||||
|
<<NChainName/binary, "/", AuthenticatorID/binary, ":", Version/binary>>.
|
||||||
|
|
||||||
switch_version(State = #{version := ?VER_1}) ->
|
switch_version(State = #{version := ?VER_1}) ->
|
||||||
State#{version := ?VER_2};
|
State#{version := ?VER_2};
|
||||||
switch_version(State = #{version := ?VER_2}) ->
|
switch_version(State = #{version := ?VER_2}) ->
|
||||||
|
|
|
@ -214,7 +214,7 @@ init(ConnInfo = #{peername := {PeerHost, _Port},
|
||||||
ClientInfo = set_peercert_infos(
|
ClientInfo = set_peercert_infos(
|
||||||
Peercert,
|
Peercert,
|
||||||
#{zone => Zone,
|
#{zone => Zone,
|
||||||
listener => Listener,
|
listener => emqx_listeners:listener_id(Type, Listener),
|
||||||
protocol => Protocol,
|
protocol => Protocol,
|
||||||
peerhost => PeerHost,
|
peerhost => PeerHost,
|
||||||
sockport => SockPort,
|
sockport => SockPort,
|
||||||
|
@ -223,7 +223,7 @@ init(ConnInfo = #{peername := {PeerHost, _Port},
|
||||||
mountpoint => MountPoint,
|
mountpoint => MountPoint,
|
||||||
is_bridge => false,
|
is_bridge => false,
|
||||||
is_superuser => false
|
is_superuser => false
|
||||||
}, Zone, Listener),
|
}, Zone),
|
||||||
{NClientInfo, NConnInfo} = take_ws_cookie(ClientInfo, ConnInfo),
|
{NClientInfo, NConnInfo} = take_ws_cookie(ClientInfo, ConnInfo),
|
||||||
#channel{conninfo = NConnInfo,
|
#channel{conninfo = NConnInfo,
|
||||||
clientinfo = NClientInfo,
|
clientinfo = NClientInfo,
|
||||||
|
@ -244,12 +244,12 @@ quota_policy(RawPolicy) ->
|
||||||
erlang:trunc(hocon_postprocess:duration(StrWind) / 1000)}}
|
erlang:trunc(hocon_postprocess:duration(StrWind) / 1000)}}
|
||||||
|| {Name, [StrCount, StrWind]} <- maps:to_list(RawPolicy)].
|
|| {Name, [StrCount, StrWind]} <- maps:to_list(RawPolicy)].
|
||||||
|
|
||||||
set_peercert_infos(NoSSL, ClientInfo, _, _)
|
set_peercert_infos(NoSSL, ClientInfo, _)
|
||||||
when NoSSL =:= nossl;
|
when NoSSL =:= nossl;
|
||||||
NoSSL =:= undefined ->
|
NoSSL =:= undefined ->
|
||||||
ClientInfo#{username => undefined};
|
ClientInfo#{username => undefined};
|
||||||
|
|
||||||
set_peercert_infos(Peercert, ClientInfo, Zone, _Listener) ->
|
set_peercert_infos(Peercert, ClientInfo, Zone) ->
|
||||||
{DN, CN} = {esockd_peercert:subject(Peercert),
|
{DN, CN} = {esockd_peercert:subject(Peercert),
|
||||||
esockd_peercert:common_name(Peercert)},
|
esockd_peercert:common_name(Peercert)},
|
||||||
PeercetAs = fun(Key) ->
|
PeercetAs = fun(Key) ->
|
||||||
|
@ -1303,11 +1303,11 @@ do_authenticate(#{auth_method := AuthMethod} = Credential, #channel{clientinfo =
|
||||||
case emqx_access_control:authenticate(Credential) of
|
case emqx_access_control:authenticate(Credential) of
|
||||||
{ok, Result} ->
|
{ok, Result} ->
|
||||||
{ok, Properties,
|
{ok, Properties,
|
||||||
Channel#channel{clientinfo = ClientInfo#{is_superuser => maps:get(superuser, Result, false)},
|
Channel#channel{clientinfo = ClientInfo#{is_superuser => maps:get(is_superuser, Result, false)},
|
||||||
auth_cache = #{}}};
|
auth_cache = #{}}};
|
||||||
{ok, Result, AuthData} ->
|
{ok, Result, AuthData} ->
|
||||||
{ok, Properties#{'Authentication-Data' => AuthData},
|
{ok, Properties#{'Authentication-Data' => AuthData},
|
||||||
Channel#channel{clientinfo = ClientInfo#{is_superuser => maps:get(superuser, Result, false)},
|
Channel#channel{clientinfo = ClientInfo#{is_superuser => maps:get(is_superuser, Result, false)},
|
||||||
auth_cache = #{}}};
|
auth_cache = #{}}};
|
||||||
{continue, AuthCache} ->
|
{continue, AuthCache} ->
|
||||||
{continue, Properties, Channel#channel{auth_cache = AuthCache}};
|
{continue, Properties, Channel#channel{auth_cache = AuthCache}};
|
||||||
|
@ -1320,8 +1320,8 @@ do_authenticate(#{auth_method := AuthMethod} = Credential, #channel{clientinfo =
|
||||||
|
|
||||||
do_authenticate(Credential, #channel{clientinfo = ClientInfo} = Channel) ->
|
do_authenticate(Credential, #channel{clientinfo = ClientInfo} = Channel) ->
|
||||||
case emqx_access_control:authenticate(Credential) of
|
case emqx_access_control:authenticate(Credential) of
|
||||||
{ok, #{superuser := Superuser}} ->
|
{ok, #{is_superuser := IsSuperuser}} ->
|
||||||
{ok, #{}, Channel#channel{clientinfo = ClientInfo#{is_superuser => Superuser}}};
|
{ok, #{}, Channel#channel{clientinfo = ClientInfo#{is_superuser => IsSuperuser}}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, emqx_reason_codes:connack_error(Reason)}
|
{error, emqx_reason_codes:connack_error(Reason)}
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -73,7 +73,7 @@ update(_Config, _State) ->
|
||||||
{ok, #{mark => 2}}.
|
{ok, #{mark => 2}}.
|
||||||
|
|
||||||
authenticate(#{username := <<"good">>}, _State) ->
|
authenticate(#{username := <<"good">>}, _State) ->
|
||||||
{ok, #{superuser => true}};
|
{ok, #{is_superuser => true}};
|
||||||
authenticate(#{username := _}, _State) ->
|
authenticate(#{username := _}, _State) ->
|
||||||
{error, bad_username_or_password}.
|
{error, bad_username_or_password}.
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ end_per_suite(_) ->
|
||||||
|
|
||||||
t_chain(_) ->
|
t_chain(_) ->
|
||||||
% CRUD of authentication chain
|
% CRUD of authentication chain
|
||||||
ChainName = <<"test">>,
|
ChainName = 'test',
|
||||||
?assertMatch({ok, []}, ?AUTHN:list_chains()),
|
?assertMatch({ok, []}, ?AUTHN:list_chains()),
|
||||||
?assertMatch({ok, #{name := ChainName, authenticators := []}}, ?AUTHN:create_chain(ChainName)),
|
?assertMatch({ok, #{name := ChainName, authenticators := []}}, ?AUTHN:create_chain(ChainName)),
|
||||||
?assertEqual({error, {already_exists, {chain, ChainName}}}, ?AUTHN:create_chain(ChainName)),
|
?assertEqual({error, {already_exists, {chain, ChainName}}}, ?AUTHN:create_chain(ChainName)),
|
||||||
|
@ -105,7 +105,7 @@ t_chain(_) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
t_authenticator(_) ->
|
t_authenticator(_) ->
|
||||||
ChainName = <<"test">>,
|
ChainName = 'test',
|
||||||
AuthenticatorConfig1 = #{mechanism => 'password-based',
|
AuthenticatorConfig1 = #{mechanism => 'password-based',
|
||||||
backend => 'built-in-database',
|
backend => 'built-in-database',
|
||||||
enable => true},
|
enable => true},
|
||||||
|
@ -155,13 +155,13 @@ t_authenticator(_) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
t_authenticate(_) ->
|
t_authenticate(_) ->
|
||||||
ListenerID = <<"tcp:default">>,
|
ListenerID = 'tcp:default',
|
||||||
ClientInfo = #{zone => default,
|
ClientInfo = #{zone => default,
|
||||||
listener => ListenerID,
|
listener => ListenerID,
|
||||||
protocol => mqtt,
|
protocol => mqtt,
|
||||||
username => <<"good">>,
|
username => <<"good">>,
|
||||||
password => <<"any">>},
|
password => <<"any">>},
|
||||||
?assertEqual({ok, #{superuser => false}}, emqx_access_control:authenticate(ClientInfo)),
|
?assertEqual({ok, #{is_superuser => false}}, emqx_access_control:authenticate(ClientInfo)),
|
||||||
|
|
||||||
AuthNType = {'password-based', 'built-in-database'},
|
AuthNType = {'password-based', 'built-in-database'},
|
||||||
?AUTHN:add_provider(AuthNType, ?MODULE),
|
?AUTHN:add_provider(AuthNType, ?MODULE),
|
||||||
|
@ -171,7 +171,7 @@ t_authenticate(_) ->
|
||||||
enable => true},
|
enable => true},
|
||||||
?AUTHN:create_chain(ListenerID),
|
?AUTHN:create_chain(ListenerID),
|
||||||
?assertMatch({ok, _}, ?AUTHN:create_authenticator(ListenerID, AuthenticatorConfig)),
|
?assertMatch({ok, _}, ?AUTHN:create_authenticator(ListenerID, AuthenticatorConfig)),
|
||||||
?assertEqual({ok, #{superuser => true}}, emqx_access_control:authenticate(ClientInfo)),
|
?assertEqual({ok, #{is_superuser => true}}, emqx_access_control:authenticate(ClientInfo)),
|
||||||
?assertEqual({error, bad_username_or_password}, emqx_access_control:authenticate(ClientInfo#{username => <<"bad">>})),
|
?assertEqual({error, bad_username_or_password}, emqx_access_control:authenticate(ClientInfo#{username => <<"bad">>})),
|
||||||
|
|
||||||
?AUTHN:delete_chain(ListenerID),
|
?AUTHN:delete_chain(ListenerID),
|
||||||
|
@ -186,7 +186,7 @@ t_update_config(_) ->
|
||||||
?AUTHN:add_provider(AuthNType1, ?MODULE),
|
?AUTHN:add_provider(AuthNType1, ?MODULE),
|
||||||
?AUTHN:add_provider(AuthNType2, ?MODULE),
|
?AUTHN:add_provider(AuthNType2, ?MODULE),
|
||||||
|
|
||||||
Global = <<"mqtt:global">>,
|
Global = 'mqtt:global',
|
||||||
AuthenticatorConfig1 = #{mechanism => 'password-based',
|
AuthenticatorConfig1 = #{mechanism => 'password-based',
|
||||||
backend => 'built-in-database',
|
backend => 'built-in-database',
|
||||||
enable => true},
|
enable => true},
|
||||||
|
@ -212,7 +212,7 @@ t_update_config(_) ->
|
||||||
?assertMatch({ok, _}, update_config([authentication], {delete_authenticator, Global, ID1})),
|
?assertMatch({ok, _}, update_config([authentication], {delete_authenticator, Global, ID1})),
|
||||||
?assertEqual({error, {not_found, {authenticator, ID1}}}, ?AUTHN:lookup_authenticator(Global, ID1)),
|
?assertEqual({error, {not_found, {authenticator, ID1}}}, ?AUTHN:lookup_authenticator(Global, ID1)),
|
||||||
|
|
||||||
ListenerID = <<"tcp:default">>,
|
ListenerID = 'tcp:default',
|
||||||
ConfKeyPath = [listeners, tcp, default, authentication],
|
ConfKeyPath = [listeners, tcp, default, authentication],
|
||||||
?assertMatch({ok, _}, update_config(ConfKeyPath, {create_authenticator, ListenerID, AuthenticatorConfig1})),
|
?assertMatch({ok, _}, update_config(ConfKeyPath, {create_authenticator, ListenerID, AuthenticatorConfig1})),
|
||||||
?assertMatch({ok, #{id := ID1, state := #{mark := 1}}}, ?AUTHN:lookup_authenticator(ListenerID, ID1)),
|
?assertMatch({ok, #{id := ID1, state := #{mark := 1}}}, ?AUTHN:lookup_authenticator(ListenerID, ID1)),
|
||||||
|
|
|
@ -144,7 +144,7 @@ init_per_suite(Config) ->
|
||||||
%% Access Control Meck
|
%% Access Control Meck
|
||||||
ok = meck:new(emqx_access_control, [passthrough, no_history, no_link]),
|
ok = meck:new(emqx_access_control, [passthrough, no_history, no_link]),
|
||||||
ok = meck:expect(emqx_access_control, authenticate,
|
ok = meck:expect(emqx_access_control, authenticate,
|
||||||
fun(_) -> {ok, #{superuser => false}} end),
|
fun(_) -> {ok, #{is_superuser => false}} end),
|
||||||
ok = meck:expect(emqx_access_control, authorize, fun(_, _, _) -> allow end),
|
ok = meck:expect(emqx_access_control, authorize, fun(_, _, _) -> allow end),
|
||||||
%% Broker Meck
|
%% Broker Meck
|
||||||
ok = meck:new(emqx_broker, [passthrough, no_history, no_link]),
|
ok = meck:new(emqx_broker, [passthrough, no_history, no_link]),
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
user_id,password_hash,salt,superuser
|
user_id,password_hash,salt,is_superuser
|
||||||
myuser3,b6c743545a7817ae8c8f624371d5f5f0373234bb0ff36b8ffbf19bce0e06ab75,de1024f462fb83910fd13151bd4bd235,true
|
myuser3,b6c743545a7817ae8c8f624371d5f5f0373234bb0ff36b8ffbf19bce0e06ab75,de1024f462fb83910fd13151bd4bd235,true
|
||||||
myuser4,ee68c985a69208b6eda8c6c9b4c7c2d2b15ee2352cdd64a903171710a99182e8,ad773b5be9dd0613fe6c2f4d8c403139,false
|
myuser4,ee68c985a69208b6eda8c6c9b4c7c2d2b15ee2352cdd64a903171710a99182e8,ad773b5be9dd0613fe6c2f4d8c403139,false
|
||||||
|
|
|
|
@ -3,12 +3,12 @@
|
||||||
"user_id":"myuser1",
|
"user_id":"myuser1",
|
||||||
"password_hash":"c5e46903df45e5dc096dc74657610dbee8deaacae656df88a1788f1847390242",
|
"password_hash":"c5e46903df45e5dc096dc74657610dbee8deaacae656df88a1788f1847390242",
|
||||||
"salt": "e378187547bf2d6f0545a3f441aa4d8a",
|
"salt": "e378187547bf2d6f0545a3f441aa4d8a",
|
||||||
"superuser": true
|
"is_superuser": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"user_id":"myuser2",
|
"user_id":"myuser2",
|
||||||
"password_hash":"f4d17f300b11e522fd33f497c11b126ef1ea5149c74d2220f9a16dc876d4567b",
|
"password_hash":"f4d17f300b11e522fd33f497c11b126ef1ea5149c74d2220f9a16dc876d4567b",
|
||||||
"salt": "6d3f9bd5b54d94b98adbcfe10b6d181f",
|
"salt": "6d3f9bd5b54d94b98adbcfe10b6d181f",
|
||||||
"superuser": false
|
"is_superuser": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
-define(AUTHN, emqx_authentication).
|
-define(AUTHN, emqx_authentication).
|
||||||
|
|
||||||
-define(GLOBAL, <<"mqtt:global">>).
|
-define(GLOBAL, 'mqtt:global').
|
||||||
|
|
||||||
-define(RE_PLACEHOLDER, "\\$\\{[a-z0-9\\-]+\\}").
|
-define(RE_PLACEHOLDER, "\\$\\{[a-z0-9\\-]+\\}").
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,11 @@
|
||||||
, move/2
|
, move/2
|
||||||
, move2/2
|
, move2/2
|
||||||
, import_users/2
|
, import_users/2
|
||||||
|
, import_users2/2
|
||||||
, users/2
|
, users/2
|
||||||
, users2/2
|
, users2/2
|
||||||
|
, users3/2
|
||||||
|
, users4/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-define(EXAMPLE_1, #{mechanism => <<"password-based">>,
|
-define(EXAMPLE_1, #{mechanism => <<"password-based">>,
|
||||||
|
@ -70,6 +73,7 @@
|
||||||
},
|
},
|
||||||
password_hash_field => <<"password_hash">>,
|
password_hash_field => <<"password_hash">>,
|
||||||
salt_field => <<"salt">>,
|
salt_field => <<"salt">>,
|
||||||
|
is_superuser_field => <<"is_superuser">>,
|
||||||
password_hash_algorithm => <<"sha256">>,
|
password_hash_algorithm => <<"sha256">>,
|
||||||
salt_position => <<"prefix">>
|
salt_position => <<"prefix">>
|
||||||
}).
|
}).
|
||||||
|
@ -153,8 +157,11 @@ api_spec() ->
|
||||||
, authentication_api4()
|
, authentication_api4()
|
||||||
, move_api2()
|
, move_api2()
|
||||||
, import_users_api()
|
, import_users_api()
|
||||||
|
, import_users_api2()
|
||||||
, users_api()
|
, users_api()
|
||||||
, users2_api()
|
, users2_api()
|
||||||
|
, users3_api()
|
||||||
|
, users4_api()
|
||||||
], definitions()}.
|
], definitions()}.
|
||||||
|
|
||||||
authentication_api() ->
|
authentication_api() ->
|
||||||
|
@ -166,7 +173,7 @@ authentication_api() ->
|
||||||
|
|
||||||
authentication_api2() ->
|
authentication_api2() ->
|
||||||
Metadata = #{
|
Metadata = #{
|
||||||
get => list_authenticator_api_spec(),
|
get => find_authenticator_api_spec(),
|
||||||
put => update_authenticator_api_spec(),
|
put => update_authenticator_api_spec(),
|
||||||
delete => delete_authenticator_api_spec()
|
delete => delete_authenticator_api_spec()
|
||||||
},
|
},
|
||||||
|
@ -181,7 +188,7 @@ authentication_api3() ->
|
||||||
|
|
||||||
authentication_api4() ->
|
authentication_api4() ->
|
||||||
Metadata = #{
|
Metadata = #{
|
||||||
get => list_authenticator_api_spec2(),
|
get => find_authenticator_api_spec2(),
|
||||||
put => update_authenticator_api_spec2(),
|
put => update_authenticator_api_spec2(),
|
||||||
delete => delete_authenticator_api_spec2()
|
delete => delete_authenticator_api_spec2()
|
||||||
},
|
},
|
||||||
|
@ -199,6 +206,48 @@ move_api2() ->
|
||||||
},
|
},
|
||||||
{"/listeners/:listener_id/authentication/:id/move", Metadata, move2}.
|
{"/listeners/:listener_id/authentication/:id/move", Metadata, move2}.
|
||||||
|
|
||||||
|
import_users_api() ->
|
||||||
|
Metadata = #{
|
||||||
|
post => import_users_api_spec()
|
||||||
|
},
|
||||||
|
{"/authentication/:id/import_users", Metadata, import_users}.
|
||||||
|
|
||||||
|
import_users_api2() ->
|
||||||
|
Metadata = #{
|
||||||
|
post => import_users_api_spec2()
|
||||||
|
},
|
||||||
|
{"/listeners/:listener_id/authentication/:id/import_users", Metadata, import_users2}.
|
||||||
|
|
||||||
|
users_api() ->
|
||||||
|
Metadata = #{
|
||||||
|
post => create_user_api_spec(),
|
||||||
|
get => list_users_api_spec()
|
||||||
|
},
|
||||||
|
{"/authentication/:id/users", Metadata, users}.
|
||||||
|
|
||||||
|
users2_api() ->
|
||||||
|
Metadata = #{
|
||||||
|
put => update_user_api_spec(),
|
||||||
|
get => find_user_api_spec(),
|
||||||
|
delete => delete_user_api_spec()
|
||||||
|
},
|
||||||
|
{"/authentication/:id/users/:user_id", Metadata, users2}.
|
||||||
|
|
||||||
|
users3_api() ->
|
||||||
|
Metadata = #{
|
||||||
|
post => create_user_api_spec2(),
|
||||||
|
get => list_users_api_spec2()
|
||||||
|
},
|
||||||
|
{"/listeners/:listener_id/authentication/:id/users", Metadata, users3}.
|
||||||
|
|
||||||
|
users4_api() ->
|
||||||
|
Metadata = #{
|
||||||
|
put => update_user_api_spec2(),
|
||||||
|
get => find_user_api_spec2(),
|
||||||
|
delete => delete_user_api_spec2()
|
||||||
|
},
|
||||||
|
{"/listeners/:listener_id/authentication/:id/users/:user_id", Metadata, users4}.
|
||||||
|
|
||||||
create_authenticator_api_spec() ->
|
create_authenticator_api_spec() ->
|
||||||
#{
|
#{
|
||||||
description => "Create a authenticator for global authentication",
|
description => "Create a authenticator for global authentication",
|
||||||
|
@ -321,14 +370,14 @@ list_authenticators_api_spec2() ->
|
||||||
]
|
]
|
||||||
}.
|
}.
|
||||||
|
|
||||||
list_authenticator_api_spec() ->
|
find_authenticator_api_spec() ->
|
||||||
#{
|
#{
|
||||||
description => "Get authenticator by id",
|
description => "Get authenticator by id",
|
||||||
parameters => [
|
parameters => [
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -370,14 +419,14 @@ list_authenticator_api_spec() ->
|
||||||
}
|
}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
list_authenticator_api_spec2() ->
|
find_authenticator_api_spec2() ->
|
||||||
Spec = list_authenticator_api_spec(),
|
Spec = find_authenticator_api_spec(),
|
||||||
Spec#{
|
Spec#{
|
||||||
parameters => [
|
parameters => [
|
||||||
#{
|
#{
|
||||||
name => listener_id,
|
name => listener_id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of listener",
|
description => "Listener id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -386,7 +435,7 @@ list_authenticator_api_spec2() ->
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -402,7 +451,7 @@ update_authenticator_api_spec() ->
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -482,7 +531,7 @@ update_authenticator_api_spec2() ->
|
||||||
#{
|
#{
|
||||||
name => listener_id,
|
name => listener_id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of listener",
|
description => "Listener id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -491,7 +540,7 @@ update_authenticator_api_spec2() ->
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -507,7 +556,7 @@ delete_authenticator_api_spec() ->
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -529,7 +578,7 @@ delete_authenticator_api_spec2() ->
|
||||||
#{
|
#{
|
||||||
name => listener_id,
|
name => listener_id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of listener",
|
description => "Listener id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -538,7 +587,7 @@ delete_authenticator_api_spec2() ->
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -554,7 +603,7 @@ move_authenticator_api_spec() ->
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -609,7 +658,7 @@ move_authenticator_api_spec2() ->
|
||||||
#{
|
#{
|
||||||
name => listener_id,
|
name => listener_id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of listener",
|
description => "Listener id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -618,7 +667,7 @@ move_authenticator_api_spec2() ->
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -627,15 +676,14 @@ move_authenticator_api_spec2() ->
|
||||||
]
|
]
|
||||||
}.
|
}.
|
||||||
|
|
||||||
import_users_api() ->
|
import_users_api_spec() ->
|
||||||
Metadata = #{
|
#{
|
||||||
post => #{
|
|
||||||
description => "Import users from json/csv file",
|
description => "Import users from json/csv file",
|
||||||
parameters => [
|
parameters => [
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -664,19 +712,41 @@ import_users_api() ->
|
||||||
<<"400">> => ?ERR_RESPONSE(<<"Bad Request">>),
|
<<"400">> => ?ERR_RESPONSE(<<"Bad Request">>),
|
||||||
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
||||||
}
|
}
|
||||||
}
|
}.
|
||||||
},
|
|
||||||
{"/authentication/:id/import_users", Metadata, import_users}.
|
|
||||||
|
|
||||||
users_api() ->
|
import_users_api_spec2() ->
|
||||||
Metadata = #{
|
Spec = import_users_api_spec(),
|
||||||
post => #{
|
Spec#{
|
||||||
|
parameters => [
|
||||||
|
#{
|
||||||
|
name => listener_id,
|
||||||
|
in => path,
|
||||||
|
description => "Listener id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
},
|
||||||
|
#{
|
||||||
|
name => id,
|
||||||
|
in => path,
|
||||||
|
description => "Authenticator id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}.
|
||||||
|
|
||||||
|
create_user_api_spec() ->
|
||||||
|
#{
|
||||||
description => "Add user",
|
description => "Add user",
|
||||||
parameters => [
|
parameters => [
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -696,7 +766,7 @@ users_api() ->
|
||||||
password => #{
|
password => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
superuser => #{
|
is_superuser => #{
|
||||||
type => boolean,
|
type => boolean,
|
||||||
default => false
|
default => false
|
||||||
}
|
}
|
||||||
|
@ -716,7 +786,7 @@ users_api() ->
|
||||||
user_id => #{
|
user_id => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
superuser => #{
|
is_superuser => #{
|
||||||
type => boolean
|
type => boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -727,14 +797,41 @@ users_api() ->
|
||||||
<<"400">> => ?ERR_RESPONSE(<<"Bad Request">>),
|
<<"400">> => ?ERR_RESPONSE(<<"Bad Request">>),
|
||||||
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
||||||
}
|
}
|
||||||
|
}.
|
||||||
|
|
||||||
|
create_user_api_spec2() ->
|
||||||
|
Spec = create_user_api_spec(),
|
||||||
|
Spec#{
|
||||||
|
parameters => [
|
||||||
|
#{
|
||||||
|
name => listener_id,
|
||||||
|
in => path,
|
||||||
|
description => "Listener id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
},
|
},
|
||||||
get => #{
|
required => true
|
||||||
|
},
|
||||||
|
#{
|
||||||
|
name => id,
|
||||||
|
in => path,
|
||||||
|
description => "Authenticator id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}.
|
||||||
|
|
||||||
|
list_users_api_spec() ->
|
||||||
|
#{
|
||||||
description => "List users",
|
description => "List users",
|
||||||
parameters => [
|
parameters => [
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -754,7 +851,7 @@ users_api() ->
|
||||||
user_id => #{
|
user_id => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
superuser => #{
|
is_superuser => #{
|
||||||
type => boolean
|
type => boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -765,19 +862,41 @@ users_api() ->
|
||||||
},
|
},
|
||||||
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
||||||
}
|
}
|
||||||
}
|
}.
|
||||||
},
|
|
||||||
{"/authentication/:id/users", Metadata, users}.
|
|
||||||
|
|
||||||
users2_api() ->
|
list_users_api_spec2() ->
|
||||||
Metadata = #{
|
Spec = list_users_api_spec(),
|
||||||
patch => #{
|
Spec#{
|
||||||
|
parameters => [
|
||||||
|
#{
|
||||||
|
name => listener_id,
|
||||||
|
in => path,
|
||||||
|
description => "Listener id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
},
|
||||||
|
#{
|
||||||
|
name => id,
|
||||||
|
in => path,
|
||||||
|
description => "Authenticator id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}.
|
||||||
|
|
||||||
|
update_user_api_spec() ->
|
||||||
|
#{
|
||||||
description => "Update user",
|
description => "Update user",
|
||||||
parameters => [
|
parameters => [
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -786,6 +905,7 @@ users2_api() ->
|
||||||
#{
|
#{
|
||||||
name => user_id,
|
name => user_id,
|
||||||
in => path,
|
in => path,
|
||||||
|
description => "User id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -801,7 +921,7 @@ users2_api() ->
|
||||||
password => #{
|
password => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
superuser => #{
|
is_superuser => #{
|
||||||
type => boolean
|
type => boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -822,7 +942,7 @@ users2_api() ->
|
||||||
user_id => #{
|
user_id => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
superuser => #{
|
is_superuser => #{
|
||||||
type => boolean
|
type => boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -834,14 +954,25 @@ users2_api() ->
|
||||||
<<"400">> => ?ERR_RESPONSE(<<"Bad Request">>),
|
<<"400">> => ?ERR_RESPONSE(<<"Bad Request">>),
|
||||||
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
||||||
}
|
}
|
||||||
},
|
}.
|
||||||
get => #{
|
|
||||||
description => "Get user info",
|
update_user_api_spec2() ->
|
||||||
|
Spec = update_user_api_spec(),
|
||||||
|
Spec#{
|
||||||
parameters => [
|
parameters => [
|
||||||
|
#{
|
||||||
|
name => listener_id,
|
||||||
|
in => path,
|
||||||
|
description => "Listener id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
},
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -850,6 +981,32 @@ users2_api() ->
|
||||||
#{
|
#{
|
||||||
name => user_id,
|
name => user_id,
|
||||||
in => path,
|
in => path,
|
||||||
|
description => "User id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}.
|
||||||
|
|
||||||
|
find_user_api_spec() ->
|
||||||
|
#{
|
||||||
|
description => "Get user info",
|
||||||
|
parameters => [
|
||||||
|
#{
|
||||||
|
name => id,
|
||||||
|
in => path,
|
||||||
|
description => "Authenticator id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
},
|
||||||
|
#{
|
||||||
|
name => user_id,
|
||||||
|
in => path,
|
||||||
|
description => "User id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -869,7 +1026,7 @@ users2_api() ->
|
||||||
user_id => #{
|
user_id => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
superuser => #{
|
is_superuser => #{
|
||||||
type => boolean
|
type => boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -880,14 +1037,25 @@ users2_api() ->
|
||||||
},
|
},
|
||||||
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
||||||
}
|
}
|
||||||
},
|
}.
|
||||||
delete => #{
|
|
||||||
description => "Delete user",
|
find_user_api_spec2() ->
|
||||||
|
Spec = find_user_api_spec(),
|
||||||
|
Spec#{
|
||||||
parameters => [
|
parameters => [
|
||||||
|
#{
|
||||||
|
name => listener_id,
|
||||||
|
in => path,
|
||||||
|
description => "Listener id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
},
|
||||||
#{
|
#{
|
||||||
name => id,
|
name => id,
|
||||||
in => path,
|
in => path,
|
||||||
description => "ID of authenticator",
|
description => "Authenticator id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -896,6 +1064,32 @@ users2_api() ->
|
||||||
#{
|
#{
|
||||||
name => user_id,
|
name => user_id,
|
||||||
in => path,
|
in => path,
|
||||||
|
description => "User id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}.
|
||||||
|
|
||||||
|
delete_user_api_spec() ->
|
||||||
|
#{
|
||||||
|
description => "Delete user",
|
||||||
|
parameters => [
|
||||||
|
#{
|
||||||
|
name => id,
|
||||||
|
in => path,
|
||||||
|
description => "Authenticator id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
},
|
||||||
|
#{
|
||||||
|
name => user_id,
|
||||||
|
in => path,
|
||||||
|
description => "User id",
|
||||||
schema => #{
|
schema => #{
|
||||||
type => string
|
type => string
|
||||||
},
|
},
|
||||||
|
@ -908,9 +1102,42 @@ users2_api() ->
|
||||||
},
|
},
|
||||||
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
<<"404">> => ?ERR_RESPONSE(<<"Not Found">>)
|
||||||
}
|
}
|
||||||
}
|
}.
|
||||||
|
|
||||||
|
delete_user_api_spec2() ->
|
||||||
|
Spec = delete_user_api_spec(),
|
||||||
|
Spec#{
|
||||||
|
parameters => [
|
||||||
|
#{
|
||||||
|
name => listener_id,
|
||||||
|
in => path,
|
||||||
|
description => "Listener id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
},
|
},
|
||||||
{"/authentication/:id/users/:user_id", Metadata, users2}.
|
required => true
|
||||||
|
},
|
||||||
|
#{
|
||||||
|
name => id,
|
||||||
|
in => path,
|
||||||
|
description => "Authenticator id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
},
|
||||||
|
#{
|
||||||
|
name => user_id,
|
||||||
|
in => path,
|
||||||
|
description => "User id",
|
||||||
|
schema => #{
|
||||||
|
type => string
|
||||||
|
},
|
||||||
|
required => true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}.
|
||||||
|
|
||||||
|
|
||||||
definitions() ->
|
definitions() ->
|
||||||
AuthenticatorConfigDef = #{
|
AuthenticatorConfigDef = #{
|
||||||
|
@ -1172,6 +1399,10 @@ definitions() ->
|
||||||
type => string,
|
type => string,
|
||||||
example => <<"salt">>
|
example => <<"salt">>
|
||||||
},
|
},
|
||||||
|
is_superuser_field => #{
|
||||||
|
type => string,
|
||||||
|
example => <<"is_superuser">>
|
||||||
|
},
|
||||||
password_hash_algorithm => #{
|
password_hash_algorithm => #{
|
||||||
type => string,
|
type => string,
|
||||||
enum => [<<"plain">>, <<"md5">>, <<"sha">>, <<"sha256">>, <<"sha512">>, <<"bcrypt">>],
|
enum => [<<"plain">>, <<"md5">>, <<"sha">>, <<"sha256">>, <<"sha512">>, <<"bcrypt">>],
|
||||||
|
@ -1536,71 +1767,54 @@ move2(post, #{bindings := #{listener_id := ListenerID, id := AuthenticatorID}, b
|
||||||
move2(post, #{bindings := #{listener_id := _, id := _}, body := _}) ->
|
move2(post, #{bindings := #{listener_id := _, id := _}, body := _}) ->
|
||||||
serialize_error({missing_parameter, position}).
|
serialize_error({missing_parameter, position}).
|
||||||
|
|
||||||
import_users(post, #{bindings := #{id := AuthenticatorID}, body := Body}) ->
|
import_users(post, #{bindings := #{id := AuthenticatorID}, body := #{<<"filename">> := Filename}}) ->
|
||||||
case Body of
|
|
||||||
#{<<"filename">> := Filename} ->
|
|
||||||
case ?AUTHN:import_users(?GLOBAL, AuthenticatorID, Filename) of
|
case ?AUTHN:import_users(?GLOBAL, AuthenticatorID, Filename) of
|
||||||
ok -> {204};
|
ok -> {204};
|
||||||
{error, Reason} -> serialize_error(Reason)
|
{error, Reason} -> serialize_error(Reason)
|
||||||
end;
|
end;
|
||||||
_ ->
|
import_users(post, #{bindings := #{id := _}, body := _}) ->
|
||||||
serialize_error({missing_parameter, filename})
|
serialize_error({missing_parameter, filename}).
|
||||||
end.
|
|
||||||
|
import_users2(post, #{bindings := #{listener_id := ListenerID, id := AuthenticatorID}, body := #{<<"filename">> := Filename}}) ->
|
||||||
|
case ?AUTHN:import_users(ListenerID, AuthenticatorID, Filename) of
|
||||||
|
ok -> {204};
|
||||||
|
{error, Reason} -> serialize_error(Reason)
|
||||||
|
end;
|
||||||
|
import_users2(post, #{bindings := #{listener_id := _, id := _}, body := _}) ->
|
||||||
|
serialize_error({missing_parameter, filename}).
|
||||||
|
|
||||||
users(post, #{bindings := #{id := AuthenticatorID}, body := UserInfo}) ->
|
users(post, #{bindings := #{id := AuthenticatorID}, body := UserInfo}) ->
|
||||||
case UserInfo of
|
add_user(?GLOBAL, AuthenticatorID, UserInfo);
|
||||||
#{ <<"user_id">> := UserID, <<"password">> := Password} ->
|
|
||||||
Superuser = maps:get(<<"superuser">>, UserInfo, false),
|
|
||||||
case ?AUTHN:add_user(?GLOBAL, AuthenticatorID, #{ user_id => UserID
|
|
||||||
, password => Password
|
|
||||||
, superuser => Superuser}) of
|
|
||||||
{ok, User} ->
|
|
||||||
{201, User};
|
|
||||||
{error, Reason} ->
|
|
||||||
serialize_error(Reason)
|
|
||||||
end;
|
|
||||||
#{<<"user_id">> := _} ->
|
|
||||||
serialize_error({missing_parameter, password});
|
|
||||||
_ ->
|
|
||||||
serialize_error({missing_parameter, user_id})
|
|
||||||
end;
|
|
||||||
users(get, #{bindings := #{id := AuthenticatorID}}) ->
|
users(get, #{bindings := #{id := AuthenticatorID}}) ->
|
||||||
case ?AUTHN:list_users(?GLOBAL, AuthenticatorID) of
|
list_users(?GLOBAL, AuthenticatorID).
|
||||||
{ok, Users} ->
|
|
||||||
{200, Users};
|
|
||||||
{error, Reason} ->
|
|
||||||
serialize_error(Reason)
|
|
||||||
end.
|
|
||||||
|
|
||||||
users2(patch, #{bindings := #{id := AuthenticatorID,
|
users2(put, #{bindings := #{id := AuthenticatorID,
|
||||||
user_id := UserID},
|
user_id := UserID}, body := UserInfo}) ->
|
||||||
body := UserInfo}) ->
|
update_user(?GLOBAL, AuthenticatorID, UserID, UserInfo);
|
||||||
NUserInfo = maps:with([<<"password">>, <<"superuser">>], UserInfo),
|
|
||||||
case NUserInfo =:= #{} of
|
|
||||||
true ->
|
|
||||||
serialize_error({missing_parameter, password});
|
|
||||||
false ->
|
|
||||||
case ?AUTHN:update_user(?GLOBAL, AuthenticatorID, UserID, UserInfo) of
|
|
||||||
{ok, User} ->
|
|
||||||
{200, User};
|
|
||||||
{error, Reason} ->
|
|
||||||
serialize_error(Reason)
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
users2(get, #{bindings := #{id := AuthenticatorID, user_id := UserID}}) ->
|
users2(get, #{bindings := #{id := AuthenticatorID, user_id := UserID}}) ->
|
||||||
case ?AUTHN:lookup_user(?GLOBAL, AuthenticatorID, UserID) of
|
find_user(?GLOBAL, AuthenticatorID, UserID);
|
||||||
{ok, User} ->
|
|
||||||
{200, User};
|
|
||||||
{error, Reason} ->
|
|
||||||
serialize_error(Reason)
|
|
||||||
end;
|
|
||||||
users2(delete, #{bindings := #{id := AuthenticatorID, user_id := UserID}}) ->
|
users2(delete, #{bindings := #{id := AuthenticatorID, user_id := UserID}}) ->
|
||||||
case ?AUTHN:delete_user(?GLOBAL, AuthenticatorID, UserID) of
|
delete_user(?GLOBAL, AuthenticatorID, UserID).
|
||||||
ok ->
|
|
||||||
{204};
|
users3(post, #{bindings := #{listener_id := ListenerID,
|
||||||
{error, Reason} ->
|
id := AuthenticatorID}, body := UserInfo}) ->
|
||||||
serialize_error(Reason)
|
add_user(ListenerID, AuthenticatorID, UserInfo);
|
||||||
end.
|
users3(get, #{bindings := #{listener_id := ListenerID,
|
||||||
|
id := AuthenticatorID}}) ->
|
||||||
|
list_users(ListenerID, AuthenticatorID).
|
||||||
|
|
||||||
|
users4(put, #{bindings := #{listener_id := ListenerID,
|
||||||
|
id := AuthenticatorID,
|
||||||
|
user_id := UserID}, body := UserInfo}) ->
|
||||||
|
update_user(ListenerID, AuthenticatorID, UserID, UserInfo);
|
||||||
|
users4(get, #{bindings := #{listener_id := ListenerID,
|
||||||
|
id := AuthenticatorID,
|
||||||
|
user_id := UserID}}) ->
|
||||||
|
find_user(ListenerID, AuthenticatorID, UserID);
|
||||||
|
users4(delete, #{bindings := #{listener_id := ListenerID,
|
||||||
|
id := AuthenticatorID,
|
||||||
|
user_id := UserID}}) ->
|
||||||
|
delete_user(ListenerID, AuthenticatorID, UserID).
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
|
@ -1615,7 +1829,8 @@ find_listener(ListenerID) ->
|
||||||
{ok, {Type, Name}}
|
{ok, {Type, Name}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
create_authenticator(ConfKeyPath, ChainName, Config) ->
|
create_authenticator(ConfKeyPath, ChainName0, Config) ->
|
||||||
|
ChainName = to_atom(ChainName0),
|
||||||
case update_config(ConfKeyPath, {create_authenticator, ChainName, Config}) of
|
case update_config(ConfKeyPath, {create_authenticator, ChainName, Config}) of
|
||||||
{ok, #{post_config_update := #{?AUTHN := #{id := ID}},
|
{ok, #{post_config_update := #{?AUTHN := #{id := ID}},
|
||||||
raw_config := AuthenticatorsConfig}} ->
|
raw_config := AuthenticatorsConfig}} ->
|
||||||
|
@ -1640,7 +1855,8 @@ list_authenticator(ConfKeyPath, AuthenticatorID) ->
|
||||||
serialize_error(Reason)
|
serialize_error(Reason)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
update_authenticator(ConfKeyPath, ChainName, AuthenticatorID, Config) ->
|
update_authenticator(ConfKeyPath, ChainName0, AuthenticatorID, Config) ->
|
||||||
|
ChainName = to_atom(ChainName0),
|
||||||
case update_config(ConfKeyPath,
|
case update_config(ConfKeyPath,
|
||||||
{update_authenticator, ChainName, AuthenticatorID, Config}) of
|
{update_authenticator, ChainName, AuthenticatorID, Config}) of
|
||||||
{ok, #{post_config_update := #{?AUTHN := #{id := ID}},
|
{ok, #{post_config_update := #{?AUTHN := #{id := ID}},
|
||||||
|
@ -1651,7 +1867,8 @@ update_authenticator(ConfKeyPath, ChainName, AuthenticatorID, Config) ->
|
||||||
serialize_error(Reason)
|
serialize_error(Reason)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
delete_authenticator(ConfKeyPath, ChainName, AuthenticatorID) ->
|
delete_authenticator(ConfKeyPath, ChainName0, AuthenticatorID) ->
|
||||||
|
ChainName = to_atom(ChainName0),
|
||||||
case update_config(ConfKeyPath, {delete_authenticator, ChainName, AuthenticatorID}) of
|
case update_config(ConfKeyPath, {delete_authenticator, ChainName, AuthenticatorID}) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
{204};
|
{204};
|
||||||
|
@ -1659,7 +1876,8 @@ delete_authenticator(ConfKeyPath, ChainName, AuthenticatorID) ->
|
||||||
serialize_error(Reason)
|
serialize_error(Reason)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
move_authenitcator(ConfKeyPath, ChainName, AuthenticatorID, Position) ->
|
move_authenitcator(ConfKeyPath, ChainName0, AuthenticatorID, Position) ->
|
||||||
|
ChainName = to_atom(ChainName0),
|
||||||
case update_config(ConfKeyPath, {move_authenticator, ChainName, AuthenticatorID, Position}) of
|
case update_config(ConfKeyPath, {move_authenticator, ChainName, AuthenticatorID, Position}) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
{204};
|
{204};
|
||||||
|
@ -1667,6 +1885,63 @@ move_authenitcator(ConfKeyPath, ChainName, AuthenticatorID, Position) ->
|
||||||
serialize_error(Reason)
|
serialize_error(Reason)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
add_user(ChainName0, AuthenticatorID, #{<<"user_id">> := UserID, <<"password">> := Password} = UserInfo) ->
|
||||||
|
ChainName = to_atom(ChainName0),
|
||||||
|
IsSuperuser = maps:get(<<"is_superuser">>, UserInfo, false),
|
||||||
|
case ?AUTHN:add_user(ChainName, AuthenticatorID, #{ user_id => UserID
|
||||||
|
, password => Password
|
||||||
|
, is_superuser => IsSuperuser}) of
|
||||||
|
{ok, User} ->
|
||||||
|
{201, User};
|
||||||
|
{error, Reason} ->
|
||||||
|
serialize_error(Reason)
|
||||||
|
end;
|
||||||
|
add_user(_, _, #{<<"user_id">> := _}) ->
|
||||||
|
serialize_error({missing_parameter, password});
|
||||||
|
add_user(_, _, _) ->
|
||||||
|
serialize_error({missing_parameter, user_id}).
|
||||||
|
|
||||||
|
update_user(ChainName0, AuthenticatorID, UserID, UserInfo) ->
|
||||||
|
ChainName = to_atom(ChainName0),
|
||||||
|
case maps:with([<<"password">>, <<"is_superuser">>], UserInfo) =:= #{} of
|
||||||
|
true ->
|
||||||
|
serialize_error({missing_parameter, password});
|
||||||
|
false ->
|
||||||
|
case ?AUTHN:update_user(ChainName, AuthenticatorID, UserID, UserInfo) of
|
||||||
|
{ok, User} ->
|
||||||
|
{200, User};
|
||||||
|
{error, Reason} ->
|
||||||
|
serialize_error(Reason)
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
find_user(ChainName0, AuthenticatorID, UserID) ->
|
||||||
|
ChainName = to_atom(ChainName0),
|
||||||
|
case ?AUTHN:lookup_user(ChainName, AuthenticatorID, UserID) of
|
||||||
|
{ok, User} ->
|
||||||
|
{200, User};
|
||||||
|
{error, Reason} ->
|
||||||
|
serialize_error(Reason)
|
||||||
|
end.
|
||||||
|
|
||||||
|
delete_user(ChainName0, AuthenticatorID, UserID) ->
|
||||||
|
ChainName = to_atom(ChainName0),
|
||||||
|
case ?AUTHN:delete_user(ChainName, AuthenticatorID, UserID) of
|
||||||
|
ok ->
|
||||||
|
{204};
|
||||||
|
{error, Reason} ->
|
||||||
|
serialize_error(Reason)
|
||||||
|
end.
|
||||||
|
|
||||||
|
list_users(ChainName0, AuthenticatorID) ->
|
||||||
|
ChainName = to_atom(ChainName0),
|
||||||
|
case ?AUTHN:list_users(ChainName, AuthenticatorID) of
|
||||||
|
{ok, Users} ->
|
||||||
|
{200, Users};
|
||||||
|
{error, Reason} ->
|
||||||
|
serialize_error(Reason)
|
||||||
|
end.
|
||||||
|
|
||||||
update_config(Path, ConfigRequest) ->
|
update_config(Path, ConfigRequest) ->
|
||||||
emqx:update_config(Path, ConfigRequest, #{rawconf_with_defaults => true}).
|
emqx:update_config(Path, ConfigRequest, #{rawconf_with_defaults => true}).
|
||||||
|
|
||||||
|
@ -1692,9 +1967,11 @@ serialize_error({not_found, {authenticator, ID}}) ->
|
||||||
serialize_error({not_found, {listener, ID}}) ->
|
serialize_error({not_found, {listener, ID}}) ->
|
||||||
{404, #{code => <<"NOT_FOUND">>,
|
{404, #{code => <<"NOT_FOUND">>,
|
||||||
message => list_to_binary(io_lib:format("Listener '~s' does not exist", [ID]))}};
|
message => list_to_binary(io_lib:format("Listener '~s' does not exist", [ID]))}};
|
||||||
serialize_error(name_has_be_used) ->
|
serialize_error({already_exists, {authenticator, ID}}) ->
|
||||||
{409, #{code => <<"ALREADY_EXISTS">>,
|
{409, #{code => <<"ALREADY_EXISTS">>,
|
||||||
message => <<"Name has be used">>}};
|
message => list_to_binary(
|
||||||
|
io_lib:format("Authenticator '~s' already exist", [ID])
|
||||||
|
)}};
|
||||||
serialize_error({missing_parameter, Name}) ->
|
serialize_error({missing_parameter, Name}) ->
|
||||||
{400, #{code => <<"MISSING_PARAMETER">>,
|
{400, #{code => <<"MISSING_PARAMETER">>,
|
||||||
message => list_to_binary(
|
message => list_to_binary(
|
||||||
|
@ -1707,9 +1984,14 @@ serialize_error({invalid_parameter, Name}) ->
|
||||||
)}};
|
)}};
|
||||||
serialize_error(Reason) ->
|
serialize_error(Reason) ->
|
||||||
{400, #{code => <<"BAD_REQUEST">>,
|
{400, #{code => <<"BAD_REQUEST">>,
|
||||||
message => list_to_binary(io_lib:format("Todo: ~p", [Reason]))}}.
|
message => list_to_binary(io_lib:format("~p", [Reason]))}}.
|
||||||
|
|
||||||
to_list(M) when is_map(M) ->
|
to_list(M) when is_map(M) ->
|
||||||
[M];
|
[M];
|
||||||
to_list(L) when is_list(L) ->
|
to_list(L) when is_list(L) ->
|
||||||
L.
|
L.
|
||||||
|
|
||||||
|
to_atom(B) when is_binary(B) ->
|
||||||
|
binary_to_atom(B);
|
||||||
|
to_atom(A) when is_atom(A) ->
|
||||||
|
A.
|
|
@ -53,7 +53,7 @@ remove_providers() ->
|
||||||
initialize() ->
|
initialize() ->
|
||||||
?AUTHN:initialize_authentication(?GLOBAL, emqx:get_raw_config([authentication], [])),
|
?AUTHN:initialize_authentication(?GLOBAL, emqx:get_raw_config([authentication], [])),
|
||||||
lists:foreach(fun({ListenerID, ListenerConfig}) ->
|
lists:foreach(fun({ListenerID, ListenerConfig}) ->
|
||||||
?AUTHN:initialize_authentication(atom_to_binary(ListenerID), maps:get(authentication, ListenerConfig, []))
|
?AUTHN:initialize_authentication(ListenerID, maps:get(authentication, ListenerConfig, []))
|
||||||
end, emqx_listeners:list()),
|
end, emqx_listeners:list()),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
, stored_key
|
, stored_key
|
||||||
, server_key
|
, server_key
|
||||||
, salt
|
, salt
|
||||||
, superuser
|
, is_superuser
|
||||||
}).
|
}).
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
@ -147,9 +147,9 @@ add_user(#{user_id := UserID,
|
||||||
fun() ->
|
fun() ->
|
||||||
case mnesia:read(?TAB, {UserGroup, UserID}, write) of
|
case mnesia:read(?TAB, {UserGroup, UserID}, write) of
|
||||||
[] ->
|
[] ->
|
||||||
Superuser = maps:get(superuser, UserInfo, false),
|
IsSuperuser = maps:get(is_superuser, UserInfo, false),
|
||||||
add_user(UserID, Password, Superuser, State),
|
add_user(UserID, Password, IsSuperuser, State),
|
||||||
{ok, #{user_id => UserID, superuser => Superuser}};
|
{ok, #{user_id => UserID, is_superuser => IsSuperuser}};
|
||||||
[_] ->
|
[_] ->
|
||||||
{error, already_exist}
|
{error, already_exist}
|
||||||
end
|
end
|
||||||
|
@ -173,8 +173,8 @@ update_user(UserID, User,
|
||||||
case mnesia:read(?TAB, {UserGroup, UserID}, write) of
|
case mnesia:read(?TAB, {UserGroup, UserID}, write) of
|
||||||
[] ->
|
[] ->
|
||||||
{error, not_found};
|
{error, not_found};
|
||||||
[#user_info{superuser = Superuser} = UserInfo] ->
|
[#user_info{is_superuser = IsSuperuser} = UserInfo] ->
|
||||||
UserInfo1 = UserInfo#user_info{superuser = maps:get(superuser, User, Superuser)},
|
UserInfo1 = UserInfo#user_info{is_superuser = maps:get(is_superuser, User, IsSuperuser)},
|
||||||
UserInfo2 = case maps:get(password, User, undefined) of
|
UserInfo2 = case maps:get(password, User, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
UserInfo1;
|
UserInfo1;
|
||||||
|
@ -229,24 +229,24 @@ check_client_first_message(Bin, _Cache, #{iteration_count := IterationCount} = S
|
||||||
{error, not_authorized}
|
{error, not_authorized}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
check_client_final_message(Bin, #{superuser := Superuser} = Cache, #{algorithm := Alg}) ->
|
check_client_final_message(Bin, #{is_superuser := IsSuperuser} = Cache, #{algorithm := Alg}) ->
|
||||||
case esasl_scram:check_client_final_message(
|
case esasl_scram:check_client_final_message(
|
||||||
Bin,
|
Bin,
|
||||||
Cache#{algorithm => Alg}
|
Cache#{algorithm => Alg}
|
||||||
) of
|
) of
|
||||||
{ok, ServerFinalMessage} ->
|
{ok, ServerFinalMessage} ->
|
||||||
{ok, #{superuser => Superuser}, ServerFinalMessage};
|
{ok, #{is_superuser => IsSuperuser}, ServerFinalMessage};
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
{error, not_authorized}
|
{error, not_authorized}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
add_user(UserID, Password, Superuser, State) ->
|
add_user(UserID, Password, IsSuperuser, State) ->
|
||||||
{StoredKey, ServerKey, Salt} = esasl_scram:generate_authentication_info(Password, State),
|
{StoredKey, ServerKey, Salt} = esasl_scram:generate_authentication_info(Password, State),
|
||||||
UserInfo = #user_info{user_id = UserID,
|
UserInfo = #user_info{user_id = UserID,
|
||||||
stored_key = StoredKey,
|
stored_key = StoredKey,
|
||||||
server_key = ServerKey,
|
server_key = ServerKey,
|
||||||
salt = Salt,
|
salt = Salt,
|
||||||
superuser = Superuser},
|
is_superuser = IsSuperuser},
|
||||||
mnesia:write(?TAB, UserInfo, write).
|
mnesia:write(?TAB, UserInfo, write).
|
||||||
|
|
||||||
retrieve(UserID, #{user_group := UserGroup}) ->
|
retrieve(UserID, #{user_group := UserGroup}) ->
|
||||||
|
@ -254,11 +254,11 @@ retrieve(UserID, #{user_group := UserGroup}) ->
|
||||||
[#user_info{stored_key = StoredKey,
|
[#user_info{stored_key = StoredKey,
|
||||||
server_key = ServerKey,
|
server_key = ServerKey,
|
||||||
salt = Salt,
|
salt = Salt,
|
||||||
superuser = Superuser}] ->
|
is_superuser = IsSuperuser}] ->
|
||||||
{ok, #{stored_key => StoredKey,
|
{ok, #{stored_key => StoredKey,
|
||||||
server_key => ServerKey,
|
server_key => ServerKey,
|
||||||
salt => Salt,
|
salt => Salt,
|
||||||
superuser => Superuser}};
|
is_superuser => IsSuperuser}};
|
||||||
[] ->
|
[] ->
|
||||||
{error, not_found}
|
{error, not_found}
|
||||||
end.
|
end.
|
||||||
|
@ -273,5 +273,5 @@ trans(Fun, Args) ->
|
||||||
{aborted, Reason} -> {error, Reason}
|
{aborted, Reason} -> {error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
serialize_user_info(#user_info{user_id = {_, UserID}, superuser = Superuser}) ->
|
serialize_user_info(#user_info{user_id = {_, UserID}, is_superuser = IsSuperuser}) ->
|
||||||
#{user_id => UserID, superuser => Superuser}.
|
#{user_id => UserID, is_superuser => IsSuperuser}.
|
||||||
|
|
|
@ -161,16 +161,16 @@ authenticate(Credential, #{'_unique' := Unique,
|
||||||
try
|
try
|
||||||
Request = generate_request(Credential, State),
|
Request = generate_request(Credential, State),
|
||||||
case emqx_resource:query(Unique, {Method, Request, RequestTimeout}) of
|
case emqx_resource:query(Unique, {Method, Request, RequestTimeout}) of
|
||||||
{ok, 204, _Headers} -> {ok, #{superuser => false}};
|
{ok, 204, _Headers} -> {ok, #{is_superuser => false}};
|
||||||
{ok, 200, Headers, Body} ->
|
{ok, 200, Headers, Body} ->
|
||||||
ContentType = proplists:get_value(<<"content-type">>, Headers, <<"application/json">>),
|
ContentType = proplists:get_value(<<"content-type">>, Headers, <<"application/json">>),
|
||||||
case safely_parse_body(ContentType, Body) of
|
case safely_parse_body(ContentType, Body) of
|
||||||
{ok, NBody} ->
|
{ok, NBody} ->
|
||||||
%% TODO: Return by user property
|
%% TODO: Return by user property
|
||||||
{ok, #{superuser => maps:get(<<"superuser">>, NBody, false),
|
{ok, #{is_superuser => maps:get(<<"is_superuser">>, NBody, false),
|
||||||
user_property => NBody}};
|
user_property => NBody}};
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
{ok, #{superuser => false}}
|
{ok, #{is_superuser => false}}
|
||||||
end;
|
end;
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
ignore
|
ignore
|
||||||
|
|
|
@ -249,7 +249,7 @@ verify(JWS, [JWK | More], VerifyClaims) ->
|
||||||
Claims = emqx_json:decode(Payload, [return_maps]),
|
Claims = emqx_json:decode(Payload, [return_maps]),
|
||||||
case verify_claims(Claims, VerifyClaims) of
|
case verify_claims(Claims, VerifyClaims) of
|
||||||
ok ->
|
ok ->
|
||||||
{ok, #{superuser => maps:get(<<"superuser">>, Claims, false)}};
|
{ok, #{is_superuser => maps:get(<<"is_superuser">>, Claims, false)}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
{ user_id :: {user_group(), user_id()}
|
{ user_id :: {user_group(), user_id()}
|
||||||
, password_hash :: binary()
|
, password_hash :: binary()
|
||||||
, salt :: binary()
|
, salt :: binary()
|
||||||
, superuser :: boolean()
|
, is_superuser :: boolean()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-reflect_type([ user_id_type/0 ]).
|
-reflect_type([ user_id_type/0 ]).
|
||||||
|
@ -158,13 +158,13 @@ authenticate(#{password := Password} = Credential,
|
||||||
case mnesia:dirty_read(?TAB, {UserGroup, UserID}) of
|
case mnesia:dirty_read(?TAB, {UserGroup, UserID}) of
|
||||||
[] ->
|
[] ->
|
||||||
ignore;
|
ignore;
|
||||||
[#user_info{password_hash = PasswordHash, salt = Salt0, superuser = Superuser}] ->
|
[#user_info{password_hash = PasswordHash, salt = Salt0, is_superuser = IsSuperuser}] ->
|
||||||
Salt = case Algorithm of
|
Salt = case Algorithm of
|
||||||
bcrypt -> PasswordHash;
|
bcrypt -> PasswordHash;
|
||||||
_ -> Salt0
|
_ -> Salt0
|
||||||
end,
|
end,
|
||||||
case PasswordHash =:= hash(Algorithm, Password, Salt) of
|
case PasswordHash =:= hash(Algorithm, Password, Salt) of
|
||||||
true -> {ok, #{superuser => Superuser}};
|
true -> {ok, #{is_superuser => IsSuperuser}};
|
||||||
false -> {error, bad_username_or_password}
|
false -> {error, bad_username_or_password}
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
@ -197,9 +197,9 @@ add_user(#{user_id := UserID,
|
||||||
case mnesia:read(?TAB, {UserGroup, UserID}, write) of
|
case mnesia:read(?TAB, {UserGroup, UserID}, write) of
|
||||||
[] ->
|
[] ->
|
||||||
{PasswordHash, Salt} = hash(Password, State),
|
{PasswordHash, Salt} = hash(Password, State),
|
||||||
Superuser = maps:get(superuser, UserInfo, false),
|
IsSuperuser = maps:get(is_superuser, UserInfo, false),
|
||||||
insert_user(UserGroup, UserID, PasswordHash, Salt, Superuser),
|
insert_user(UserGroup, UserID, PasswordHash, Salt, IsSuperuser),
|
||||||
{ok, #{user_id => UserID, superuser => Superuser}};
|
{ok, #{user_id => UserID, is_superuser => IsSuperuser}};
|
||||||
[_] ->
|
[_] ->
|
||||||
{error, already_exist}
|
{error, already_exist}
|
||||||
end
|
end
|
||||||
|
@ -225,8 +225,8 @@ update_user(UserID, UserInfo,
|
||||||
{error, not_found};
|
{error, not_found};
|
||||||
[#user_info{ password_hash = PasswordHash
|
[#user_info{ password_hash = PasswordHash
|
||||||
, salt = Salt
|
, salt = Salt
|
||||||
, superuser = Superuser}] ->
|
, is_superuser = IsSuperuser}] ->
|
||||||
NSuperuser = maps:get(superuser, UserInfo, Superuser),
|
NSuperuser = maps:get(is_superuser, UserInfo, IsSuperuser),
|
||||||
{NPasswordHash, NSalt} = case maps:get(password, UserInfo, undefined) of
|
{NPasswordHash, NSalt} = case maps:get(password, UserInfo, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{PasswordHash, Salt};
|
{PasswordHash, Salt};
|
||||||
|
@ -234,7 +234,7 @@ update_user(UserID, UserInfo,
|
||||||
hash(Password, State)
|
hash(Password, State)
|
||||||
end,
|
end,
|
||||||
insert_user(UserGroup, UserID, NPasswordHash, NSalt, NSuperuser),
|
insert_user(UserGroup, UserID, NPasswordHash, NSalt, NSuperuser),
|
||||||
{ok, #{user_id => UserID, superuser => NSuperuser}}
|
{ok, #{user_id => UserID, is_superuser => NSuperuser}}
|
||||||
end
|
end
|
||||||
end).
|
end).
|
||||||
|
|
||||||
|
@ -290,8 +290,8 @@ import(UserGroup, [#{<<"user_id">> := UserID,
|
||||||
<<"password_hash">> := PasswordHash} = UserInfo | More])
|
<<"password_hash">> := PasswordHash} = UserInfo | More])
|
||||||
when is_binary(UserID) andalso is_binary(PasswordHash) ->
|
when is_binary(UserID) andalso is_binary(PasswordHash) ->
|
||||||
Salt = maps:get(<<"salt">>, UserInfo, <<>>),
|
Salt = maps:get(<<"salt">>, UserInfo, <<>>),
|
||||||
Superuser = maps:get(<<"superuser">>, UserInfo, false),
|
IsSuperuser = maps:get(<<"is_superuser">>, UserInfo, false),
|
||||||
insert_user(UserGroup, UserID, PasswordHash, Salt, Superuser),
|
insert_user(UserGroup, UserID, PasswordHash, Salt, IsSuperuser),
|
||||||
import(UserGroup, More);
|
import(UserGroup, More);
|
||||||
import(_UserGroup, [_ | _More]) ->
|
import(_UserGroup, [_ | _More]) ->
|
||||||
{error, bad_format}.
|
{error, bad_format}.
|
||||||
|
@ -305,8 +305,8 @@ import(UserGroup, File, Seq) ->
|
||||||
{ok, #{user_id := UserID,
|
{ok, #{user_id := UserID,
|
||||||
password_hash := PasswordHash} = UserInfo} ->
|
password_hash := PasswordHash} = UserInfo} ->
|
||||||
Salt = maps:get(salt, UserInfo, <<>>),
|
Salt = maps:get(salt, UserInfo, <<>>),
|
||||||
Superuser = maps:get(superuser, UserInfo, false),
|
IsSuperuser = maps:get(is_superuser, UserInfo, false),
|
||||||
insert_user(UserGroup, UserID, PasswordHash, Salt, Superuser),
|
insert_user(UserGroup, UserID, PasswordHash, Salt, IsSuperuser),
|
||||||
import(UserGroup, File, Seq);
|
import(UserGroup, File, Seq);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
|
@ -341,10 +341,10 @@ get_user_info_by_seq([PasswordHash | More1], [<<"password_hash">> | More2], Acc)
|
||||||
get_user_info_by_seq(More1, More2, Acc#{password_hash => PasswordHash});
|
get_user_info_by_seq(More1, More2, Acc#{password_hash => PasswordHash});
|
||||||
get_user_info_by_seq([Salt | More1], [<<"salt">> | More2], Acc) ->
|
get_user_info_by_seq([Salt | More1], [<<"salt">> | More2], Acc) ->
|
||||||
get_user_info_by_seq(More1, More2, Acc#{salt => Salt});
|
get_user_info_by_seq(More1, More2, Acc#{salt => Salt});
|
||||||
get_user_info_by_seq([<<"true">> | More1], [<<"superuser">> | More2], Acc) ->
|
get_user_info_by_seq([<<"true">> | More1], [<<"is_superuser">> | More2], Acc) ->
|
||||||
get_user_info_by_seq(More1, More2, Acc#{superuser => true});
|
get_user_info_by_seq(More1, More2, Acc#{is_superuser => true});
|
||||||
get_user_info_by_seq([<<"false">> | More1], [<<"superuser">> | More2], Acc) ->
|
get_user_info_by_seq([<<"false">> | More1], [<<"is_superuser">> | More2], Acc) ->
|
||||||
get_user_info_by_seq(More1, More2, Acc#{superuser => false});
|
get_user_info_by_seq(More1, More2, Acc#{is_superuser => false});
|
||||||
get_user_info_by_seq(_, _, _) ->
|
get_user_info_by_seq(_, _, _) ->
|
||||||
{error, bad_format}.
|
{error, bad_format}.
|
||||||
|
|
||||||
|
@ -368,11 +368,11 @@ hash(Password, #{password_hash_algorithm := Algorithm} = State) ->
|
||||||
PasswordHash = hash(Algorithm, Password, Salt),
|
PasswordHash = hash(Algorithm, Password, Salt),
|
||||||
{PasswordHash, Salt}.
|
{PasswordHash, Salt}.
|
||||||
|
|
||||||
insert_user(UserGroup, UserID, PasswordHash, Salt, Superuser) ->
|
insert_user(UserGroup, UserID, PasswordHash, Salt, IsSuperuser) ->
|
||||||
UserInfo = #user_info{user_id = {UserGroup, UserID},
|
UserInfo = #user_info{user_id = {UserGroup, UserID},
|
||||||
password_hash = PasswordHash,
|
password_hash = PasswordHash,
|
||||||
salt = Salt,
|
salt = Salt,
|
||||||
superuser = Superuser},
|
is_superuser = IsSuperuser},
|
||||||
mnesia:write(?TAB, UserInfo, write).
|
mnesia:write(?TAB, UserInfo, write).
|
||||||
|
|
||||||
delete_user2(UserInfo) ->
|
delete_user2(UserInfo) ->
|
||||||
|
@ -400,5 +400,5 @@ to_binary(B) when is_binary(B) ->
|
||||||
to_binary(L) when is_list(L) ->
|
to_binary(L) when is_list(L) ->
|
||||||
iolist_to_binary(L).
|
iolist_to_binary(L).
|
||||||
|
|
||||||
serialize_user_info(#user_info{user_id = {_, UserID}, superuser = Superuser}) ->
|
serialize_user_info(#user_info{user_id = {_, UserID}, is_superuser = IsSuperuser}) ->
|
||||||
#{user_id => UserID, superuser => Superuser}.
|
#{user_id => UserID, is_superuser => IsSuperuser}.
|
||||||
|
|
|
@ -64,6 +64,7 @@ common_fields() ->
|
||||||
, {selector, fun selector/1}
|
, {selector, fun selector/1}
|
||||||
, {password_hash_field, fun password_hash_field/1}
|
, {password_hash_field, fun password_hash_field/1}
|
||||||
, {salt_field, fun salt_field/1}
|
, {salt_field, fun salt_field/1}
|
||||||
|
, {is_superuser_field, fun is_superuser_field/1}
|
||||||
, {password_hash_algorithm, fun password_hash_algorithm/1}
|
, {password_hash_algorithm, fun password_hash_algorithm/1}
|
||||||
, {salt_position, fun salt_position/1}
|
, {salt_position, fun salt_position/1}
|
||||||
] ++ emqx_authn_schema:common_fields().
|
] ++ emqx_authn_schema:common_fields().
|
||||||
|
@ -84,6 +85,10 @@ salt_field(type) -> binary();
|
||||||
salt_field(nullable) -> true;
|
salt_field(nullable) -> true;
|
||||||
salt_field(_) -> undefined.
|
salt_field(_) -> undefined.
|
||||||
|
|
||||||
|
is_superuser_field(type) -> binary();
|
||||||
|
is_superuser_field(nullable) -> true;
|
||||||
|
is_superuser_field(_) -> undefined.
|
||||||
|
|
||||||
password_hash_algorithm(type) -> {enum, [plain, md5, sha, sha256, sha512, bcrypt]};
|
password_hash_algorithm(type) -> {enum, [plain, md5, sha, sha256, sha512, bcrypt]};
|
||||||
password_hash_algorithm(default) -> sha256;
|
password_hash_algorithm(default) -> sha256;
|
||||||
password_hash_algorithm(_) -> undefined.
|
password_hash_algorithm(_) -> undefined.
|
||||||
|
@ -109,6 +114,7 @@ create(#{ selector := Selector
|
||||||
State = maps:with([ collection
|
State = maps:with([ collection
|
||||||
, password_hash_field
|
, password_hash_field
|
||||||
, salt_field
|
, salt_field
|
||||||
|
, is_superuser_field
|
||||||
, password_hash_algorithm
|
, password_hash_algorithm
|
||||||
, salt_position
|
, salt_position
|
||||||
, '_unique'], Config),
|
, '_unique'], Config),
|
||||||
|
@ -149,7 +155,7 @@ authenticate(#{password := Password} = Credential,
|
||||||
Doc ->
|
Doc ->
|
||||||
case check_password(Password, Doc, State) of
|
case check_password(Password, Doc, State) of
|
||||||
ok ->
|
ok ->
|
||||||
{ok, #{superuser => superuser(Doc, State)}};
|
{ok, #{is_superuser => is_superuser(Doc, State)}};
|
||||||
{error, {cannot_find_password_hash_field, PasswordHashField}} ->
|
{error, {cannot_find_password_hash_field, PasswordHashField}} ->
|
||||||
?LOG(error, "['~s'] Can't find password hash field: ~s", [Unique, PasswordHashField]),
|
?LOG(error, "['~s'] Can't find password hash field: ~s", [Unique, PasswordHashField]),
|
||||||
{error, bad_username_or_password};
|
{error, bad_username_or_password};
|
||||||
|
@ -230,9 +236,9 @@ check_password(Password,
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
superuser(Doc, #{superuser_field := SuperuserField}) ->
|
is_superuser(Doc, #{is_superuser_field := IsSuperuserField}) ->
|
||||||
maps:get(SuperuserField, Doc, false);
|
maps:get(IsSuperuserField, Doc, false);
|
||||||
superuser(_, _) ->
|
is_superuser(_, _) ->
|
||||||
false.
|
false.
|
||||||
|
|
||||||
hash(Algorithm, Password, Salt, prefix) ->
|
hash(Algorithm, Password, Salt, prefix) ->
|
||||||
|
|
|
@ -123,7 +123,7 @@ authenticate(#{password := Password} = Credential,
|
||||||
Selected = maps:from_list(lists:zip(Columns, Rows)),
|
Selected = maps:from_list(lists:zip(Columns, Rows)),
|
||||||
case check_password(Password, Selected, State) of
|
case check_password(Password, Selected, State) of
|
||||||
ok ->
|
ok ->
|
||||||
{ok, #{superuser => maps:get(<<"superuser">>, Selected, false)}};
|
{ok, #{is_superuser => maps:get(<<"is_superuser">>, Selected, false)}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -113,7 +113,7 @@ authenticate(#{password := Password} = Credential,
|
||||||
Selected = maps:from_list(lists:zip(NColumns, Rows)),
|
Selected = maps:from_list(lists:zip(NColumns, Rows)),
|
||||||
case check_password(Password, Selected, State) of
|
case check_password(Password, Selected, State) of
|
||||||
ok ->
|
ok ->
|
||||||
{ok, #{superuser => maps:get(<<"superuser">>, Selected, false)}};
|
{ok, #{is_superuser => maps:get(<<"is_superuser">>, Selected, false)}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -135,7 +135,7 @@ authenticate(#{password := Password} = Credential,
|
||||||
Selected = merge(Fields, Values),
|
Selected = merge(Fields, Values),
|
||||||
case check_password(Password, Selected, State) of
|
case check_password(Password, Selected, State) of
|
||||||
ok ->
|
ok ->
|
||||||
{ok, #{superuser => maps:get("superuser", Selected, false)}};
|
{ok, #{is_superuser => maps:get("is_superuser", Selected, false)}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end;
|
end;
|
||||||
|
@ -180,7 +180,7 @@ check_fields(["password_hash" | More], false) ->
|
||||||
check_fields(More, true);
|
check_fields(More, true);
|
||||||
check_fields(["salt" | More], HasPassHash) ->
|
check_fields(["salt" | More], HasPassHash) ->
|
||||||
check_fields(More, HasPassHash);
|
check_fields(More, HasPassHash);
|
||||||
check_fields(["superuser" | More], HasPassHash) ->
|
check_fields(["is_superuser" | More], HasPassHash) ->
|
||||||
check_fields(More, HasPassHash);
|
check_fields(More, HasPassHash);
|
||||||
check_fields([Field | _], _) ->
|
check_fields([Field | _], _) ->
|
||||||
error({unsupported_field, Field}).
|
error({unsupported_field, Field}).
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
user_id,password_hash,salt,superuser
|
user_id,password_hash,salt,is_superuser
|
||||||
myuser3,b6c743545a7817ae8c8f624371d5f5f0373234bb0ff36b8ffbf19bce0e06ab75,de1024f462fb83910fd13151bd4bd235,true
|
myuser3,b6c743545a7817ae8c8f624371d5f5f0373234bb0ff36b8ffbf19bce0e06ab75,de1024f462fb83910fd13151bd4bd235,true
|
||||||
myuser4,ee68c985a69208b6eda8c6c9b4c7c2d2b15ee2352cdd64a903171710a99182e8,ad773b5be9dd0613fe6c2f4d8c403139,false
|
myuser4,ee68c985a69208b6eda8c6c9b4c7c2d2b15ee2352cdd64a903171710a99182e8,ad773b5be9dd0613fe6c2f4d8c403139,false
|
||||||
|
|
|
|
@ -3,12 +3,12 @@
|
||||||
"user_id":"myuser1",
|
"user_id":"myuser1",
|
||||||
"password_hash":"c5e46903df45e5dc096dc74657610dbee8deaacae656df88a1788f1847390242",
|
"password_hash":"c5e46903df45e5dc096dc74657610dbee8deaacae656df88a1788f1847390242",
|
||||||
"salt": "e378187547bf2d6f0545a3f441aa4d8a",
|
"salt": "e378187547bf2d6f0545a3f441aa4d8a",
|
||||||
"superuser": true
|
"is_superuser": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"user_id":"myuser2",
|
"user_id":"myuser2",
|
||||||
"password_hash":"f4d17f300b11e522fd33f497c11b126ef1ea5149c74d2220f9a16dc876d4567b",
|
"password_hash":"f4d17f300b11e522fd33f497c11b126ef1ea5149c74d2220f9a16dc876d4567b",
|
||||||
"salt": "6d3f9bd5b54d94b98adbcfe10b6d181f",
|
"salt": "6d3f9bd5b54d94b98adbcfe10b6d181f",
|
||||||
"superuser": false
|
"is_superuser": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -52,13 +52,13 @@ all() ->
|
||||||
% JWS = generate_jws('hmac-based', Payload, <<"abcdef">>),
|
% JWS = generate_jws('hmac-based', Payload, <<"abcdef">>),
|
||||||
% ClientInfo = #{username => <<"myuser">>,
|
% ClientInfo = #{username => <<"myuser">>,
|
||||||
% password => JWS},
|
% password => JWS},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
|
||||||
|
|
||||||
% Payload1 = #{<<"username">> => <<"myuser">>, <<"superuser">> => true},
|
% Payload1 = #{<<"username">> => <<"myuser">>, <<"is_superuser">> => true},
|
||||||
% JWS1 = generate_jws('hmac-based', Payload1, <<"abcdef">>),
|
% JWS1 = generate_jws('hmac-based', Payload1, <<"abcdef">>),
|
||||||
% ClientInfo1 = #{username => <<"myuser">>,
|
% ClientInfo1 = #{username => <<"myuser">>,
|
||||||
% password => JWS1},
|
% password => JWS1},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => true}}}, ?AUTH:authenticate(ClientInfo1, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => true}}}, ?AUTH:authenticate(ClientInfo1, ignored)),
|
||||||
|
|
||||||
% BadJWS = generate_jws('hmac-based', Payload, <<"bad_secret">>),
|
% BadJWS = generate_jws('hmac-based', Payload, <<"bad_secret">>),
|
||||||
% ClientInfo2 = ClientInfo#{password => BadJWS},
|
% ClientInfo2 = ClientInfo#{password => BadJWS},
|
||||||
|
@ -68,11 +68,11 @@ all() ->
|
||||||
% Config2 = Config#{secret => base64:encode(<<"abcdef">>),
|
% Config2 = Config#{secret => base64:encode(<<"abcdef">>),
|
||||||
% secret_base64_encoded => true},
|
% secret_base64_encoded => true},
|
||||||
% ?assertMatch({ok, _}, ?AUTH:update_authenticator(?CHAIN, ID, Config2)),
|
% ?assertMatch({ok, _}, ?AUTH:update_authenticator(?CHAIN, ID, Config2)),
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
|
||||||
|
|
||||||
% Config3 = Config#{verify_claims => [{<<"username">>, <<"${mqtt-username}">>}]},
|
% Config3 = Config#{verify_claims => [{<<"username">>, <<"${mqtt-username}">>}]},
|
||||||
% ?assertMatch({ok, _}, ?AUTH:update_authenticator(?CHAIN, ID, Config3)),
|
% ?assertMatch({ok, _}, ?AUTH:update_authenticator(?CHAIN, ID, Config3)),
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
|
||||||
% ?assertEqual({stop, {error, bad_username_or_password}}, ?AUTH:authenticate(ClientInfo#{username => <<"otheruser">>}, ok)),
|
% ?assertEqual({stop, {error, bad_username_or_password}}, ?AUTH:authenticate(ClientInfo#{username => <<"otheruser">>}, ok)),
|
||||||
|
|
||||||
% %% Expiration
|
% %% Expiration
|
||||||
|
@ -86,14 +86,14 @@ all() ->
|
||||||
% , <<"exp">> => erlang:system_time(second) + 60},
|
% , <<"exp">> => erlang:system_time(second) + 60},
|
||||||
% JWS4 = generate_jws('hmac-based', Payload4, <<"abcdef">>),
|
% JWS4 = generate_jws('hmac-based', Payload4, <<"abcdef">>),
|
||||||
% ClientInfo4 = ClientInfo#{password => JWS4},
|
% ClientInfo4 = ClientInfo#{password => JWS4},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo4, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo4, ignored)),
|
||||||
|
|
||||||
% %% Issued At
|
% %% Issued At
|
||||||
% Payload5 = #{ <<"username">> => <<"myuser">>
|
% Payload5 = #{ <<"username">> => <<"myuser">>
|
||||||
% , <<"iat">> => erlang:system_time(second) - 60},
|
% , <<"iat">> => erlang:system_time(second) - 60},
|
||||||
% JWS5 = generate_jws('hmac-based', Payload5, <<"abcdef">>),
|
% JWS5 = generate_jws('hmac-based', Payload5, <<"abcdef">>),
|
||||||
% ClientInfo5 = ClientInfo#{password => JWS5},
|
% ClientInfo5 = ClientInfo#{password => JWS5},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo5, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo5, ignored)),
|
||||||
|
|
||||||
% Payload6 = #{ <<"username">> => <<"myuser">>
|
% Payload6 = #{ <<"username">> => <<"myuser">>
|
||||||
% , <<"iat">> => erlang:system_time(second) + 60},
|
% , <<"iat">> => erlang:system_time(second) + 60},
|
||||||
|
@ -106,7 +106,7 @@ all() ->
|
||||||
% , <<"nbf">> => erlang:system_time(second) - 60},
|
% , <<"nbf">> => erlang:system_time(second) - 60},
|
||||||
% JWS7 = generate_jws('hmac-based', Payload7, <<"abcdef">>),
|
% JWS7 = generate_jws('hmac-based', Payload7, <<"abcdef">>),
|
||||||
% ClientInfo7 = ClientInfo#{password => JWS7},
|
% ClientInfo7 = ClientInfo#{password => JWS7},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo7, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo7, ignored)),
|
||||||
|
|
||||||
% Payload8 = #{ <<"username">> => <<"myuser">>
|
% Payload8 = #{ <<"username">> => <<"myuser">>
|
||||||
% , <<"nbf">> => erlang:system_time(second) + 60},
|
% , <<"nbf">> => erlang:system_time(second) + 60},
|
||||||
|
@ -134,7 +134,7 @@ all() ->
|
||||||
% JWS = generate_jws('public-key', Payload, PrivateKey),
|
% JWS = generate_jws('public-key', Payload, PrivateKey),
|
||||||
% ClientInfo = #{username => <<"myuser">>,
|
% ClientInfo = #{username => <<"myuser">>,
|
||||||
% password => JWS},
|
% password => JWS},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
|
||||||
% ?assertEqual({stop, {error, not_authorized}}, ?AUTH:authenticate(ClientInfo#{password => <<"badpassword">>}, ignored)),
|
% ?assertEqual({stop, {error, not_authorized}}, ?AUTH:authenticate(ClientInfo#{password => <<"badpassword">>}, ignored)),
|
||||||
|
|
||||||
% ?assertEqual(ok, ?AUTH:delete_authenticator(?CHAIN, ID)),
|
% ?assertEqual(ok, ?AUTH:delete_authenticator(?CHAIN, ID)),
|
||||||
|
|
|
@ -56,9 +56,9 @@ all() ->
|
||||||
% ClientInfo = #{zone => external,
|
% ClientInfo = #{zone => external,
|
||||||
% username => <<"myuser">>,
|
% username => <<"myuser">>,
|
||||||
% password => <<"mypass">>},
|
% password => <<"mypass">>},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo, ignored)),
|
||||||
% ?AUTH:enable(),
|
% ?AUTH:enable(),
|
||||||
% ?assertEqual({ok, #{superuser => false}}, emqx_access_control:authenticate(ClientInfo)),
|
% ?assertEqual({ok, #{is_superuser => false}}, emqx_access_control:authenticate(ClientInfo)),
|
||||||
|
|
||||||
% ClientInfo2 = ClientInfo#{username => <<"baduser">>},
|
% ClientInfo2 = ClientInfo#{username => <<"baduser">>},
|
||||||
% ?assertEqual({stop, {error, not_authorized}}, ?AUTH:authenticate(ClientInfo2, ignored)),
|
% ?assertEqual({stop, {error, not_authorized}}, ?AUTH:authenticate(ClientInfo2, ignored)),
|
||||||
|
@ -71,10 +71,10 @@ all() ->
|
||||||
% UserInfo2 = UserInfo#{password => <<"mypass2">>},
|
% UserInfo2 = UserInfo#{password => <<"mypass2">>},
|
||||||
% ?assertMatch({ok, #{user_id := <<"myuser">>}}, ?AUTH:update_user(?CHAIN, ID, <<"myuser">>, UserInfo2)),
|
% ?assertMatch({ok, #{user_id := <<"myuser">>}}, ?AUTH:update_user(?CHAIN, ID, <<"myuser">>, UserInfo2)),
|
||||||
% ClientInfo4 = ClientInfo#{password => <<"mypass2">>},
|
% ClientInfo4 = ClientInfo#{password => <<"mypass2">>},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo4, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo4, ignored)),
|
||||||
|
|
||||||
% ?assertMatch({ok, #{user_id := <<"myuser">>}}, ?AUTH:update_user(?CHAIN, ID, <<"myuser">>, #{superuser => true})),
|
% ?assertMatch({ok, #{user_id := <<"myuser">>}}, ?AUTH:update_user(?CHAIN, ID, <<"myuser">>, #{is_superuser => true})),
|
||||||
% ?assertEqual({stop, {ok, #{superuser => true}}}, ?AUTH:authenticate(ClientInfo4, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => true}}}, ?AUTH:authenticate(ClientInfo4, ignored)),
|
||||||
|
|
||||||
% ?assertEqual(ok, ?AUTH:delete_user(?CHAIN, ID, <<"myuser">>)),
|
% ?assertEqual(ok, ?AUTH:delete_user(?CHAIN, ID, <<"myuser">>)),
|
||||||
% ?assertEqual({error, not_found}, ?AUTH:lookup_user(?CHAIN, ID, <<"myuser">>)),
|
% ?assertEqual({error, not_found}, ?AUTH:lookup_user(?CHAIN, ID, <<"myuser">>)),
|
||||||
|
@ -107,15 +107,15 @@ all() ->
|
||||||
|
|
||||||
% ClientInfo1 = #{username => <<"myuser1">>,
|
% ClientInfo1 = #{username => <<"myuser1">>,
|
||||||
% password => <<"mypassword1">>},
|
% password => <<"mypassword1">>},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => true}}}, ?AUTH:authenticate(ClientInfo1, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => true}}}, ?AUTH:authenticate(ClientInfo1, ignored)),
|
||||||
|
|
||||||
% ClientInfo2 = ClientInfo1#{username => <<"myuser2">>,
|
% ClientInfo2 = ClientInfo1#{username => <<"myuser2">>,
|
||||||
% password => <<"mypassword2">>},
|
% password => <<"mypassword2">>},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo2, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo2, ignored)),
|
||||||
|
|
||||||
% ClientInfo3 = ClientInfo1#{username => <<"myuser3">>,
|
% ClientInfo3 = ClientInfo1#{username => <<"myuser3">>,
|
||||||
% password => <<"mypassword3">>},
|
% password => <<"mypassword3">>},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => true}}}, ?AUTH:authenticate(ClientInfo3, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => true}}}, ?AUTH:authenticate(ClientInfo3, ignored)),
|
||||||
|
|
||||||
% ?assertEqual(ok, ?AUTH:delete_authenticator(?CHAIN, ID)),
|
% ?assertEqual(ok, ?AUTH:delete_authenticator(?CHAIN, ID)),
|
||||||
% ok.
|
% ok.
|
||||||
|
@ -152,12 +152,12 @@ all() ->
|
||||||
% ClientInfo1 = #{username => <<"myuser">>,
|
% ClientInfo1 = #{username => <<"myuser">>,
|
||||||
% clientid => <<"myclient">>,
|
% clientid => <<"myclient">>,
|
||||||
% password => <<"mypass1">>},
|
% password => <<"mypass1">>},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo1, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo1, ignored)),
|
||||||
% ?assertEqual(ok, ?AUTH:move_authenticator(?CHAIN, ID2, top)),
|
% ?assertEqual(ok, ?AUTH:move_authenticator(?CHAIN, ID2, top)),
|
||||||
|
|
||||||
% ?assertEqual({stop, {error, bad_username_or_password}}, ?AUTH:authenticate(ClientInfo1, ignored)),
|
% ?assertEqual({stop, {error, bad_username_or_password}}, ?AUTH:authenticate(ClientInfo1, ignored)),
|
||||||
% ClientInfo2 = ClientInfo1#{password => <<"mypass2">>},
|
% ClientInfo2 = ClientInfo1#{password => <<"mypass2">>},
|
||||||
% ?assertEqual({stop, {ok, #{superuser => false}}}, ?AUTH:authenticate(ClientInfo2, ignored)),
|
% ?assertEqual({stop, {ok, #{is_superuser => false}}}, ?AUTH:authenticate(ClientInfo2, ignored)),
|
||||||
|
|
||||||
% ?assertEqual(ok, ?AUTH:delete_authenticator(?CHAIN, ID1)),
|
% ?assertEqual(ok, ?AUTH:delete_authenticator(?CHAIN, ID1)),
|
||||||
% ?assertEqual(ok, ?AUTH:delete_authenticator(?CHAIN, ID2)),
|
% ?assertEqual(ok, ?AUTH:delete_authenticator(?CHAIN, ID2)),
|
||||||
|
|
Loading…
Reference in New Issue