Просмотр исходного кода

fix(authz_http): handle `ignore` results (request failures)

Related issue: https://github.com/emqx/emqx/issues/9683

When the HTTP request for authz fails (e.g.: resource is down or
server is down), then the HTTP authorizer returns `ignore`, which was
not handled correctly by the authorization callback.
Thales Macedo Garitezi 3 лет назад
Родитель
Сommit
c6b8e614df

+ 1 - 1
apps/emqx_authz/src/emqx_authz.app.src

@@ -1,7 +1,7 @@
 %% -*- mode: erlang -*-
 {application, emqx_authz, [
     {description, "An OTP application"},
-    {vsn, "0.1.10"},
+    {vsn, "0.1.11"},
     {registered, []},
     {mod, {emqx_authz_app, []}},
     {applications, [

+ 8 - 0
apps/emqx_authz/src/emqx_authz.erl

@@ -20,6 +20,7 @@
 -include("emqx_authz.hrl").
 -include_lib("emqx/include/logger.hrl").
 -include_lib("emqx/include/emqx_hooks.hrl").
+-include_lib("snabbkaffe/include/snabbkaffe.hrl").
 
 -ifdef(TEST).
 -compile(export_all).
@@ -358,6 +359,7 @@ authorize_non_superuser(
             emqx_metrics:inc(?METRIC_DENY),
             {stop, #{result => deny, from => AuthzSource}};
         nomatch ->
+            ?tp(authz_non_superuser, #{result => nomatch}),
             ?SLOG(info, #{
                 msg => "authorization_failed_nomatch",
                 username => Username,
@@ -388,6 +390,12 @@ do_authorize(
         nomatch ->
             emqx_metrics_worker:inc(authz_metrics, Type, nomatch),
             do_authorize(Client, PubSub, Topic, Tail);
+        %% {matched, allow | deny | ignore}
+        {matched, ignore} ->
+            do_authorize(Client, PubSub, Topic, Tail);
+        ignore ->
+            do_authorize(Client, PubSub, Topic, Tail);
+        %% {matched, allow | deny}
         Matched ->
             {Matched, Type}
     catch

+ 2 - 0
apps/emqx_authz/src/emqx_authz_http.erl

@@ -20,6 +20,7 @@
 -include_lib("emqx/include/emqx.hrl").
 -include_lib("emqx/include/logger.hrl").
 -include_lib("emqx/include/emqx_placeholder.hrl").
+-include_lib("snabbkaffe/include/snabbkaffe.hrl").
 
 -behaviour(emqx_authz).
 
@@ -104,6 +105,7 @@ authorize(
             log_nomtach_msg(Status, Headers, Body),
             nomatch;
         {error, Reason} ->
+            ?tp(authz_http_request_failure, #{error => Reason}),
             ?SLOG(error, #{
                 msg => "http_server_query_failed",
                 resource => ResourceID,

+ 42 - 2
apps/emqx_authz/test/emqx_authz_http_SUITE.erl

@@ -23,6 +23,7 @@
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("common_test/include/ct.hrl").
 -include_lib("emqx/include/emqx_placeholder.hrl").
+-include_lib("snabbkaffe/include/snabbkaffe.hrl").
 
 -define(HTTP_PORT, 33333).
 -define(HTTP_PATH, "/authz/[...]").
@@ -64,7 +65,14 @@ init_per_testcase(_Case, Config) ->
     Config.
 
 end_per_testcase(_Case, _Config) ->
-    ok = emqx_authz_http_test_server:stop().
+    try
+        ok = emqx_authz_http_test_server:stop()
+    catch
+        exit:noproc ->
+            ok
+    end,
+    snabbkaffe:stop(),
+    ok.
 
 %%------------------------------------------------------------------------------
 %% Tests
@@ -148,7 +156,39 @@ t_response_handling(_Config) ->
     ?assertEqual(
         deny,
         emqx_access_control:authorize(ClientInfo, publish, <<"t">>)
-    ).
+    ),
+
+    %% the server cannot be reached; should skip to the next
+    %% authorizer in the chain.
+    ok = emqx_authz_http_test_server:stop(),
+
+    ?check_trace(
+        ?assertEqual(
+            deny,
+            emqx_access_control:authorize(ClientInfo, publish, <<"t">>)
+        ),
+        fun(Trace) ->
+            ?assertMatch(
+                [
+                    #{
+                        ?snk_kind := authz_http_request_failure,
+                        error := {recoverable_error, econnrefused}
+                    }
+                ],
+                ?of_kind(authz_http_request_failure, Trace)
+            ),
+            ?assert(
+                ?strict_causality(
+                    #{?snk_kind := authz_http_request_failure},
+                    #{?snk_kind := authz_non_superuser, result := nomatch},
+                    Trace
+                )
+            ),
+            ok
+        end
+    ),
+
+    ok.
 
 t_query_params(_Config) ->
     ok = setup_handler_and_config(

+ 1 - 0
changes/v5.0.14/fix-9689.en.md

@@ -0,0 +1 @@
+Fix handling of HTTP authorization result when a request failure (e.g.: HTTP resource is down) would cause a `function_clause` error.

+ 1 - 0
changes/v5.0.14/fix-9689.zh.md

@@ -0,0 +1 @@
+修正当请求失败(如:HTTP资源关闭)会导致`function_clause`错误时对HTTP授权结果的处理。