fix(oidc): return to dashboard when provider calls back
fixed a bug when updating config
This commit is contained in:
parent
abc255bb02
commit
3d398873f1
|
@ -33,7 +33,7 @@
|
||||||
backend/2
|
backend/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([sso_parameters/1, login_meta/3]).
|
-export([sso_parameters/1, login_meta/4]).
|
||||||
|
|
||||||
-define(REDIRECT, 'REDIRECT').
|
-define(REDIRECT, 'REDIRECT').
|
||||||
-define(BAD_USERNAME_OR_PWD, 'BAD_USERNAME_OR_PWD').
|
-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)
|
request => emqx_utils:redact(Request)
|
||||||
}),
|
}),
|
||||||
Username = maps:get(<<"username">>, Body),
|
Username = maps:get(<<"username">>, Body),
|
||||||
{200, login_meta(Username, Role, Token)};
|
{200, login_meta(Username, Role, Token, Backend)};
|
||||||
{redirect, Redirect} ->
|
{redirect, Redirect} ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => "dashboard_sso_login_redirect",
|
msg => "dashboard_sso_login_redirect",
|
||||||
|
@ -286,11 +286,12 @@ to_redacted_json(Data) ->
|
||||||
end
|
end
|
||||||
).
|
).
|
||||||
|
|
||||||
login_meta(Username, Role, Token) ->
|
login_meta(Username, Role, Token, Backend) ->
|
||||||
#{
|
#{
|
||||||
username => Username,
|
username => Username,
|
||||||
role => Role,
|
role => Role,
|
||||||
token => Token,
|
token => Token,
|
||||||
version => iolist_to_binary(proplists:get_value(version, emqx_sys:info())),
|
version => iolist_to_binary(proplists:get_value(version, emqx_sys:info())),
|
||||||
license => #{edition => emqx_release:edition()}
|
license => #{edition => emqx_release:edition()},
|
||||||
|
backend => Backend
|
||||||
}.
|
}.
|
||||||
|
|
|
@ -107,7 +107,14 @@ get_backend_status(Backend, _) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
update(Backend, Config) ->
|
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) ->
|
delete(Backend) ->
|
||||||
update_config(Backend, {?FUNCTION_NAME, Backend}).
|
update_config(Backend, {?FUNCTION_NAME, Backend}).
|
||||||
|
|
||||||
|
|
|
@ -62,9 +62,8 @@ fields(oidc) ->
|
||||||
#{desc => ?DESC(clientid), required => true}
|
#{desc => ?DESC(clientid), required => true}
|
||||||
)},
|
)},
|
||||||
{secret,
|
{secret,
|
||||||
?HOCON(
|
emqx_schema_secret:mk(
|
||||||
binary(),
|
maps:merge(#{desc => ?DESC(secret), required => true}, #{})
|
||||||
#{desc => ?DESC(secret), required => true}
|
|
||||||
)},
|
)},
|
||||||
{scopes,
|
{scopes,
|
||||||
?HOCON(
|
?HOCON(
|
||||||
|
@ -82,7 +81,7 @@ fields(oidc) ->
|
||||||
default => <<"http://127.0.0.1:18083">>
|
default => <<"http://127.0.0.1:18083">>
|
||||||
})},
|
})},
|
||||||
{session_expiry,
|
{session_expiry,
|
||||||
?HOCON(emqx_schema:timeout_duration_ms(), #{
|
?HOCON(emqx_schema:timeout_duration_s(), #{
|
||||||
desc => ?DESC(session_expiry),
|
desc => ?DESC(session_expiry),
|
||||||
default => <<"30s">>
|
default => <<"30s">>
|
||||||
})},
|
})},
|
||||||
|
@ -217,7 +216,7 @@ login(
|
||||||
oidcc:create_redirect_url(
|
oidcc:create_redirect_url(
|
||||||
?PROVIDER_SVR_NAME,
|
?PROVIDER_SVR_NAME,
|
||||||
ClientId,
|
ClientId,
|
||||||
Secret,
|
emqx_secret:unwrap(Secret),
|
||||||
Opts#{
|
Opts#{
|
||||||
state => State,
|
state => State,
|
||||||
client_jwks => ClientJwks,
|
client_jwks => ClientJwks,
|
||||||
|
|
|
@ -30,6 +30,14 @@
|
||||||
|
|
||||||
-define(BAD_USERNAME_OR_PWD, 'BAD_USERNAME_OR_PWD').
|
-define(BAD_USERNAME_OR_PWD, 'BAD_USERNAME_OR_PWD').
|
||||||
-define(BACKEND_NOT_FOUND, 'BACKEND_NOT_FOUND').
|
-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(TAGS, <<"Dashboard Single Sign-On">>).
|
||||||
-define(BACKEND, oidc).
|
-define(BACKEND, oidc).
|
||||||
-define(BASE_PATH, "/api/v5").
|
-define(BASE_PATH, "/api/v5").
|
||||||
|
@ -66,11 +74,12 @@ schema("/sso/oidc/callback") ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
code_callback(get, #{query_string := QS}) ->
|
code_callback(get, #{query_string := QS}) ->
|
||||||
case ensure_sso_state(QS) of
|
case ensure_sso_state(QS) of
|
||||||
{ok, Username, Role, DashboardToken} ->
|
{ok, Target} ->
|
||||||
?SLOG(info, #{
|
?SLOG(info, #{
|
||||||
msg => "dashboard_sso_login_successful"
|
msg => "dashboard_sso_login_successful"
|
||||||
}),
|
}),
|
||||||
{200, login_meta(Username, Role, DashboardToken)};
|
|
||||||
|
{302, ?RESPHEADERS#{<<"location">> => Target}, ?REDIRECT_BODY};
|
||||||
{error, invalid_backend} ->
|
{error, invalid_backend} ->
|
||||||
{404, #{code => ?BACKEND_NOT_FOUND, message => <<"Backend not found">>}};
|
{404, #{code => ?BACKEND_NOT_FOUND, message => <<"Backend not found">>}};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
@ -130,7 +139,7 @@ retrieve_token(
|
||||||
Code,
|
Code,
|
||||||
Name,
|
Name,
|
||||||
ClientId,
|
ClientId,
|
||||||
Secret,
|
emqx_secret:unwrap(Secret),
|
||||||
Data#{
|
Data#{
|
||||||
redirect_uri => make_callback_url(Cfg),
|
redirect_uri => make_callback_url(Cfg),
|
||||||
client_jwks => ClientJwks,
|
client_jwks => ClientJwks,
|
||||||
|
@ -144,18 +153,21 @@ retrieve_token(
|
||||||
Error
|
Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
retrieve_userinfo(Token, #{
|
retrieve_userinfo(
|
||||||
|
Token,
|
||||||
|
#{
|
||||||
name := Name,
|
name := Name,
|
||||||
client_jwks := ClientJwks,
|
client_jwks := ClientJwks,
|
||||||
config := #{clientid := ClientId, secret := Secret},
|
config := #{clientid := ClientId, secret := Secret},
|
||||||
name_tokens := NameTks
|
name_tokens := NameTks
|
||||||
}) ->
|
} = Cfg
|
||||||
|
) ->
|
||||||
case
|
case
|
||||||
oidcc:retrieve_userinfo(
|
oidcc:retrieve_userinfo(
|
||||||
Token,
|
Token,
|
||||||
Name,
|
Name,
|
||||||
ClientId,
|
ClientId,
|
||||||
Secret,
|
emqx_secret:unwrap(Secret),
|
||||||
#{client_jwks => ClientJwks}
|
#{client_jwks => ClientJwks}
|
||||||
)
|
)
|
||||||
of
|
of
|
||||||
|
@ -165,29 +177,29 @@ retrieve_userinfo(Token, #{
|
||||||
user_info => UserInfo
|
user_info => UserInfo
|
||||||
}),
|
}),
|
||||||
Username = emqx_placeholder:proc_tmpl(NameTks, UserInfo),
|
Username = emqx_placeholder:proc_tmpl(NameTks, UserInfo),
|
||||||
ensure_user_exists(Username);
|
ensure_user_exists(Cfg, Username);
|
||||||
{error, _Reason} = Error ->
|
{error, _Reason} = Error ->
|
||||||
Error
|
Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-dialyzer({nowarn_function, ensure_user_exists/1}).
|
-dialyzer({nowarn_function, ensure_user_exists/2}).
|
||||||
ensure_user_exists(<<>>) ->
|
ensure_user_exists(_Cfg, <<>>) ->
|
||||||
{error, <<"Username can not be empty">>};
|
{error, <<"Username can not be empty">>};
|
||||||
ensure_user_exists(<<"undefined">>) ->
|
ensure_user_exists(_Cfg, <<"undefined">>) ->
|
||||||
{error, <<"Username can not be 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
|
case emqx_dashboard_admin:lookup_user(?BACKEND, Username) of
|
||||||
[User] ->
|
[User] ->
|
||||||
case emqx_dashboard_token:sign(User, <<>>) of
|
case emqx_dashboard_token:sign(User, <<>>) of
|
||||||
{ok, Role, Token} ->
|
{ok, Role, Token} ->
|
||||||
{ok, Username, Role, Token};
|
{ok, login_redirect_target(Cfg, Username, Role, Token)};
|
||||||
Error ->
|
Error ->
|
||||||
Error
|
Error
|
||||||
end;
|
end;
|
||||||
[] ->
|
[] ->
|
||||||
case emqx_dashboard_admin:add_sso_user(?BACKEND, Username, ?ROLE_VIEWER, <<>>) of
|
case emqx_dashboard_admin:add_sso_user(?BACKEND, Username, ?ROLE_VIEWER, <<>>) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
ensure_user_exists(Username);
|
ensure_user_exists(Cfg, Username);
|
||||||
Error ->
|
Error ->
|
||||||
Error
|
Error
|
||||||
end
|
end
|
||||||
|
@ -195,3 +207,8 @@ ensure_user_exists(Username) ->
|
||||||
|
|
||||||
make_callback_url(#{config := #{dashboard_addr := Addr}}) ->
|
make_callback_url(#{config := #{dashboard_addr := Addr}}) ->
|
||||||
list_to_binary(binary_to_list(Addr) ++ ?BASE_PATH ++ ?CALLBACK_PATH).
|
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>>.
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
start_link(Cfg) ->
|
start_link(Cfg) ->
|
||||||
gen_server:start_link({local, ?MODULE}, ?MODULE, Cfg, []).
|
gen_server:start_link({local, ?MODULE}, ?MODULE, Cfg, []).
|
||||||
|
|
||||||
start(Name, #{issuer := Issuer, session_expiry := SessionExpiry}) ->
|
start(Name, #{issuer := Issuer, session_expiry := SessionExpiry0}) ->
|
||||||
case
|
case
|
||||||
emqx_dashboard_sso_sup:start_child(
|
emqx_dashboard_sso_sup:start_child(
|
||||||
oidcc_provider_configuration_worker,
|
oidcc_provider_configuration_worker,
|
||||||
|
@ -57,6 +57,7 @@ start(Name, #{issuer := Issuer, session_expiry := SessionExpiry}) ->
|
||||||
{error, _} = Error ->
|
{error, _} = Error ->
|
||||||
Error;
|
Error;
|
||||||
_ ->
|
_ ->
|
||||||
|
SessionExpiry = timer:seconds(SessionExpiry0),
|
||||||
emqx_dashboard_sso_sup:start_child(?MODULE, [SessionExpiry])
|
emqx_dashboard_sso_sup:start_child(?MODULE, [SessionExpiry])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
|
@ -273,7 +273,7 @@ is_msie(Headers) ->
|
||||||
not (binary:match(UA, <<"MSIE">>) =:= nomatch).
|
not (binary:match(UA, <<"MSIE">>) =:= nomatch).
|
||||||
|
|
||||||
login_redirect_target(DashboardAddr, Username, Role, Token) ->
|
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>>.
|
<<DashboardAddr/binary, "/?login_meta=", (base64_login_meta(LoginMeta))/binary>>.
|
||||||
|
|
||||||
base64_login_meta(LoginMeta) ->
|
base64_login_meta(LoginMeta) ->
|
||||||
|
|
Loading…
Reference in New Issue