Merge pull request #10550 from thalesmg/fix-ocsp-disabled-r50

fix(ocsp): disable periodic refresh when listener or stapling are disabled
This commit is contained in:
Thales Macedo Garitezi 2023-04-27 17:22:44 -03:00 committed by GitHub
commit 270fa5d19d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 7 deletions

View File

@ -441,6 +441,7 @@ post_config_update([listeners, Type, Name], {create, _Request}, NewConf, undefin
start_listener(Type, Name, NewConf); start_listener(Type, Name, NewConf);
post_config_update([listeners, Type, Name], {update, _Request}, NewConf, OldConf, _AppEnvs) -> post_config_update([listeners, Type, Name], {update, _Request}, NewConf, OldConf, _AppEnvs) ->
try_clear_ssl_files(certs_dir(Type, Name), NewConf, OldConf), try_clear_ssl_files(certs_dir(Type, Name), NewConf, OldConf),
ok = maybe_unregister_ocsp_stapling_refresh(Type, Name, NewConf),
case NewConf of case NewConf of
#{enabled := true} -> restart_listener(Type, Name, {OldConf, NewConf}); #{enabled := true} -> restart_listener(Type, Name, {OldConf, NewConf});
_ -> ok _ -> ok
@ -448,6 +449,7 @@ post_config_update([listeners, Type, Name], {update, _Request}, NewConf, OldConf
post_config_update([listeners, _Type, _Name], '$remove', undefined, undefined, _AppEnvs) -> post_config_update([listeners, _Type, _Name], '$remove', undefined, undefined, _AppEnvs) ->
ok; ok;
post_config_update([listeners, Type, Name], '$remove', undefined, OldConf, _AppEnvs) -> post_config_update([listeners, Type, Name], '$remove', undefined, OldConf, _AppEnvs) ->
ok = unregister_ocsp_stapling_refresh(Type, Name),
case stop_listener(Type, Name, OldConf) of case stop_listener(Type, Name, OldConf) of
ok -> ok ->
_ = emqx_authentication:delete_chain(listener_id(Type, Name)), _ = emqx_authentication:delete_chain(listener_id(Type, Name)),
@ -460,10 +462,18 @@ post_config_update([listeners, Type, Name], {action, _Action, _}, NewConf, OldCo
#{enabled := NewEnabled} = NewConf, #{enabled := NewEnabled} = NewConf,
#{enabled := OldEnabled} = OldConf, #{enabled := OldEnabled} = OldConf,
case {NewEnabled, OldEnabled} of case {NewEnabled, OldEnabled} of
{true, true} -> restart_listener(Type, Name, {OldConf, NewConf}); {true, true} ->
{true, false} -> start_listener(Type, Name, NewConf); ok = maybe_unregister_ocsp_stapling_refresh(Type, Name, NewConf),
{false, true} -> stop_listener(Type, Name, OldConf); restart_listener(Type, Name, {OldConf, NewConf});
{false, false} -> stop_listener(Type, Name, OldConf) {true, false} ->
ok = maybe_unregister_ocsp_stapling_refresh(Type, Name, NewConf),
start_listener(Type, Name, NewConf);
{false, true} ->
ok = unregister_ocsp_stapling_refresh(Type, Name),
stop_listener(Type, Name, OldConf);
{false, false} ->
ok = unregister_ocsp_stapling_refresh(Type, Name),
stop_listener(Type, Name, OldConf)
end; end;
post_config_update(_Path, _Request, _NewConf, _OldConf, _AppEnvs) -> post_config_update(_Path, _Request, _NewConf, _OldConf, _AppEnvs) ->
ok. ok.
@ -813,3 +823,16 @@ inject_crl_config(
}; };
inject_crl_config(Conf) -> inject_crl_config(Conf) ->
Conf. Conf.
maybe_unregister_ocsp_stapling_refresh(
ssl = Type, Name, #{ssl_options := #{ocsp := #{enable_ocsp_stapling := false}}} = _Conf
) ->
unregister_ocsp_stapling_refresh(Type, Name),
ok;
maybe_unregister_ocsp_stapling_refresh(_Type, _Name, _Conf) ->
ok.
unregister_ocsp_stapling_refresh(Type, Name) ->
ListenerId = listener_id(Type, Name),
emqx_ocsp_cache:unregister_listener(ListenerId),
ok.

View File

@ -30,6 +30,7 @@
sni_fun/2, sni_fun/2,
fetch_response/1, fetch_response/1,
register_listener/2, register_listener/2,
unregister_listener/1,
inject_sni_fun/2 inject_sni_fun/2
]). ]).
@ -107,6 +108,9 @@ fetch_response(ListenerID) ->
register_listener(ListenerID, Opts) -> register_listener(ListenerID, Opts) ->
gen_server:call(?MODULE, {register_listener, ListenerID, Opts}, ?CALL_TIMEOUT). gen_server:call(?MODULE, {register_listener, ListenerID, Opts}, ?CALL_TIMEOUT).
unregister_listener(ListenerID) ->
gen_server:cast(?MODULE, {unregister_listener, ListenerID}).
-spec inject_sni_fun(emqx_listeners:listener_id(), map()) -> map(). -spec inject_sni_fun(emqx_listeners:listener_id(), map()) -> map().
inject_sni_fun(ListenerID, Conf0) -> inject_sni_fun(ListenerID, Conf0) ->
SNIFun = emqx_const_v1:make_sni_fun(ListenerID), SNIFun = emqx_const_v1:make_sni_fun(ListenerID),
@ -160,6 +164,18 @@ handle_call({register_listener, ListenerID, Conf}, _From, State0) ->
handle_call(Call, _From, State) -> handle_call(Call, _From, State) ->
{reply, {error, {unknown_call, Call}}, State}. {reply, {error, {unknown_call, Call}}, State}.
handle_cast({unregister_listener, ListenerID}, State0) ->
State2 =
case maps:take(?REFRESH_TIMER(ListenerID), State0) of
error ->
State0;
{TRef, State1} ->
emqx_utils:cancel_timer(TRef),
State1
end,
State = maps:remove({refresh_interval, ListenerID}, State2),
?tp(ocsp_cache_listener_unregistered, #{listener_id => ListenerID}),
{noreply, State};
handle_cast(_Cast, State) -> handle_cast(_Cast, State) ->
{noreply, State}. {noreply, State}.

View File

@ -254,10 +254,15 @@ does_module_exist(Mod) ->
end. end.
assert_no_http_get() -> assert_no_http_get() ->
Timeout = 0,
Error = should_be_cached,
assert_no_http_get(Timeout, Error).
assert_no_http_get(Timeout, Error) ->
receive receive
{http_get, _URL} -> {http_get, _URL} ->
error(should_be_cached) error(Error)
after 0 -> after Timeout ->
ok ok
end. end.
@ -702,7 +707,9 @@ do_t_update_listener(Config) ->
%% the API converts that to an internally %% the API converts that to an internally
%% managed file %% managed file
<<"issuer_pem">> => IssuerPem, <<"issuer_pem">> => IssuerPem,
<<"responder_url">> => <<"http://localhost:9877">> <<"responder_url">> => <<"http://localhost:9877">>,
%% for quicker testing; min refresh in tests is 5 s.
<<"refresh_interval">> => <<"5s">>
} }
} }
}, },
@ -739,6 +746,70 @@ do_t_update_listener(Config) ->
) )
), ),
assert_http_get(1, 5_000), assert_http_get(1, 5_000),
%% Disable OCSP Stapling; the periodic refreshes should stop
RefreshInterval = emqx_config:get([listeners, ssl, default, ssl_options, ocsp, refresh_interval]),
OCSPConfig1 =
#{
<<"ssl_options">> =>
#{
<<"ocsp">> =>
#{
<<"enable_ocsp_stapling">> => false
}
}
},
ListenerData3 = emqx_utils_maps:deep_merge(ListenerData2, OCSPConfig1),
{ok, {_, _, ListenerData4}} = update_listener_via_api(ListenerId, ListenerData3),
?assertMatch(
#{
<<"ssl_options">> :=
#{
<<"ocsp">> :=
#{
<<"enable_ocsp_stapling">> := false
}
}
},
ListenerData4
),
assert_no_http_get(2 * RefreshInterval, should_stop_refreshing),
ok.
t_double_unregister(_Config) ->
ListenerID = <<"ssl:test_ocsp">>,
Conf = emqx_config:get_listener_conf(ssl, test_ocsp, []),
?check_trace(
begin
{ok, {ok, _}} =
?wait_async_action(
emqx_ocsp_cache:register_listener(ListenerID, Conf),
#{?snk_kind := ocsp_http_fetch_and_cache, listener_id := ListenerID},
5_000
),
assert_http_get(1),
{ok, {ok, _}} =
?wait_async_action(
emqx_ocsp_cache:unregister_listener(ListenerID),
#{?snk_kind := ocsp_cache_listener_unregistered, listener_id := ListenerID},
5_000
),
%% Should be idempotent and not crash
{ok, {ok, _}} =
?wait_async_action(
emqx_ocsp_cache:unregister_listener(ListenerID),
#{?snk_kind := ocsp_cache_listener_unregistered, listener_id := ListenerID},
5_000
),
ok
end,
[]
),
ok. ok.
t_ocsp_responder_error_responses(_Config) -> t_ocsp_responder_error_responses(_Config) ->