mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-10-30 18:23:35 +08:00
Merge pull request #14801 from swordqiu/feature/qj-oidc-sp-init-logout-support
feature(apigateway): SP-initiated logout
This commit is contained in:
@@ -78,6 +78,7 @@ func (h *AuthHandlers) AddMethods() {
|
||||
NewHP(handleOIDCConfiguration, "oidc", ".well-known", "openid-configuration"),
|
||||
NewHP(handleOIDCJWKeys, "oidc", "keys"),
|
||||
NewHP(handleOIDCUserInfo, "oidc", "user"),
|
||||
NewHP(handleOIDCRPInitLogout, "oidc", "logout"),
|
||||
)
|
||||
h.AddByMethod(POST, nil,
|
||||
NewHP(h.initTotpSecrets, "initcredential"),
|
||||
@@ -89,6 +90,7 @@ func (h *AuthHandlers) AddMethods() {
|
||||
NewHP(h.handleSsoLogin, "ssologin"),
|
||||
NewHP(h.handleIdpInitSsoLogin, "ssologin", "<idp_id>"),
|
||||
NewHP(handleOIDCToken, "oidc", "token"),
|
||||
NewHP(handleOIDCRPInitLogout, "oidc", "logout"),
|
||||
)
|
||||
|
||||
// auth middleware handler
|
||||
@@ -622,7 +624,7 @@ func (h *AuthHandlers) doLogin(ctx context.Context, w http.ResponseWriter, req *
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *AuthHandlers) postLogoutHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
func doLogout(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
token, _, _ := fetchAuthInfo(ctx, req)
|
||||
if token != nil {
|
||||
// valid login, log the event
|
||||
@@ -631,6 +633,10 @@ func (h *AuthHandlers) postLogoutHandler(ctx context.Context, w http.ResponseWri
|
||||
}
|
||||
clearAuthCookie(w)
|
||||
appsrv.DisableClientCache(w)
|
||||
}
|
||||
|
||||
func (h *AuthHandlers) postLogoutHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
doLogout(ctx, w, req)
|
||||
appsrv.Send(w, "")
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -342,12 +343,14 @@ func handleOIDCConfiguration(ctx context.Context, w http.ResponseWriter, req *ht
|
||||
authUrl := httputils.JoinPath(options.Options.ApiServer, "api/v1/auth/oidc/auth")
|
||||
tokenUrl := httputils.JoinPath(options.Options.ApiServer, "api/v1/auth/oidc/token")
|
||||
userinfoUrl := httputils.JoinPath(options.Options.ApiServer, "api/v1/auth/oidc/user")
|
||||
logoutUrl := httputils.JoinPath(options.Options.ApiServer, "api/v1/auth/oidc/logout")
|
||||
jwksUrl := httputils.JoinPath(options.Options.ApiServer, "api/v1/auth/oidc/keys")
|
||||
conf := oidcutils.SOIDCConfiguration{
|
||||
Issuer: httputils.JoinPath(options.Options.ApiServer, "api/v1/auth/oidc"),
|
||||
AuthorizationEndpoint: authUrl,
|
||||
TokenEndpoint: tokenUrl,
|
||||
UserinfoEndpoint: userinfoUrl,
|
||||
EndSessionEndpoint: logoutUrl,
|
||||
JwksUri: jwksUrl,
|
||||
ResponseTypesSupported: []string{
|
||||
oidcutils.OIDC_RESPONSE_TYPE_CODE,
|
||||
@@ -410,3 +413,93 @@ func handleOIDCUserInfo(ctx context.Context, w http.ResponseWriter, req *http.Re
|
||||
}
|
||||
appsrv.SendJSON(w, data)
|
||||
}
|
||||
|
||||
type SOIDCRPInitLogoutRequest struct {
|
||||
// RECOMMENDED. ID Token previously issued by the OP to the RP passed to the Logout Endpoint
|
||||
// as a hint about the End-User's current authenticated session with the Client. This is used
|
||||
// as an indication of the identity of the End-User that the RP is requesting be logged out by the OP.
|
||||
IdTokenHint string `json:"id_token_hint"`
|
||||
// OPTIONAL. Hint to the Authorization Server about the End-User that is logging out. The value
|
||||
// and meaning of this parameter is left up to the OP's discretion. For instance, the value might
|
||||
// contain an email address, phone number, username, or session identifier pertaining to the RP's
|
||||
// session with the OP for the End-User. (This parameter is intended to be analogous to the
|
||||
// login_hint parameter defined in Section 3.1.2.1 of OpenID Connect Core 1.0 [OpenID.Core] that
|
||||
// is used in Authentication Requests; whereas, logout_hint is used in RP-Initiated Logout Requests.)
|
||||
LogoutHint string `json:"logout_hint"`
|
||||
// OPTIONAL. OAuth 2.0 Client Identifier valid at the Authorization Server. When both client_id and
|
||||
// id_token_hint are present, the OP MUST verify that the Client Identifier matches the one used when
|
||||
// issuing the ID Token. The most common use case for this parameter is to specify the Client Identifier
|
||||
// when post_logout_redirect_uri is used but id_token_hint is not. Another use is for symmetrically
|
||||
// encrypted ID Tokens used as id_token_hint values that require the Client Identifier to be specified
|
||||
// by other means, so that the ID Tokens can be decrypted by the OP.
|
||||
ClientId string `json:"client_id"`
|
||||
// OPTIONAL. URI to which the RP is requesting that the End-User's User Agent be redirected after a
|
||||
// logout has been performed. This URI SHOULD use the https scheme and MAY contain port, path, and
|
||||
// query parameter components; however, it MAY use the http scheme, provided that the Client Type is
|
||||
// confidential, as defined in Section 2.1 of OAuth 2.0 [RFC6749], and provided the OP allows the use
|
||||
// of http RP URIs. The URI MAY use an alternate scheme, such as one that is intended to identify a
|
||||
// callback into a native application. The value MUST have been previously registered with the OP,
|
||||
// either using the post_logout_redirect_uris Registration parameter or via another mechanism. An
|
||||
// id_token_hint is also RECOMMENDED when this parameter is included.
|
||||
PostLogoutRedirectUri string `json:"post_logout_redirect_uri"`
|
||||
// OPTIONAL. Opaque value used by the RP to maintain state between the logout request and the callback
|
||||
// to the endpoint specified by the post_logout_redirect_uri parameter. If included in the logout request,
|
||||
// the OP passes this value back to the RP using the state parameter when redirecting the User Agent back to the RP.
|
||||
State string `json:"state"`
|
||||
// OPTIONAL. End-User's preferred languages and scripts for the user interface, represented as a
|
||||
// space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. For instance,
|
||||
// the value "fr-CA fr en" represents a preference for French as spoken in Canada, then French (without
|
||||
// a region designation), followed by English (without a region designation). An error SHOULD NOT result
|
||||
// if some or all of the requested locales are not supported by the OpenID Provider.
|
||||
UiLocales string `json:"ui_locales"`
|
||||
}
|
||||
|
||||
func handleOIDCRPInitLogout(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
params, err := fetchOIDCRPInitLogoutParam(req)
|
||||
if err != nil {
|
||||
httperrors.GeneralServerError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
doLogout(ctx, w, req)
|
||||
var redirUrl string
|
||||
if len(params.PostLogoutRedirectUri) > 0 {
|
||||
redirUrl = params.PostLogoutRedirectUri
|
||||
if len(params.State) > 0 {
|
||||
redirUrl = addQuery(redirUrl, jsonutils.Marshal(map[string]string{"state": params.State}))
|
||||
}
|
||||
} else {
|
||||
redirUrl = getSsoAuthCallbackUrl()
|
||||
}
|
||||
appsrv.SendRedirect(w, redirUrl)
|
||||
}
|
||||
|
||||
func fetchOIDCRPInitLogoutParam(req *http.Request) (*SOIDCRPInitLogoutRequest, error) {
|
||||
var qs string
|
||||
if req.Method == "GET" {
|
||||
qs = req.URL.RawQuery
|
||||
} else if req.Method == "POST" {
|
||||
b, err := req.GetBody()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBody")
|
||||
}
|
||||
defer b.Close()
|
||||
qsBytes, err := ioutil.ReadAll(b)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ioutil.ReadAll")
|
||||
}
|
||||
qs = string(qsBytes)
|
||||
}
|
||||
params := SOIDCRPInitLogoutRequest{}
|
||||
if len(qs) == 0 {
|
||||
return ¶ms, nil
|
||||
}
|
||||
qsJson, err := jsonutils.ParseQueryString(qs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "jsonutils.ParseQueryString")
|
||||
}
|
||||
err = qsJson.Unmarshal(¶ms)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "qsJson.Unmarshal")
|
||||
}
|
||||
return ¶ms, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user