Kaynağa Gözat

fix(sso): add convet_certs callback for sso backends

must convert certs in pre_config_update so the cert path refernces
are stored in raw config, otherwise the files might get gc:ed
Zaiming (Stone) Shi 2 yıl önce
ebeveyn
işleme
bb49914fd6

+ 10 - 1
apps/emqx_dashboard_sso/src/emqx_dashboard_sso.erl

@@ -13,7 +13,8 @@
     create/2,
     update/3,
     destroy/2,
-    login/3
+    login/3,
+    convert_certs/3
 ]).
 
 -export([types/0, modules/0, provider/1, backends/0, format/1]).
@@ -45,6 +46,11 @@
     | {redirect, tuple()}
     | {error, Reason :: term()}.
 
+-callback convert_certs(
+    Dir :: file:filename_all(),
+    config()
+) -> config().
+
 %%------------------------------------------------------------------------------
 %% Callback Interface
 %%------------------------------------------------------------------------------
@@ -68,6 +74,9 @@ destroy(Mod, State) ->
 login(Mod, Req, State) ->
     Mod:login(Req, State).
 
+convert_certs(Mod, Dir, Config) ->
+    Mod:convert_certs(Dir, Config).
+
 %%------------------------------------------------------------------------------
 %% API
 %%------------------------------------------------------------------------------

+ 20 - 1
apps/emqx_dashboard_sso/src/emqx_dashboard_sso_ldap.erl

@@ -22,7 +22,8 @@
     login/2,
     create/1,
     update/2,
-    destroy/1
+    destroy/1,
+    convert_certs/2
 ]).
 
 %%------------------------------------------------------------------------------
@@ -163,3 +164,21 @@ ensure_user_exists(Username) ->
                     Error
             end
     end.
+
+convert_certs(Dir, Conf) ->
+    case
+        emqx_tls_lib:ensure_ssl_files(
+            Dir, maps:get(<<"ssl">>, Conf, undefined)
+        )
+    of
+        {ok, SSL} ->
+            new_ssl_source(Conf, SSL);
+        {error, Reason} ->
+            ?SLOG(error, Reason#{msg => "bad_ssl_config"}),
+            throw({bad_ssl_config, Reason})
+    end.
+
+new_ssl_source(Source, undefined) ->
+    Source;
+new_ssl_source(Source, SSL) ->
+    Source#{<<"ssl">> => SSL}.

+ 6 - 19
apps/emqx_dashboard_sso/src/emqx_dashboard_sso_manager.erl

@@ -52,7 +52,7 @@
 
 -record(?MOD_TAB, {
     backend :: atom(),
-    state :: map(),
+    state :: undefined | map(),
     last_error = ?NO_ERROR :: term()
 }).
 
@@ -217,7 +217,7 @@ update_config(Backend, UpdateReq) ->
     end.
 
 pre_config_update(_, {update, _Backend, Config}, _OldConf) ->
-    maybe_write_certs(Config);
+    {ok, maybe_write_certs(Config)};
 pre_config_update(_, {delete, _Backend}, undefined) ->
     throw(not_exists);
 pre_config_update(_, {delete, _Backend}, _OldConf) ->
@@ -333,26 +333,13 @@ remove_handler() ->
     ok = emqx_conf:remove_handler(?MOD_KEY_PATH('?')).
 
 maybe_write_certs(#{<<"backend">> := Backend} = Conf) ->
-    case
-        emqx_tls_lib:ensure_ssl_files(
-            ssl_file_path(Backend), maps:get(<<"ssl">>, Conf, undefined)
-        )
-    of
-        {ok, SSL} ->
-            {ok, new_ssl_source(Conf, SSL)};
-        {error, Reason} ->
-            ?SLOG(error, Reason#{msg => "bad_ssl_config"}),
-            throw({bad_ssl_config, Reason})
-    end.
+    Dir = certs_path(Backend),
+    Provider = provider(Backend),
+    emqx_dashboard_sso:convert_certs(Provider, Dir, Conf).
 
-ssl_file_path(Backend) ->
+certs_path(Backend) ->
     filename:join(["sso", Backend]).
 
-new_ssl_source(Source, undefined) ->
-    Source;
-new_ssl_source(Source, SSL) ->
-    Source#{<<"ssl">> => SSL}.
-
 update_state(Backend, State) ->
     Data = ensure_backend_data(Backend),
     ets:insert(?MOD_TAB, Data#?MOD_TAB{state = State}).

+ 24 - 14
apps/emqx_dashboard_sso/src/emqx_dashboard_sso_saml.erl

@@ -22,7 +22,8 @@
 -export([
     create/1,
     update/2,
-    destroy/1
+    destroy/1,
+    convert_certs/2
 ]).
 
 -export([login/2, callback/2]).
@@ -102,7 +103,7 @@ desc(_) ->
 
 create(#{sp_sign_request := true} = Config) ->
     try
-        do_create(ensure_cert_and_key(Config))
+        do_create(Config)
     catch
         Kind:Error ->
             Msg = failed_to_ensure_cert_and_key,
@@ -150,10 +151,31 @@ callback(_Req = #{body := Body}, #{sp := SP, dashboard_addr := DashboardAddr} =
             {error, iolist_to_binary(Reason)}
     end.
 
+convert_certs(
+    Dir,
+    #{<<"sp_sign_request">> := true, <<"sp_public_key">> := Cert, <<"sp_private_key">> := Key} =
+        Conf
+) ->
+    case
+        emqx_tls_lib:ensure_ssl_files(
+            Dir, #{enable => ture, certfile => Cert, keyfile => Key}, #{}
+        )
+    of
+        {ok, #{certfile := CertPath, keyfile := KeyPath}} ->
+            Conf#{<<"sp_public_key">> => bin(CertPath), <<"sp_private_key">> => bin(KeyPath)};
+        {error, Reason} ->
+            ?SLOG(error, #{msg => "failed_to_save_sp_sign_keys", reason => Reason}),
+            throw("Failed to save sp signing key(s)")
+    end;
+convert_certs(_Dir, Conf) ->
+    Conf.
+
 %%------------------------------------------------------------------------------
 %% Internal functions
 %%------------------------------------------------------------------------------
 
+bin(X) -> iolist_to_binary(X).
+
 do_create(
     #{
         dashboard_addr := DashboardAddr,
@@ -222,18 +244,6 @@ gen_redirect_response(DashboardAddr, Username) ->
 %% Helpers functions
 %%------------------------------------------------------------------------------
 
-ensure_cert_and_key(#{sp_public_key := Cert, sp_private_key := Key} = Config) ->
-    case
-        emqx_tls_lib:ensure_ssl_files(
-            ?DIR, #{enable => ture, certfile => Cert, keyfile => Key}, #{}
-        )
-    of
-        {ok, #{certfile := CertPath, keyfile := KeyPath} = _NSSL} ->
-            Config#{sp_public_key => CertPath, sp_private_key => KeyPath};
-        {error, #{which_options := KeyPath}} ->
-            error({missing_key, lists:flatten(KeyPath)})
-    end.
-
 %% TODO: unify with emqx_dashboard_sso_manager:ensure_user_exists/1
 ensure_user_exists(Username) ->
     case emqx_dashboard_admin:lookup_user(saml, Username) of