|
@@ -36,6 +36,11 @@
|
|
|
, destroy/1
|
|
, destroy/1
|
|
|
]).
|
|
]).
|
|
|
|
|
|
|
|
|
|
+-ifdef(TEST).
|
|
|
|
|
+-compile(export_all).
|
|
|
|
|
+-compile(nowarn_export_all).
|
|
|
|
|
+-endif.
|
|
|
|
|
+
|
|
|
%%------------------------------------------------------------------------------
|
|
%%------------------------------------------------------------------------------
|
|
|
%% Hocon Schema
|
|
%% Hocon Schema
|
|
|
%%------------------------------------------------------------------------------
|
|
%%------------------------------------------------------------------------------
|
|
@@ -48,7 +53,7 @@ fields(config) ->
|
|
|
[ {mechanism, {enum, ['password-based']}}
|
|
[ {mechanism, {enum, ['password-based']}}
|
|
|
, {backend, {enum, [postgresql]}}
|
|
, {backend, {enum, [postgresql]}}
|
|
|
, {password_hash_algorithm, fun password_hash_algorithm/1}
|
|
, {password_hash_algorithm, fun password_hash_algorithm/1}
|
|
|
- , {salt_position, {enum, [prefix, suffix]}}
|
|
|
|
|
|
|
+ , {salt_position, fun salt_position/1}
|
|
|
, {query, fun query/1}
|
|
, {query, fun query/1}
|
|
|
] ++ emqx_authn_schema:common_fields()
|
|
] ++ emqx_authn_schema:common_fields()
|
|
|
++ emqx_connector_schema_lib:relational_db_fields()
|
|
++ emqx_connector_schema_lib:relational_db_fields()
|
|
@@ -58,6 +63,10 @@ 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.
|
|
|
|
|
|
|
|
|
|
+salt_position(type) -> {enum, [prefix, suffix]};
|
|
|
|
|
+salt_position(default) -> prefix;
|
|
|
|
|
+salt_position(_) -> undefined.
|
|
|
|
|
+
|
|
|
query(type) -> string();
|
|
query(type) -> string();
|
|
|
query(_) -> undefined.
|
|
query(_) -> undefined.
|
|
|
|
|
|
|
@@ -106,10 +115,9 @@ authenticate(#{password := Password} = Credential,
|
|
|
Params = emqx_authn_utils:replace_placeholders(PlaceHolders, Credential),
|
|
Params = emqx_authn_utils:replace_placeholders(PlaceHolders, Credential),
|
|
|
case emqx_resource:query(Unique, {sql, Query, Params}) of
|
|
case emqx_resource:query(Unique, {sql, Query, Params}) of
|
|
|
{ok, _Columns, []} -> ignore;
|
|
{ok, _Columns, []} -> ignore;
|
|
|
- {ok, Columns, Rows} ->
|
|
|
|
|
|
|
+ {ok, Columns, [Row | _]} ->
|
|
|
NColumns = [Name || #column{name = Name} <- Columns],
|
|
NColumns = [Name || #column{name = Name} <- Columns],
|
|
|
- NRows = [erlang:element(1, Row) || Row <- Rows],
|
|
|
|
|
- Selected = maps:from_list(lists:zip(NColumns, NRows)),
|
|
|
|
|
|
|
+ Selected = maps:from_list(lists:zip(NColumns, erlang:tuple_to_list(Row))),
|
|
|
case emqx_authn_utils:check_password(Password, Selected, State) of
|
|
case emqx_authn_utils:check_password(Password, Selected, State) of
|
|
|
ok ->
|
|
ok ->
|
|
|
{ok, emqx_authn_utils:is_superuser(Selected)};
|
|
{ok, emqx_authn_utils:is_superuser(Selected)};
|
|
@@ -138,7 +146,7 @@ parse_query(Query) ->
|
|
|
PlaceHolders = [PlaceHolder || [PlaceHolder] <- Captured],
|
|
PlaceHolders = [PlaceHolder || [PlaceHolder] <- Captured],
|
|
|
Replacements = ["$" ++ integer_to_list(I) || I <- lists:seq(1, length(Captured))],
|
|
Replacements = ["$" ++ integer_to_list(I) || I <- lists:seq(1, length(Captured))],
|
|
|
NQuery = lists:foldl(fun({PlaceHolder, Replacement}, Query0) ->
|
|
NQuery = lists:foldl(fun({PlaceHolder, Replacement}, Query0) ->
|
|
|
- re:replace(Query0, PlaceHolder, Replacement, [{return, binary}])
|
|
|
|
|
|
|
+ re:replace(Query0, "\\" ++ PlaceHolder, Replacement, [{return, binary}])
|
|
|
end, Query, lists:zip(PlaceHolders, Replacements)),
|
|
end, Query, lists:zip(PlaceHolders, Replacements)),
|
|
|
{NQuery, PlaceHolders};
|
|
{NQuery, PlaceHolders};
|
|
|
nomatch ->
|
|
nomatch ->
|