feat(oidc): support the PKCE extension

This commit is contained in:
firest 2024-06-20 22:57:00 +08:00
parent 5e2693c9b4
commit 9c0df3c0a8
3 changed files with 29 additions and 10 deletions

View File

@ -33,6 +33,7 @@
<<"content-type">> => <<"text/plain">> <<"content-type">> => <<"text/plain">>
}). }).
-define(REDIRECT_BODY, <<"Redirecting...">>). -define(REDIRECT_BODY, <<"Redirecting...">>).
-define(PKCE_VERIFIER_LEN, 60).
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
%% Hocon Schema %% Hocon Schema
@ -84,6 +85,11 @@ fields(oidc) ->
?HOCON(emqx_schema:timeout_duration_ms(), #{ ?HOCON(emqx_schema:timeout_duration_ms(), #{
desc => ?DESC(session_expiry), desc => ?DESC(session_expiry),
default => <<"30s">> default => <<"30s">>
})},
{require_pkce,
?HOCON(boolean(), #{
desc => ?DESC(require_pkce),
default => false
})} })}
]; ];
fields(login) -> fields(login) ->
@ -133,25 +139,27 @@ login(
config := #{ config := #{
clientid := ClientId, clientid := ClientId,
secret := Secret, secret := Secret,
scopes := Scopes scopes := Scopes,
require_pkce := RequirePKCE
} }
} = Cfg } = Cfg
) -> ) ->
Nonce = emqx_dashboard_sso_oidc_session:random_bin(), Nonce = emqx_dashboard_sso_oidc_session:random_bin(),
Data = #{nonce => Nonce}, Opts = maybe_require_pkce(RequirePKCE, #{
scopes => Scopes,
nonce => Nonce,
redirect_uri => emqx_dashboard_sso_oidc_api:make_callback_url(Cfg)
}),
Data = maps:with([nonce, require_pkce, pkce_verifier], Opts),
State = emqx_dashboard_sso_oidc_session:new(Data), State = emqx_dashboard_sso_oidc_session:new(Data),
case case
oidcc:create_redirect_url( oidcc:create_redirect_url(
?PROVIDER_SVR_NAME, ?PROVIDER_SVR_NAME,
ClientId, ClientId,
Secret, Secret,
#{ Opts#{state => State}
scopes => Scopes,
state => State,
nonce => Nonce,
redirect_uri => emqx_dashboard_sso_oidc_api:make_callback_url(Cfg)
}
) )
of of
{ok, [Base, Delimiter, Params]} -> {ok, [Base, Delimiter, Params]} ->
@ -164,3 +172,11 @@ login(
convert_certs(_Dir, Conf) -> convert_certs(_Dir, Conf) ->
Conf. Conf.
maybe_require_pkce(false, Opts) ->
Opts;
maybe_require_pkce(true, Opts) ->
Opts#{
require_pkce => true,
pkce_verifier => emqx_dashboard_sso_oidc_session:random_bin(?PKCE_VERIFIER_LEN)
}.

View File

@ -115,7 +115,7 @@ ensure_oidc_state(#{<<"state">> := State} = QS, Cfg) ->
retrieve_token( retrieve_token(
#{<<"code">> := Code}, #{<<"code">> := Code},
#{name := Name, config := #{clientid := ClientId, secret := Secret}} = Cfg, #{name := Name, config := #{clientid := ClientId, secret := Secret}} = Cfg,
#{nonce := Nonce} = _Data Data
) -> ) ->
case case
oidcc:retrieve_token( oidcc:retrieve_token(
@ -123,7 +123,7 @@ retrieve_token(
Name, Name,
ClientId, ClientId,
Secret, Secret,
#{redirect_uri => make_callback_url(Cfg), nonce => Nonce} Data#{redirect_uri => make_callback_url(Cfg)}
) )
of of
{ok, Token} -> {ok, Token} ->

View File

@ -21,4 +21,7 @@ dashboard_addr.desc:
session_expiry.desc: session_expiry.desc:
"""The valid time span for an OIDC `state`, the default is `30s`, if the code response returned by the authorization server exceeds this time span, it will be treated as invalid.""" """The valid time span for an OIDC `state`, the default is `30s`, if the code response returned by the authorization server exceeds this time span, it will be treated as invalid."""
require_pkce.desc:
"""Whether to require PKCE when getting the token."""
} }