Merge pull request #8554 from savonarola/authn-logging

Add more tracing for authentication
This commit is contained in:
Ilya Averyanov 2022-07-25 17:43:00 +03:00 committed by GitHub
commit 2f470b8878
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 182 additions and 112 deletions

View File

@ -28,7 +28,8 @@
* Improve the dashboard listener startup log, the listener name is no longer spliced with port information, * Improve the dashboard listener startup log, the listener name is no longer spliced with port information,
and the colon(:) is no longer displayed when IP is not specified. [#8480](https://github.com/emqx/emqx/pull/8480) and the colon(:) is no longer displayed when IP is not specified. [#8480](https://github.com/emqx/emqx/pull/8480)
* Remove `/configs/listeners` API, use `/listeners/` instead. [#8485](https://github.com/emqx/emqx/pull/8485) * Remove `/configs/listeners` API, use `/listeners/` instead. [#8485](https://github.com/emqx/emqx/pull/8485)
* Optimize performance of builtin database operations in processes with long message queue [8439](https://github.com/emqx/emqx/pull/8439) * Optimize performance of builtin database operations in processes with long message queue [#8439](https://github.com/emqx/emqx/pull/8439)
* Improve authentication tracing. [#8554](https://github.com/emqx/emqx/pull/8554)
# 5.0.3 # 5.0.3

View File

@ -17,6 +17,19 @@
-ifndef(EMQX_AUTHENTICATION_HRL). -ifndef(EMQX_AUTHENTICATION_HRL).
-define(EMQX_AUTHENTICATION_HRL, true). -define(EMQX_AUTHENTICATION_HRL, true).
-include_lib("emqx/include/logger.hrl").
-define(AUTHN_TRACE_TAG, "AUTHN").
-define(TRACE_AUTHN_PROVIDER(Msg), ?TRACE_AUTHN_PROVIDER(Msg, #{})).
-define(TRACE_AUTHN_PROVIDER(Msg, Meta), ?TRACE_AUTHN_PROVIDER(debug, Msg, Meta)).
-define(TRACE_AUTHN_PROVIDER(Level, Msg, Meta),
?TRACE_AUTHN(Level, Msg, (Meta)#{provider => ?MODULE})
).
-define(TRACE_AUTHN(Msg, Meta), ?TRACE_AUTHN(debug, Msg, Meta)).
-define(TRACE_AUTHN(Level, Msg, Meta), ?TRACE(Level, ?AUTHN_TRACE_TAG, Msg, Meta)).
%% config root name all auth providers have to agree on. %% config root name all auth providers have to agree on.
-define(EMQX_AUTHENTICATION_CONFIG_ROOT_NAME, "authentication"). -define(EMQX_AUTHENTICATION_CONFIG_ROOT_NAME, "authentication").
-define(EMQX_AUTHENTICATION_CONFIG_ROOT_NAME_ATOM, authentication). -define(EMQX_AUTHENTICATION_CONFIG_ROOT_NAME_ATOM, authentication).

View File

@ -42,17 +42,21 @@
-define(TRACE_FILTER, emqx_trace_filter). -define(TRACE_FILTER, emqx_trace_filter).
-define(TRACE(Tag, Msg, Meta), ?TRACE(debug, Tag, Msg, Meta)).
%% Only evaluate when necessary %% Only evaluate when necessary
%% Always debug the trace events. -define(TRACE(Level, Tag, Msg, Meta), begin
-define(TRACE(Tag, Msg, Meta), begin case persistent_term:get(?TRACE_FILTER, []) of
case persistent_term:get(?TRACE_FILTER, undefined) of
undefined -> ok;
[] -> ok; [] -> ok;
List -> emqx_trace:log(List, Msg, Meta#{trace_tag => Tag}) %% We can't bind filter list to a variablebecause we pollute the calling scope with it.
%% We also don't want to wrap the macro body in a fun
%% beacause this adds overhead to the happy path.
%% So evaluate `persistent_term:get` twice.
_ -> emqx_trace:log(persistent_term:get(?TRACE_FILTER, []), Msg, (Meta)#{trace_tag => Tag})
end, end,
?SLOG( ?SLOG(
debug, Level,
(emqx_trace_formatter:format_meta(Meta))#{msg => Msg, tag => Tag}, (emqx_trace_formatter:format_meta_map(Meta))#{msg => Msg, tag => Tag},
#{is_trace => false} #{is_trace => false}
) )
end). end).

View File

@ -101,6 +101,14 @@
-define(CHAINS_TAB, emqx_authn_chains). -define(CHAINS_TAB, emqx_authn_chains).
-define(TRACE_RESULT(Label, Result, Reason), begin
?TRACE_AUTHN(Label, #{
result => (Result),
reason => (Reason)
}),
Result
end).
-type chain_name() :: atom(). -type chain_name() :: atom().
-type authenticator_id() :: binary(). -type authenticator_id() :: binary().
-type position() :: front | rear | {before, authenticator_id()} | {'after', authenticator_id()}. -type position() :: front | rear | {before, authenticator_id()} | {'after', authenticator_id()}.
@ -216,14 +224,14 @@ when
authenticate(#{enable_authn := false}, _AuthResult) -> authenticate(#{enable_authn := false}, _AuthResult) ->
inc_authenticate_metric('authentication.success.anonymous'), inc_authenticate_metric('authentication.success.anonymous'),
ignore; ?TRACE_RESULT("authentication_result", ignore, enable_authn_false);
authenticate(#{listener := Listener, protocol := Protocol} = Credential, _AuthResult) -> authenticate(#{listener := Listener, protocol := Protocol} = Credential, _AuthResult) ->
case get_authenticators(Listener, global_chain(Protocol)) of case get_authenticators(Listener, global_chain(Protocol)) of
{ok, ChainName, Authenticators} -> {ok, ChainName, Authenticators} ->
case get_enabled(Authenticators) of case get_enabled(Authenticators) of
[] -> [] ->
inc_authenticate_metric('authentication.success.anonymous'), inc_authenticate_metric('authentication.success.anonymous'),
ignore; ?TRACE_RESULT("authentication_result", ignore, empty_chain);
NAuthenticators -> NAuthenticators ->
Result = do_authenticate(ChainName, NAuthenticators, Credential), Result = do_authenticate(ChainName, NAuthenticators, Credential),
@ -235,11 +243,11 @@ authenticate(#{listener := Listener, protocol := Protocol} = Credential, _AuthRe
_ -> _ ->
ok ok
end, end,
Result ?TRACE_RESULT("authentication_result", Result, chain_result)
end; end;
none -> none ->
inc_authenticate_metric('authentication.success.anonymous'), inc_authenticate_metric('authentication.success.anonymous'),
ignore ?TRACE_RESULT("authentication_result", ignore, no_chain)
end. end.
get_authenticators(Listener, Global) -> get_authenticators(Listener, Global) ->
@ -626,11 +634,11 @@ handle_create_authenticator(Chain, Config, Providers) ->
do_authenticate(_ChainName, [], _) -> do_authenticate(_ChainName, [], _) ->
{stop, {error, not_authorized}}; {stop, {error, not_authorized}};
do_authenticate( do_authenticate(
ChainName, [#authenticator{id = ID, provider = Provider, state = State} | More], Credential ChainName, [#authenticator{id = ID} = Authenticator | More], Credential
) -> ) ->
MetricsID = metrics_id(ChainName, ID), MetricsID = metrics_id(ChainName, ID),
emqx_metrics_worker:inc(authn_metrics, MetricsID, total), emqx_metrics_worker:inc(authn_metrics, MetricsID, total),
try Provider:authenticate(Credential, State) of try authenticate_with_provider(Authenticator, Credential) of
ignore -> ignore ->
ok = emqx_metrics_worker:inc(authn_metrics, MetricsID, nomatch), ok = emqx_metrics_worker:inc(authn_metrics, MetricsID, nomatch),
do_authenticate(ChainName, More, Credential); do_authenticate(ChainName, More, Credential);
@ -651,8 +659,7 @@ do_authenticate(
{stop, Result} {stop, Result}
catch catch
Class:Reason:Stacktrace -> Class:Reason:Stacktrace ->
?SLOG(warning, #{ ?TRACE_AUTHN(warning, "authenticator_error", #{
msg => "unexpected_error_in_authentication",
exception => Class, exception => Class,
reason => Reason, reason => Reason,
stacktrace => Stacktrace, stacktrace => Stacktrace,
@ -662,6 +669,14 @@ do_authenticate(
do_authenticate(ChainName, More, Credential) do_authenticate(ChainName, More, Credential)
end. end.
authenticate_with_provider(#authenticator{id = ID, provider = Provider, state = State}, Credential) ->
AuthnResult = Provider:authenticate(Credential, State),
?TRACE_AUTHN("authenticator_result", #{
authenticator => ID,
result => AuthnResult
}),
AuthnResult.
reply(Reply, State) -> reply(Reply, State) ->
{reply, Reply, State}. {reply, Reply, State}.

View File

@ -92,15 +92,16 @@ unsubscribe(<<"$SYS/", _/binary>>, _SubOpts) ->
unsubscribe(Topic, SubOpts) -> unsubscribe(Topic, SubOpts) ->
?TRACE("UNSUBSCRIBE", "unsubscribe", #{topic => Topic, sub_opts => SubOpts}). ?TRACE("UNSUBSCRIBE", "unsubscribe", #{topic => Topic, sub_opts => SubOpts}).
log(List, Msg, Meta0) -> log(List, Msg, Meta) ->
Meta = Log = #{level => debug, meta => enrich_meta(Meta), msg => Msg},
case logger:get_process_metadata() of
undefined -> Meta0;
ProcMeta -> maps:merge(ProcMeta, Meta0)
end,
Log = #{level => debug, meta => Meta, msg => Msg},
log_filter(List, Log). log_filter(List, Log).
enrich_meta(Meta) ->
case logger:get_process_metadata() of
undefined -> Meta;
ProcMeta -> maps:merge(ProcMeta, Meta)
end.
log_filter([], _Log) -> log_filter([], _Log) ->
ok; ok;
log_filter([{Id, FilterFun, Filter, Name} | Rest], Log0) -> log_filter([{Id, FilterFun, Filter, Name} | Rest], Log0) ->

View File

@ -16,7 +16,7 @@
-module(emqx_trace_formatter). -module(emqx_trace_formatter).
-export([format/2]). -export([format/2]).
-export([format_meta/1]). -export([format_meta_map/1]).
%%%----------------------------------------------------------------- %%%-----------------------------------------------------------------
%%% API %%% API
@ -31,32 +31,39 @@ format(
ClientId = to_iolist(maps:get(clientid, Meta, "")), ClientId = to_iolist(maps:get(clientid, Meta, "")),
Peername = maps:get(peername, Meta, ""), Peername = maps:get(peername, Meta, ""),
MetaBin = format_meta(Meta, PEncode), MetaBin = format_meta(Meta, PEncode),
[Time, " [", Tag, "] ", ClientId, "@", Peername, " msg: ", Msg, MetaBin, "\n"]; [Time, " [", Tag, "] ", ClientId, "@", Peername, " msg: ", Msg, ", ", MetaBin, "\n"];
format(Event, Config) -> format(Event, Config) ->
emqx_logger_textfmt:format(Event, Config). emqx_logger_textfmt:format(Event, Config).
format_meta(Meta) -> format_meta_map(Meta) ->
Encode = emqx_trace_handler:payload_encode(), Encode = emqx_trace_handler:payload_encode(),
do_format_meta(Meta, Encode). format_meta_map(Meta, Encode).
format_meta(Meta0, Encode) -> format_meta_map(Meta, Encode) ->
Meta1 = #{packet := Packet0, payload := Payload0} = do_format_meta(Meta0, Encode), format_meta_map(Meta, Encode, [{packet, fun format_packet/2}, {payload, fun format_payload/2}]).
Packet = enrich(", packet: ", Packet0),
Payload = enrich(", payload: ", Payload0), format_meta_map(Meta, _Encode, []) ->
Meta2 = maps:without([msg, clientid, peername, packet, payload, trace_tag], Meta1), Meta;
case Meta2 =:= #{} of format_meta_map(Meta, Encode, [{Name, FormatFun} | Rest]) ->
true -> [Packet, Payload]; case Meta of
false -> [Packet, ", ", map_to_iolist(Meta2), Payload] #{Name := Value} ->
NewMeta = Meta#{Name => FormatFun(Value, Encode)},
format_meta_map(NewMeta, Encode, Rest);
#{} ->
format_meta_map(Meta, Encode, Rest)
end. end.
enrich(_, "") -> ""; format_meta(Meta0, Encode) ->
enrich(Key, IoData) -> [Key, IoData]. Meta1 = maps:without([msg, clientid, peername, trace_tag], Meta0),
Meta2 = format_meta_map(Meta1, Encode),
kvs_to_iolist(lists:sort(fun compare_meta_kvs/2, maps:to_list(Meta2))).
do_format_meta(Meta, Encode) -> %% packet always goes first; payload always goes last
Meta#{ compare_meta_kvs(KV1, KV2) -> weight(KV1) =< weight(KV2).
packet => format_packet(maps:get(packet, Meta, undefined), Encode),
payload => format_payload(maps:get(payload, Meta, undefined), Encode) weight({packet, _}) -> {0, packet};
}. weight({payload, _}) -> {2, payload};
weight({K, _}) -> {1, K}.
format_packet(undefined, _) -> ""; format_packet(undefined, _) -> "";
format_packet(Packet, Encode) -> emqx_packet:format(Packet, Encode). format_packet(Packet, Encode) -> emqx_packet:format(Packet, Encode).
@ -69,14 +76,14 @@ format_payload(_, hidden) -> "******".
to_iolist(Atom) when is_atom(Atom) -> atom_to_list(Atom); to_iolist(Atom) when is_atom(Atom) -> atom_to_list(Atom);
to_iolist(Int) when is_integer(Int) -> integer_to_list(Int); to_iolist(Int) when is_integer(Int) -> integer_to_list(Int);
to_iolist(Float) when is_float(Float) -> float_to_list(Float, [{decimals, 2}]); to_iolist(Float) when is_float(Float) -> float_to_list(Float, [{decimals, 2}]);
to_iolist(SubMap) when is_map(SubMap) -> ["[", map_to_iolist(SubMap), "]"]; to_iolist(SubMap) when is_map(SubMap) -> ["[", kvs_to_iolist(maps:to_list(SubMap)), "]"];
to_iolist(Char) -> emqx_logger_textfmt:try_format_unicode(Char). to_iolist(Char) -> emqx_logger_textfmt:try_format_unicode(Char).
map_to_iolist(Map) -> kvs_to_iolist(KVs) ->
lists:join( lists:join(
",", ", ",
lists:map( lists:map(
fun({K, V}) -> [to_iolist(K), ": ", to_iolist(V)] end, fun({K, V}) -> [to_iolist(K), ": ", to_iolist(V)] end,
maps:to_list(Map) KVs
) )
). ).

View File

@ -36,6 +36,6 @@
-type authenticator_id() :: binary(). -type authenticator_id() :: binary().
-endif.
-define(RESOURCE_GROUP, <<"emqx_authn">>). -define(RESOURCE_GROUP, <<"emqx_authn">>).
-endif.

View File

@ -33,7 +33,8 @@
bin/1, bin/1,
ensure_apps_started/1, ensure_apps_started/1,
cleanup_resources/0, cleanup_resources/0,
make_resource_id/1 make_resource_id/1,
without_password/1
]). ]).
-define(AUTHN_PLACEHOLDERS, [ -define(AUTHN_PLACEHOLDERS, [
@ -199,10 +200,23 @@ make_resource_id(Name) ->
NameBin = bin(Name), NameBin = bin(Name),
emqx_resource:generate_id(NameBin). emqx_resource:generate_id(NameBin).
without_password(Credential) ->
without_password(Credential, [password, <<"password">>]).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Internal functions %% Internal functions
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
without_password(Credential, []) ->
Credential;
without_password(Credential, [Name | Rest]) ->
case maps:is_key(Name, Credential) of
true ->
without_password(Credential#{Name => <<"[password]">>}, Rest);
false ->
without_password(Credential, Rest)
end.
handle_var({var, Name}, undefined) -> handle_var({var, Name}, undefined) ->
error({cannot_get_variable, Name}); error({cannot_get_variable, Name});
handle_var({var, <<"peerhost">>}, PeerHost) -> handle_var({var, <<"peerhost">>}, PeerHost) ->

View File

@ -331,7 +331,10 @@ check_client_first_message(Bin, _Cache, #{iteration_count := IterationCount} = S
{continue, ServerFirstMessage, Cache}; {continue, ServerFirstMessage, Cache};
ignore -> ignore ->
ignore; ignore;
{error, _Reason} -> {error, Reason} ->
?TRACE_AUTHN_PROVIDER("check_client_first_message_error", #{
reason => Reason
}),
{error, not_authorized} {error, not_authorized}
end. end.
@ -344,7 +347,10 @@ check_client_final_message(Bin, #{is_superuser := IsSuperuser} = Cache, #{algori
of of
{ok, ServerFinalMessage} -> {ok, ServerFinalMessage} ->
{ok, #{is_superuser => IsSuperuser}, ServerFinalMessage}; {ok, #{is_superuser => IsSuperuser}, ServerFinalMessage};
{error, _Reason} -> {error, Reason} ->
?TRACE_AUTHN_PROVIDER("check_client_final_message_error", #{
reason => Reason
}),
{error, not_authorized} {error, not_authorized}
end. end.

View File

@ -188,23 +188,22 @@ authenticate(
} = State } = State
) -> ) ->
Request = generate_request(Credential, State), Request = generate_request(Credential, State),
case emqx_resource:query(ResourceId, {Method, Request, RequestTimeout}) of Response = emqx_resource:query(ResourceId, {Method, Request, RequestTimeout}),
?TRACE_AUTHN_PROVIDER("http_response", #{
request => request_for_log(Credential, State),
response => response_for_log(Response),
resource => ResourceId
}),
case Response of
{ok, 204, _Headers} -> {ok, 204, _Headers} ->
{ok, #{is_superuser => false}}; {ok, #{is_superuser => false}};
{ok, 200, Headers, Body} -> {ok, 200, Headers, Body} ->
handle_response(Headers, Body); handle_response(Headers, Body);
{ok, _StatusCode, _Headers} = Response -> {ok, _StatusCode, _Headers} = Response ->
log_response(ResourceId, Response),
ignore; ignore;
{ok, _StatusCode, _Headers, _Body} = Response -> {ok, _StatusCode, _Headers, _Body} = Response ->
log_response(ResourceId, Response),
ignore; ignore;
{error, Reason} -> {error, _Reason} ->
?SLOG(error, #{
msg => "http_server_query_failed",
resource => ResourceId,
reason => Reason
}),
ignore ignore
end. end.
@ -296,7 +295,8 @@ parse_config(
cow_qs:parse_qs(to_bin(Query)) cow_qs:parse_qs(to_bin(Query))
), ),
body_template => emqx_authn_utils:parse_deep(maps:get(body, Config, #{})), body_template => emqx_authn_utils:parse_deep(maps:get(body, Config, #{})),
request_timeout => RequestTimeout request_timeout => RequestTimeout,
url => RawUrl
}, },
{Config#{base_url => BaseUrl, pool_type => random}, State}. {Config#{base_url => BaseUrl, pool_type => random}, State}.
@ -379,11 +379,6 @@ parse_body(<<"application/x-www-form-urlencoded", _/binary>>, Body) ->
parse_body(ContentType, _) -> parse_body(ContentType, _) ->
{error, {unsupported_content_type, ContentType}}. {error, {unsupported_content_type, ContentType}}.
may_append_body(Output, {ok, _, _, Body}) ->
Output#{body => Body};
may_append_body(Output, {ok, _, _}) ->
Output.
uri_encode(T) -> uri_encode(T) ->
emqx_http_lib:uri_encode(to_list(T)). emqx_http_lib:uri_encode(to_list(T)).
@ -391,26 +386,33 @@ encode_path(Path) ->
Parts = string:split(Path, "/", all), Parts = string:split(Path, "/", all),
lists:flatten(["/" ++ Part || Part <- lists:map(fun uri_encode/1, Parts)]). lists:flatten(["/" ++ Part || Part <- lists:map(fun uri_encode/1, Parts)]).
log_response(ResourceId, Other) -> request_for_log(Credential, #{url := Url} = State) ->
Output = may_append_body(#{resource => ResourceId}, Other), SafeCredential = emqx_authn_utils:without_password(Credential),
case erlang:element(2, Other) of case generate_request(SafeCredential, State) of
Code5xx when Code5xx >= 500 andalso Code5xx < 600 -> {PathQuery, Headers} ->
?SLOG(error, Output#{ #{
msg => "http_server_error", method => post,
code => Code5xx base_url => Url,
}); path_query => PathQuery,
Code4xx when Code4xx >= 400 andalso Code4xx < 500 -> headers => Headers
?SLOG(warning, Output#{ };
msg => "refused_by_http_server", {PathQuery, Headers, Body} ->
code => Code4xx #{
}); method => post,
OtherCode -> base_url => Url,
?SLOG(error, Output#{ path_query => PathQuery,
msg => "undesired_response_code", headers => Headers,
code => OtherCode mody => Body
}) }
end. end.
response_for_log({ok, StatusCode, Headers}) ->
#{status => StatusCode, headers => Headers};
response_for_log({ok, StatusCode, Headers, Body}) ->
#{status => StatusCode, headers => Headers, body => Body};
response_for_log({error, Error}) ->
#{error => Error}.
to_list(A) when is_atom(A) -> to_list(A) when is_atom(A) ->
atom_to_list(A); atom_to_list(A);
to_list(B) when is_binary(B) -> to_list(B) when is_binary(B) ->

View File

@ -227,8 +227,7 @@ authenticate(
) -> ) ->
case emqx_resource:query(ResourceId, get_jwks) of case emqx_resource:query(ResourceId, get_jwks) of
{error, Reason} -> {error, Reason} ->
?SLOG(error, #{ ?TRACE_AUTHN_PROVIDER(error, "get_jwks_failed", #{
msg => "get_jwks_failed",
resource => ResourceId, resource => ResourceId,
reason => Reason reason => Reason
}), }),
@ -350,10 +349,17 @@ verify(undefined, _, _, _) ->
ignore; ignore;
verify(JWT, JWKs, VerifyClaims, AclClaimName) -> verify(JWT, JWKs, VerifyClaims, AclClaimName) ->
case do_verify(JWT, JWKs, VerifyClaims) of case do_verify(JWT, JWKs, VerifyClaims) of
{ok, Extra} -> {ok, acl(Extra, AclClaimName)}; {ok, Extra} ->
{error, {missing_claim, _}} -> {error, bad_username_or_password}; {ok, acl(Extra, AclClaimName)};
{error, invalid_signature} -> ignore; {error, {missing_claim, Claim}} ->
{error, {claims, _}} -> {error, bad_username_or_password} ?TRACE_AUTHN_PROVIDER("missing_jwt_claim", #{jwt => JWT, claim => Claim}),
{error, bad_username_or_password};
{error, invalid_signature} ->
?TRACE_AUTHN_PROVIDER("invalid_jwt_signature", #{jwks => JWKs, jwt => JWT}),
ignore;
{error, {claims, Claims}} ->
?TRACE_AUTHN_PROVIDER("invalid_jwt_claims", #{jwt => JWT, claims => Claims}),
{error, bad_username_or_password}
end. end.
acl(Claims, AclClaimName) -> acl(Claims, AclClaimName) ->
@ -371,11 +377,11 @@ acl(Claims, AclClaimName) ->
end, end,
maps:merge(emqx_authn_utils:is_superuser(Claims), Acl). maps:merge(emqx_authn_utils:is_superuser(Claims), Acl).
do_verify(_JWS, [], _VerifyClaims) -> do_verify(_JWT, [], _VerifyClaims) ->
{error, invalid_signature}; {error, invalid_signature};
do_verify(JWS, [JWK | More], VerifyClaims) -> do_verify(JWT, [JWK | More], VerifyClaims) ->
try jose_jws:verify(JWK, JWS) of try jose_jws:verify(JWK, JWT) of
{true, Payload, _JWS} -> {true, Payload, _JWT} ->
Claims0 = emqx_json:decode(Payload, [return_maps]), Claims0 = emqx_json:decode(Payload, [return_maps]),
Claims = try_convert_to_int(Claims0, [<<"exp">>, <<"iat">>, <<"nbf">>]), Claims = try_convert_to_int(Claims0, [<<"exp">>, <<"iat">>, <<"nbf">>]),
case verify_claims(Claims, VerifyClaims) of case verify_claims(Claims, VerifyClaims) of
@ -385,11 +391,11 @@ do_verify(JWS, [JWK | More], VerifyClaims) ->
{error, Reason} {error, Reason}
end; end;
{false, _, _} -> {false, _, _} ->
do_verify(JWS, More, VerifyClaims) do_verify(JWT, More, VerifyClaims)
catch catch
_:_Reason -> _:Reason ->
?TRACE("JWT", "authn_jwt_invalid_signature", #{jwk => JWK, jws => JWS}), ?TRACE_AUTHN_PROVIDER("jwt_verify_error", #{jwk => JWK, jwt => JWT, reason => Reason}),
{error, invalid_signature} do_verify(JWT, More, VerifyClaims)
end. end.
verify_claims(Claims, VerifyClaims0) -> verify_claims(Claims, VerifyClaims0) ->

View File

@ -17,6 +17,7 @@
-module(emqx_authn_mnesia). -module(emqx_authn_mnesia).
-include("emqx_authn.hrl"). -include("emqx_authn.hrl").
-include_lib("emqx/include/logger.hrl").
-include_lib("stdlib/include/ms_transform.hrl"). -include_lib("stdlib/include/ms_transform.hrl").
-include_lib("hocon/include/hoconsc.hrl"). -include_lib("hocon/include/hoconsc.hrl").
@ -158,6 +159,7 @@ authenticate(
UserID = get_user_identity(Credential, Type), UserID = get_user_identity(Credential, Type),
case mnesia:dirty_read(?TAB, {UserGroup, UserID}) of case mnesia:dirty_read(?TAB, {UserGroup, UserID}) of
[] -> [] ->
?TRACE_AUTHN_PROVIDER("user_not_found"),
ignore; ignore;
[#user_info{password_hash = PasswordHash, salt = Salt, is_superuser = IsSuperuser}] -> [#user_info{password_hash = PasswordHash, salt = Salt, is_superuser = IsSuperuser}] ->
case case
@ -165,8 +167,10 @@ authenticate(
Algorithm, Salt, PasswordHash, Password Algorithm, Salt, PasswordHash, Password
) )
of of
true -> {ok, #{is_superuser => IsSuperuser}}; true ->
false -> {error, bad_username_or_password} {ok, #{is_superuser => IsSuperuser}};
false ->
{error, bad_username_or_password}
end end
end. end.

View File

@ -167,8 +167,7 @@ authenticate(
undefined -> undefined ->
ignore; ignore;
{error, Reason} -> {error, Reason} ->
?SLOG(error, #{ ?TRACE_AUTHN_PROVIDER(error, "mongodb_query_failed", #{
msg => "mongodb_query_failed",
resource => ResourceId, resource => ResourceId,
collection => Collection, collection => Collection,
filter => Filter, filter => Filter,
@ -180,11 +179,11 @@ authenticate(
ok -> ok ->
{ok, is_superuser(Doc, State)}; {ok, is_superuser(Doc, State)};
{error, {cannot_find_password_hash_field, PasswordHashField}} -> {error, {cannot_find_password_hash_field, PasswordHashField}} ->
?SLOG(error, #{ ?TRACE_AUTHN_PROVIDER(error, "cannot_find_password_hash_field", #{
msg => "cannot_find_password_hash_field",
resource => ResourceId, resource => ResourceId,
collection => Collection, collection => Collection,
filter => Filter, filter => Filter,
document => Doc,
password_hash_field => PasswordHashField password_hash_field => PasswordHashField
}), }),
ignore; ignore;

View File

@ -130,8 +130,7 @@ authenticate(
{error, Reason} {error, Reason}
end; end;
{error, Reason} -> {error, Reason} ->
?SLOG(error, #{ ?TRACE_AUTHN_PROVIDER(error, "mysql_query_failed", #{
msg => "mysql_query_failed",
resource => ResourceId, resource => ResourceId,
tmpl_token => TmplToken, tmpl_token => TmplToken,
params => Params, params => Params,

View File

@ -133,8 +133,7 @@ authenticate(
{error, Reason} {error, Reason}
end; end;
{error, Reason} -> {error, Reason} ->
?SLOG(error, #{ ?TRACE_AUTHN_PROVIDER(error, "postgresql_query_failed", #{
msg => "postgresql_query_failed",
resource => ResourceId, resource => ResourceId,
params => Params, params => Params,
reason => Reason reason => Reason

View File

@ -128,13 +128,14 @@ authenticate(#{auth_method := _}, _) ->
authenticate( authenticate(
#{password := Password} = Credential, #{password := Password} = Credential,
#{ #{
cmd := {Command, KeyTemplate, Fields}, cmd := {CommandName, KeyTemplate, Fields},
resource_id := ResourceId, resource_id := ResourceId,
password_hash_algorithm := Algorithm password_hash_algorithm := Algorithm
} }
) -> ) ->
NKey = emqx_authn_utils:render_str(KeyTemplate, Credential), NKey = emqx_authn_utils:render_str(KeyTemplate, Credential),
case emqx_resource:query(ResourceId, {cmd, [Command, NKey | Fields]}) of Command = [CommandName, NKey | Fields],
case emqx_resource:query(ResourceId, {cmd, Command}) of
{ok, []} -> {ok, []} ->
ignore; ignore;
{ok, Values} -> {ok, Values} ->
@ -150,8 +151,7 @@ authenticate(
{error, Reason} {error, Reason}
end; end;
{error, Reason} -> {error, Reason} ->
?SLOG(error, #{ ?TRACE_AUTHN_PROVIDER(error, "redis_query_failed", #{
msg => "redis_query_failed",
resource => ResourceId, resource => ResourceId,
cmd => Command, cmd => Command,
keys => NKey, keys => NKey,