fix(authn): add timeout option for mysql connector

This commit is contained in:
zhouzb 2021-09-23 16:40:33 +08:00
parent e737f18548
commit e31840d943
8 changed files with 82 additions and 106 deletions

View File

@ -303,8 +303,8 @@ authenticate(#{listener := Listener, protocol := Protocol} = Credential, _AuthRe
do_authenticate([], _) ->
{stop, {error, not_authorized}};
do_authenticate([#authenticator{provider = Provider, state = State} | More], Credential) ->
case Provider:authenticate(Credential, State) of
do_authenticate([#authenticator{provider = Provider, state = #{'_unique' := Unique} = State} | More], Credential) ->
try Provider:authenticate(Credential, State) of
ignore ->
do_authenticate(More, Credential);
Result ->
@ -314,6 +314,10 @@ do_authenticate([#authenticator{provider = Provider, state = State} | More], Cre
%% {continue, AuthData, AuthCache}
%% {error, Reason}
{stop, Result}
catch
error:Reason:Stacktrace ->
?LOG(warning, "The following error occurred in '~s' during authentication: ~p", [Unique, {Reason, Stacktrace}]),
do_authenticate(More, Credential)
end.
%%------------------------------------------------------------------------------

View File

@ -156,26 +156,20 @@ authenticate(#{auth_method := _}, _) ->
authenticate(Credential, #{'_unique' := Unique,
method := Method,
request_timeout := RequestTimeout} = State) ->
try
Request = generate_request(Credential, State),
case emqx_resource:query(Unique, {Method, Request, RequestTimeout}) of
{ok, 204, _Headers} -> {ok, #{is_superuser => false}};
{ok, 200, Headers, Body} ->
ContentType = proplists:get_value(<<"content-type">>, Headers, <<"application/json">>),
case safely_parse_body(ContentType, Body) of
{ok, NBody} ->
%% TODO: Return by user property
{ok, #{is_superuser => maps:get(<<"is_superuser">>, NBody, false),
user_property => NBody}};
{error, _Reason} ->
{ok, #{is_superuser => false}}
end;
{error, _Reason} ->
ignore
end
catch
error:Reason ->
?LOG(warning, "The following error occurred in '~s' during authentication: ~p", [Unique, Reason]),
Request = generate_request(Credential, State),
case emqx_resource:query(Unique, {Method, Request, RequestTimeout}) of
{ok, 204, _Headers} -> {ok, #{is_superuser => false}};
{ok, 200, Headers, Body} ->
ContentType = proplists:get_value(<<"content-type">>, Headers, <<"application/json">>),
case safely_parse_body(ContentType, Body) of
{ok, NBody} ->
%% TODO: Return by user property
{ok, #{is_superuser => maps:get(<<"is_superuser">>, NBody, false),
user_property => NBody}};
{error, _Reason} ->
{ok, #{is_superuser => false}}
end;
{error, _Reason} ->
ignore
end.

View File

@ -141,29 +141,23 @@ authenticate(#{password := Password} = Credential,
, selector := Selector0
, '_unique' := Unique
} = State) ->
try
Selector1 = replace_placeholders(Selector0, Credential),
Selector2 = normalize_selector(Selector1),
case emqx_resource:query(Unique, {find_one, Collection, Selector2, #{}}) of
undefined -> ignore;
{error, Reason} ->
?LOG(error, "['~s'] Query failed: ~p", [Unique, Reason]),
ignore;
Doc ->
case check_password(Password, Doc, State) of
ok ->
{ok, #{is_superuser => is_superuser(Doc, State)}};
{error, {cannot_find_password_hash_field, PasswordHashField}} ->
?LOG(error, "['~s'] Can't find password hash field: ~s", [Unique, PasswordHashField]),
{error, bad_username_or_password};
{error, Reason} ->
{error, Reason}
end
end
catch
error:Error ->
?LOG(warning, "The following error occurred in '~s' during authentication: ~p", [Unique, Error]),
ignore
Selector1 = replace_placeholders(Selector0, Credential),
Selector2 = normalize_selector(Selector1),
case emqx_resource:query(Unique, {find_one, Collection, Selector2, #{}}) of
undefined -> ignore;
{error, Reason} ->
?LOG(error, "['~s'] Query failed: ~p", [Unique, Reason]),
ignore;
Doc ->
case check_password(Password, Doc, State) of
ok ->
{ok, #{is_superuser => is_superuser(Doc, State)}};
{error, {cannot_find_password_hash_field, PasswordHashField}} ->
?LOG(error, "['~s'] Can't find password hash field: ~s", [Unique, PasswordHashField]),
{error, bad_username_or_password};
{error, Reason} ->
{error, Reason}
end
end.
destroy(#{'_unique' := Unique}) ->

View File

@ -114,24 +114,18 @@ authenticate(#{password := Password} = Credential,
query := Query,
query_timeout := Timeout,
'_unique' := Unique} = State) ->
try
Params = emqx_authn_utils:replace_placeholders(PlaceHolders, Credential),
case emqx_resource:query(Unique, {sql, Query, Params, Timeout}) of
{ok, _Columns, []} -> ignore;
{ok, Columns, Rows} ->
Selected = maps:from_list(lists:zip(Columns, Rows)),
case check_password(Password, Selected, State) of
ok ->
{ok, #{is_superuser => maps:get(<<"is_superuser">>, Selected, false)}};
{error, Reason} ->
{error, Reason}
end;
{error, _Reason} ->
ignore
end
catch
error:Error ->
?LOG(warning, "The following error occurred in '~s' during authentication: ~p", [Unique, Error]),
Params = emqx_authn_utils:replace_placeholders(PlaceHolders, Credential),
case emqx_resource:query(Unique, {sql, Query, Params, Timeout}) of
{ok, _Columns, []} -> ignore;
{ok, Columns, Rows} ->
Selected = maps:from_list(lists:zip(Columns, Rows)),
case check_password(Password, Selected, State) of
ok ->
{ok, #{is_superuser => maps:get(<<"is_superuser">>, Selected, false)}};
{error, Reason} ->
{error, Reason}
end;
{error, _Reason} ->
ignore
end.

View File

@ -103,25 +103,19 @@ authenticate(#{password := Password} = Credential,
#{query := Query,
placeholders := PlaceHolders,
'_unique' := Unique} = State) ->
try
Params = emqx_authn_utils:replace_placeholders(PlaceHolders, Credential),
case emqx_resource:query(Unique, {sql, Query, Params}) of
{ok, _Columns, []} -> ignore;
{ok, Columns, Rows} ->
NColumns = [Name || #column{name = Name} <- Columns],
Selected = maps:from_list(lists:zip(NColumns, Rows)),
case check_password(Password, Selected, State) of
ok ->
{ok, #{is_superuser => maps:get(<<"is_superuser">>, Selected, false)}};
{error, Reason} ->
{error, Reason}
end;
{error, _Reason} ->
ignore
end
catch
error:Error ->
?LOG(warning, "The following error occurred in '~s' during authentication: ~p", [Unique, Error]),
Params = emqx_authn_utils:replace_placeholders(PlaceHolders, Credential),
case emqx_resource:query(Unique, {sql, Query, Params}) of
{ok, _Columns, []} -> ignore;
{ok, Columns, Rows} ->
NColumns = [Name || #column{name = Name} <- Columns],
Selected = maps:from_list(lists:zip(NColumns, Rows)),
case check_password(Password, Selected, State) of
ok ->
{ok, #{is_superuser => maps:get(<<"is_superuser">>, Selected, false)}};
{error, Reason} ->
{error, Reason}
end;
{error, _Reason} ->
ignore
end.

View File

@ -127,24 +127,18 @@ authenticate(#{password := Password} = Credential,
#{ query := {Command, Key, Fields}
, '_unique' := Unique
} = State) ->
try
NKey = binary_to_list(iolist_to_binary(replace_placeholders(Key, Credential))),
case emqx_resource:query(Unique, {cmd, [Command, NKey | Fields]}) of
{ok, Values} ->
Selected = merge(Fields, Values),
case check_password(Password, Selected, State) of
ok ->
{ok, #{is_superuser => maps:get("is_superuser", Selected, false)}};
{error, Reason} ->
{error, Reason}
end;
{error, Reason} ->
?LOG(error, "['~s'] Query failed: ~p", [Unique, Reason]),
ignore
end
catch
error:{cannot_get_variable, Placeholder} ->
?LOG(warning, "The following error occurred in '~s' during authentication: ~p", [Unique, {cannot_get_variable, Placeholder}]),
NKey = binary_to_list(iolist_to_binary(replace_placeholders(Key, Credential))),
case emqx_resource:query(Unique, {cmd, [Command, NKey | Fields]}) of
{ok, Values} ->
Selected = merge(Fields, Values),
case check_password(Password, Selected, State) of
ok ->
{ok, #{is_superuser => maps:get("is_superuser", Selected, false)}};
{error, Reason} ->
{error, Reason}
end;
{error, Reason} ->
?LOG(error, "['~s'] Query failed: ~p", [Unique, Reason]),
ignore
end.

View File

@ -76,11 +76,13 @@ on_stop(InstId, #{poolname := PoolName}) ->
logger:info("stopping mysql connector: ~p", [InstId]),
emqx_plugin_libs_pool:stop_pool(PoolName).
on_query(InstId, {sql, SQL}, AfterQuery, #{poolname := PoolName} = State) ->
on_query(InstId, {sql, SQL, []}, AfterQuery, #{poolname := PoolName} = State);
on_query(InstId, {sql, SQL, Params}, AfterQuery, #{poolname := PoolName} = State) ->
on_query(InstId, {sql, SQL}, AfterQuery, #{poolname := _PoolName} = State) ->
on_query(InstId, {sql, SQL, [], default_timeout}, AfterQuery, State);
on_query(InstId, {sql, SQL, Params}, AfterQuery, #{poolname := _PoolName} = State) ->
on_query(InstId, {sql, SQL, Params, default_timeout}, AfterQuery, State);
on_query(InstId, {sql, SQL, Params, Timeout}, AfterQuery, #{poolname := PoolName} = State) ->
logger:debug("mysql connector ~p received sql query: ~p, at state: ~p", [InstId, SQL, State]),
case Result = ecpool:pick_and_do(PoolName, {mysql, query, [SQL, Params]}, no_handover) of
case Result = ecpool:pick_and_do(PoolName, {mysql, query, [SQL, Params, Timeout]}, no_handover) of
{error, Reason} ->
logger:debug("mysql connector ~p do sql query failed, sql: ~p, reason: ~p", [InstId, SQL, Reason]),
emqx_resource:query_failed(AfterQuery);

View File

@ -76,8 +76,8 @@ on_stop(InstId, #{poolname := PoolName}) ->
logger:info("stopping postgresql connector: ~p", [InstId]),
emqx_plugin_libs_pool:stop_pool(PoolName).
on_query(InstId, {sql, SQL}, AfterQuery, #{poolname := PoolName} = State) ->
on_query(InstId, {sql, SQL, []}, AfterQuery, #{poolname := PoolName} = State);
on_query(InstId, {sql, SQL}, AfterQuery, #{poolname := _PoolName} = State) ->
on_query(InstId, {sql, SQL, []}, AfterQuery, State);
on_query(InstId, {sql, SQL, Params}, AfterQuery, #{poolname := PoolName} = State) ->
logger:debug("postgresql connector ~p received sql query: ~p, at state: ~p", [InstId, SQL, State]),
case Result = ecpool:pick_and_do(PoolName, {?MODULE, query, [SQL, Params]}, no_handover) of