Prechádzať zdrojové kódy

Merge pull request #13238 from thalesmg/fix-authz-http-content-type-handling-r57-20240612

fix(http authz): handle unknown content types in responses
Thales Macedo Garitezi 1 rok pred
rodič
commit
6ccf1dcbf9

+ 4 - 2
apps/emqx_auth/src/emqx_authz/emqx_authz_utils.erl

@@ -188,7 +188,7 @@ render_sql_params(ParamList, Values) ->
     ),
     ),
     Row.
     Row.
 
 
--spec parse_http_resp_body(binary(), binary()) -> allow | deny | ignore | error.
+-spec parse_http_resp_body(binary(), binary()) -> allow | deny | ignore | error | {error, term()}.
 parse_http_resp_body(<<"application/x-www-form-urlencoded", _/binary>>, Body) ->
 parse_http_resp_body(<<"application/x-www-form-urlencoded", _/binary>>, Body) ->
     try
     try
         result(maps:from_list(cow_qs:parse_qs(Body)))
         result(maps:from_list(cow_qs:parse_qs(Body)))
@@ -200,7 +200,9 @@ parse_http_resp_body(<<"application/json", _/binary>>, Body) ->
         result(emqx_utils_json:decode(Body, [return_maps]))
         result(emqx_utils_json:decode(Body, [return_maps]))
     catch
     catch
         _:_ -> error
         _:_ -> error
-    end.
+    end;
+parse_http_resp_body(ContentType = <<_/binary>>, _Body) ->
+    {error, <<"unsupported content-type: ", ContentType/binary>>}.
 
 
 result(#{<<"result">> := <<"allow">>}) -> allow;
 result(#{<<"result">> := <<"allow">>}) -> allow;
 result(#{<<"result">> := <<"deny">>}) -> deny;
 result(#{<<"result">> := <<"deny">>}) -> deny;

+ 3 - 0
apps/emqx_auth_http/src/emqx_authz_http.erl

@@ -105,6 +105,9 @@ authorize(
                         body => Body
                         body => Body
                     }),
                     }),
                     nomatch;
                     nomatch;
+                {error, Reason} ->
+                    ?tp(error, bad_authz_http_response, #{reason => Reason}),
+                    nomatch;
                 Result ->
                 Result ->
                     {matched, Result}
                     {matched, Result}
             end;
             end;

+ 66 - 0
apps/emqx_auth_http/test/emqx_authz_http_SUITE.erl

@@ -463,6 +463,72 @@ t_placeholder_and_body(_Config) ->
         emqx_access_control:authorize(ClientInfo, ?AUTHZ_PUBLISH, <<"t">>)
         emqx_access_control:authorize(ClientInfo, ?AUTHZ_PUBLISH, <<"t">>)
     ).
     ).
 
 
+%% Checks that we don't crash when receiving an unsupported content-type back.
+t_bad_response_content_type(_Config) ->
+    ok = setup_handler_and_config(
+        fun(Req0, State) ->
+            ?assertEqual(
+                <<"/authz/users/">>,
+                cowboy_req:path(Req0)
+            ),
+
+            {ok, _PostVars, Req1} = cowboy_req:read_urlencoded_body(Req0),
+
+            Req = cowboy_req:reply(
+                200,
+                #{<<"content-type">> => <<"text/csv">>},
+                "hi",
+                Req1
+            ),
+            {ok, Req, State}
+        end,
+        #{
+            <<"method">> => <<"post">>,
+            <<"body">> => #{
+                <<"username">> => <<"${username}">>,
+                <<"clientid">> => <<"${clientid}">>,
+                <<"peerhost">> => <<"${peerhost}">>,
+                <<"proto_name">> => <<"${proto_name}">>,
+                <<"mountpoint">> => <<"${mountpoint}">>,
+                <<"topic">> => <<"${topic}">>,
+                <<"action">> => <<"${action}">>,
+                <<"access">> => <<"${access}">>,
+                <<"CN">> => ?PH_CERT_CN_NAME,
+                <<"CS">> => ?PH_CERT_SUBJECT
+            },
+            <<"headers">> => #{
+                <<"accept">> => <<"text/plain">>,
+                <<"content-type">> => <<"application/json">>
+            }
+        }
+    ),
+
+    ClientInfo = #{
+        clientid => <<"client id">>,
+        username => <<"user name">>,
+        peerhost => {127, 0, 0, 1},
+        protocol => <<"MQTT">>,
+        mountpoint => <<"MOUNTPOINT">>,
+        zone => default,
+        listener => {tcp, default},
+        cn => ?PH_CERT_CN_NAME,
+        dn => ?PH_CERT_SUBJECT
+    },
+
+    ?check_trace(
+        ?assertEqual(
+            deny,
+            emqx_access_control:authorize(ClientInfo, ?AUTHZ_PUBLISH, <<"t">>)
+        ),
+        fun(Trace) ->
+            ?assertMatch(
+                [#{reason := <<"unsupported content-type", _/binary>>}],
+                ?of_kind(bad_authz_http_response, Trace)
+            ),
+            ok
+        end
+    ).
+
 t_no_value_for_placeholder(_Config) ->
 t_no_value_for_placeholder(_Config) ->
     ok = setup_handler_and_config(
     ok = setup_handler_and_config(
         fun(Req0, State) ->
         fun(Req0, State) ->

+ 1 - 0
changes/ce/fix-13238.en.md

@@ -0,0 +1 @@
+Improved the logged error messages when an HTTP authorization request with an unsupported content-type header is returned.