|
|
@@ -69,10 +69,21 @@ end_per_suite(Config) ->
|
|
|
suite() ->
|
|
|
[{timetrap, {seconds, 60}}].
|
|
|
|
|
|
+init_per_testcase(t_update_with_sensitive_data, Config) ->
|
|
|
+ HTTPPath = <<"/foo/bar">>,
|
|
|
+ ServerSSLOpts = false,
|
|
|
+ {ok, {HTTPPort, _Pid}} = emqx_bridge_http_connector_test_server:start_link(
|
|
|
+ _Port = random, HTTPPath, ServerSSLOpts
|
|
|
+ ),
|
|
|
+ ok = emqx_bridge_http_connector_test_server:set_handler(success_handler()),
|
|
|
+ [{path, HTTPPath}, {http_server, #{port => HTTPPort, path => HTTPPath}} | Config];
|
|
|
init_per_testcase(_TestCase, Config) ->
|
|
|
Server = start_http_server(#{response_delay_ms => 0}),
|
|
|
[{http_server, Server} | Config].
|
|
|
|
|
|
+end_per_testcase(t_update_with_sensitive_data, Config) ->
|
|
|
+ ok = emqx_bridge_http_connector_test_server:stop(),
|
|
|
+ end_per_testcase(common, proplists:delete(http_server, Config));
|
|
|
end_per_testcase(_TestCase, Config) ->
|
|
|
case ?config(http_server, Config) of
|
|
|
undefined -> ok;
|
|
|
@@ -112,6 +123,69 @@ t_compose_connector_url_and_action_path(Config) ->
|
|
|
),
|
|
|
ok.
|
|
|
|
|
|
+%% Checks that we can successfully update a connector containing sensitive headers and
|
|
|
+%% they won't be clobbered by the update.
|
|
|
+t_update_with_sensitive_data(Config) ->
|
|
|
+ ?check_trace(
|
|
|
+ begin
|
|
|
+ ConnectorCfg0 = make_connector_config(Config),
|
|
|
+ AuthHeader = <<"Bearer some_token">>,
|
|
|
+ ConnectorCfg1 = emqx_utils_maps:deep_merge(
|
|
|
+ ConnectorCfg0,
|
|
|
+ #{<<"headers">> => #{<<"authorization">> => AuthHeader}}
|
|
|
+ ),
|
|
|
+ ActionCfg = make_action_config(Config),
|
|
|
+ CreateConfig = [
|
|
|
+ {bridge_kind, action},
|
|
|
+ {action_type, ?BRIDGE_TYPE},
|
|
|
+ {action_name, ?BRIDGE_NAME},
|
|
|
+ {action_config, ActionCfg},
|
|
|
+ {connector_type, ?BRIDGE_TYPE},
|
|
|
+ {connector_name, ?CONNECTOR_NAME},
|
|
|
+ {connector_config, ConnectorCfg1}
|
|
|
+ ],
|
|
|
+ {ok, {{_, 201, _}, _, #{<<"headers">> := #{<<"authorization">> := Obfuscated}}}} =
|
|
|
+ emqx_bridge_v2_testlib:create_connector_api(CreateConfig),
|
|
|
+ {ok, _} =
|
|
|
+ emqx_bridge_v2_testlib:create_kind_api(CreateConfig),
|
|
|
+ BridgeId = emqx_bridge_resource:bridge_id(?BRIDGE_TYPE, ?BRIDGE_NAME),
|
|
|
+ {ok, _} = emqx_bridge_v2_testlib:create_rule_api(
|
|
|
+ #{
|
|
|
+ sql => <<"select * from \"t/http\" ">>,
|
|
|
+ actions => [BridgeId]
|
|
|
+ }
|
|
|
+ ),
|
|
|
+ emqx:publish(emqx_message:make(<<"t/http">>, <<"1">>)),
|
|
|
+ ?assertReceive({http, #{<<"authorization">> := AuthHeader}, _}),
|
|
|
+
|
|
|
+ %% Now update the connector and see if the header stays deobfuscated. We send the old
|
|
|
+ %% auth header as an obfuscated value to simulate the behavior of the frontend.
|
|
|
+ ConnectorCfg2 = emqx_utils_maps:deep_merge(
|
|
|
+ ConnectorCfg1,
|
|
|
+ #{
|
|
|
+ <<"headers">> => #{
|
|
|
+ <<"authorization">> => Obfuscated,
|
|
|
+ <<"other_header">> => <<"new">>
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ),
|
|
|
+ {ok, _} = emqx_bridge_v2_testlib:update_connector_api(
|
|
|
+ ?CONNECTOR_NAME,
|
|
|
+ ?BRIDGE_TYPE,
|
|
|
+ ConnectorCfg2
|
|
|
+ ),
|
|
|
+
|
|
|
+ emqx:publish(emqx_message:make(<<"t/http">>, <<"2">>)),
|
|
|
+ %% Should not be obfuscated.
|
|
|
+ ?assertReceive({http, #{<<"authorization">> := AuthHeader}, _}, 2_000),
|
|
|
+
|
|
|
+ ok
|
|
|
+ end,
|
|
|
+ []
|
|
|
+ ),
|
|
|
+
|
|
|
+ ok.
|
|
|
+
|
|
|
%%--------------------------------------------------------------------
|
|
|
%% helpers
|
|
|
%%--------------------------------------------------------------------
|
|
|
@@ -123,7 +197,10 @@ make_connector_config(Config) ->
|
|
|
<<"url">> => iolist_to_binary(io_lib:format("http://localhost:~p", [Port])),
|
|
|
<<"headers">> => #{},
|
|
|
<<"pool_type">> => <<"hash">>,
|
|
|
- <<"pool_size">> => 1
|
|
|
+ <<"pool_size">> => 1,
|
|
|
+ <<"resource_opts">> => #{
|
|
|
+ <<"health_check_interval">> => <<"100ms">>
|
|
|
+ }
|
|
|
}.
|
|
|
|
|
|
make_action_config(Config) ->
|
|
|
@@ -136,5 +213,22 @@ make_action_config(Config) ->
|
|
|
<<"method">> => <<"post">>,
|
|
|
<<"headers">> => #{},
|
|
|
<<"body">> => <<"${.}">>
|
|
|
+ },
|
|
|
+ <<"resource_opts">> => #{
|
|
|
+ <<"health_check_interval">> => <<"100ms">>
|
|
|
}
|
|
|
}.
|
|
|
+
|
|
|
+success_handler() ->
|
|
|
+ TestPid = self(),
|
|
|
+ fun(Req0, State) ->
|
|
|
+ {ok, Body, Req} = cowboy_req:read_body(Req0),
|
|
|
+ TestPid ! {http, cowboy_req:headers(Req), Body},
|
|
|
+ Rep = cowboy_req:reply(
|
|
|
+ 200,
|
|
|
+ #{<<"content-type">> => <<"application/json">>},
|
|
|
+ <<"{}">>,
|
|
|
+ Req
|
|
|
+ ),
|
|
|
+ {ok, Rep, State}
|
|
|
+ end.
|