Browse Source

fix(oidc): return to dashboard when provider calls back

fixed a bug when updating config
firest 1 year ago
parent
commit
3d398873f1

+ 5 - 4
apps/emqx_dashboard_sso/src/emqx_dashboard_sso_api.erl

@@ -33,7 +33,7 @@
     backend/2
 ]).
 
--export([sso_parameters/1, login_meta/3]).
+-export([sso_parameters/1, login_meta/4]).
 
 -define(REDIRECT, 'REDIRECT').
 -define(BAD_USERNAME_OR_PWD, 'BAD_USERNAME_OR_PWD').
@@ -168,7 +168,7 @@ login(post, #{bindings := #{backend := Backend}, body := Body} = Request) ->
                         request => emqx_utils:redact(Request)
                     }),
                     Username = maps:get(<<"username">>, Body),
-                    {200, login_meta(Username, Role, Token)};
+                    {200, login_meta(Username, Role, Token, Backend)};
                 {redirect, Redirect} ->
                     ?SLOG(info, #{
                         msg => "dashboard_sso_login_redirect",
@@ -286,11 +286,12 @@ to_redacted_json(Data) ->
         end
     ).
 
-login_meta(Username, Role, Token) ->
+login_meta(Username, Role, Token, Backend) ->
     #{
         username => Username,
         role => Role,
         token => Token,
         version => iolist_to_binary(proplists:get_value(version, emqx_sys:info())),
-        license => #{edition => emqx_release:edition()}
+        license => #{edition => emqx_release:edition()},
+        backend => Backend
     }.

+ 8 - 1
apps/emqx_dashboard_sso/src/emqx_dashboard_sso_manager.erl

@@ -107,7 +107,14 @@ get_backend_status(Backend, _) ->
     end.
 
 update(Backend, Config) ->
-    update_config(Backend, {?FUNCTION_NAME, Backend, Config}).
+    UpdateConf =
+        case emqx:get_raw_config(?MOD_KEY_PATH(Backend), #{}) of
+            RawConf when is_map(RawConf) ->
+                emqx_utils:deobfuscate(Config, RawConf);
+            null ->
+                Config
+        end,
+    update_config(Backend, {?FUNCTION_NAME, Backend, UpdateConf}).
 delete(Backend) ->
     update_config(Backend, {?FUNCTION_NAME, Backend}).
 

+ 4 - 5
apps/emqx_dashboard_sso/src/emqx_dashboard_sso_oidc.erl

@@ -62,9 +62,8 @@ fields(oidc) ->
                     #{desc => ?DESC(clientid), required => true}
                 )},
             {secret,
-                ?HOCON(
-                    binary(),
-                    #{desc => ?DESC(secret), required => true}
+                emqx_schema_secret:mk(
+                    maps:merge(#{desc => ?DESC(secret), required => true}, #{})
                 )},
             {scopes,
                 ?HOCON(
@@ -82,7 +81,7 @@ fields(oidc) ->
                     default => <<"http://127.0.0.1:18083">>
                 })},
             {session_expiry,
-                ?HOCON(emqx_schema:timeout_duration_ms(), #{
+                ?HOCON(emqx_schema:timeout_duration_s(), #{
                     desc => ?DESC(session_expiry),
                     default => <<"30s">>
                 })},
@@ -217,7 +216,7 @@ login(
         oidcc:create_redirect_url(
             ?PROVIDER_SVR_NAME,
             ClientId,
-            Secret,
+            emqx_secret:unwrap(Secret),
             Opts#{
                 state => State,
                 client_jwks => ClientJwks,

+ 34 - 17
apps/emqx_dashboard_sso/src/emqx_dashboard_sso_oidc_api.erl

@@ -30,6 +30,14 @@
 
 -define(BAD_USERNAME_OR_PWD, 'BAD_USERNAME_OR_PWD').
 -define(BACKEND_NOT_FOUND, 'BACKEND_NOT_FOUND').
+
+-define(RESPHEADERS, #{
+    <<"cache-control">> => <<"no-cache">>,
+    <<"pragma">> => <<"no-cache">>,
+    <<"content-type">> => <<"text/plain">>
+}).
+-define(REDIRECT_BODY, <<"Redirecting...">>).
+
 -define(TAGS, <<"Dashboard Single Sign-On">>).
 -define(BACKEND, oidc).
 -define(BASE_PATH, "/api/v5").
@@ -66,11 +74,12 @@ schema("/sso/oidc/callback") ->
 %%--------------------------------------------------------------------
 code_callback(get, #{query_string := QS}) ->
     case ensure_sso_state(QS) of
-        {ok, Username, Role, DashboardToken} ->
+        {ok, Target} ->
             ?SLOG(info, #{
                 msg => "dashboard_sso_login_successful"
             }),
-            {200, login_meta(Username, Role, DashboardToken)};
+
+            {302, ?RESPHEADERS#{<<"location">> => Target}, ?REDIRECT_BODY};
         {error, invalid_backend} ->
             {404, #{code => ?BACKEND_NOT_FOUND, message => <<"Backend not found">>}};
         {error, Reason} ->
@@ -130,7 +139,7 @@ retrieve_token(
             Code,
             Name,
             ClientId,
-            Secret,
+            emqx_secret:unwrap(Secret),
             Data#{
                 redirect_uri => make_callback_url(Cfg),
                 client_jwks => ClientJwks,
@@ -144,18 +153,21 @@ retrieve_token(
             Error
     end.
 
-retrieve_userinfo(Token, #{
-    name := Name,
-    client_jwks := ClientJwks,
-    config := #{clientid := ClientId, secret := Secret},
-    name_tokens := NameTks
-}) ->
+retrieve_userinfo(
+    Token,
+    #{
+        name := Name,
+        client_jwks := ClientJwks,
+        config := #{clientid := ClientId, secret := Secret},
+        name_tokens := NameTks
+    } = Cfg
+) ->
     case
         oidcc:retrieve_userinfo(
             Token,
             Name,
             ClientId,
-            Secret,
+            emqx_secret:unwrap(Secret),
             #{client_jwks => ClientJwks}
         )
     of
@@ -165,29 +177,29 @@ retrieve_userinfo(Token, #{
                 user_info => UserInfo
             }),
             Username = emqx_placeholder:proc_tmpl(NameTks, UserInfo),
-            ensure_user_exists(Username);
+            ensure_user_exists(Cfg, Username);
         {error, _Reason} = Error ->
             Error
     end.
 
--dialyzer({nowarn_function, ensure_user_exists/1}).
-ensure_user_exists(<<>>) ->
+-dialyzer({nowarn_function, ensure_user_exists/2}).
+ensure_user_exists(_Cfg, <<>>) ->
     {error, <<"Username can not be empty">>};
-ensure_user_exists(<<"undefined">>) ->
+ensure_user_exists(_Cfg, <<"undefined">>) ->
     {error, <<"Username can not be undefined">>};
-ensure_user_exists(Username) ->
+ensure_user_exists(Cfg, Username) ->
     case emqx_dashboard_admin:lookup_user(?BACKEND, Username) of
         [User] ->
             case emqx_dashboard_token:sign(User, <<>>) of
                 {ok, Role, Token} ->
-                    {ok, Username, Role, Token};
+                    {ok, login_redirect_target(Cfg, Username, Role, Token)};
                 Error ->
                     Error
             end;
         [] ->
             case emqx_dashboard_admin:add_sso_user(?BACKEND, Username, ?ROLE_VIEWER, <<>>) of
                 {ok, _} ->
-                    ensure_user_exists(Username);
+                    ensure_user_exists(Cfg, Username);
                 Error ->
                     Error
             end
@@ -195,3 +207,8 @@ ensure_user_exists(Username) ->
 
 make_callback_url(#{config := #{dashboard_addr := Addr}}) ->
     list_to_binary(binary_to_list(Addr) ++ ?BASE_PATH ++ ?CALLBACK_PATH).
+
+login_redirect_target(#{config := #{dashboard_addr := Addr}}, Username, Role, Token) ->
+    LoginMeta = emqx_dashboard_sso_api:login_meta(Username, Role, Token, oidc),
+    MetaBin = base64:encode(emqx_utils_json:encode(LoginMeta)),
+    <<Addr/binary, "/?login_meta=", MetaBin/binary>>.

+ 2 - 1
apps/emqx_dashboard_sso/src/emqx_dashboard_sso_oidc_session.erl

@@ -42,7 +42,7 @@
 start_link(Cfg) ->
     gen_server:start_link({local, ?MODULE}, ?MODULE, Cfg, []).
 
-start(Name, #{issuer := Issuer, session_expiry := SessionExpiry}) ->
+start(Name, #{issuer := Issuer, session_expiry := SessionExpiry0}) ->
     case
         emqx_dashboard_sso_sup:start_child(
             oidcc_provider_configuration_worker,
@@ -57,6 +57,7 @@ start(Name, #{issuer := Issuer, session_expiry := SessionExpiry}) ->
         {error, _} = Error ->
             Error;
         _ ->
+            SessionExpiry = timer:seconds(SessionExpiry0),
             emqx_dashboard_sso_sup:start_child(?MODULE, [SessionExpiry])
     end.
 

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

@@ -273,7 +273,7 @@ is_msie(Headers) ->
     not (binary:match(UA, <<"MSIE">>) =:= nomatch).
 
 login_redirect_target(DashboardAddr, Username, Role, Token) ->
-    LoginMeta = emqx_dashboard_sso_api:login_meta(Username, Role, Token),
+    LoginMeta = emqx_dashboard_sso_api:login_meta(Username, Role, Token, saml),
     <<DashboardAddr/binary, "/?login_meta=", (base64_login_meta(LoginMeta))/binary>>.
 
 base64_login_meta(LoginMeta) ->