Call end_session_endpoint in IDP provider when login out from Console (#2476)
This commit is contained in:
@@ -3460,6 +3460,16 @@ func init() {
|
||||
],
|
||||
"summary": "Logout from Console.",
|
||||
"operationId": "Logout",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/logoutRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response."
|
||||
@@ -6426,11 +6436,22 @@ func init() {
|
||||
"loginResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"IDPRefreshToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"logoutRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"state": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"makeBucketRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -11615,6 +11636,16 @@ func init() {
|
||||
],
|
||||
"summary": "Logout from Console.",
|
||||
"operationId": "Logout",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/logoutRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response."
|
||||
@@ -14707,11 +14738,22 @@ func init() {
|
||||
"loginResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"IDPRefreshToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"logoutRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"state": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"makeBucketRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
||||
@@ -23,10 +23,15 @@ package auth
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/validate"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// NewLogoutParams creates a new LogoutParams object
|
||||
@@ -45,6 +50,12 @@ type LogoutParams struct {
|
||||
|
||||
// HTTP Request Object
|
||||
HTTPRequest *http.Request `json:"-"`
|
||||
|
||||
/*
|
||||
Required: true
|
||||
In: body
|
||||
*/
|
||||
Body *models.LogoutRequest
|
||||
}
|
||||
|
||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||
@@ -56,6 +67,33 @@ func (o *LogoutParams) BindRequest(r *http.Request, route *middleware.MatchedRou
|
||||
|
||||
o.HTTPRequest = r
|
||||
|
||||
if runtime.HasBody(r) {
|
||||
defer r.Body.Close()
|
||||
var body models.LogoutRequest
|
||||
if err := route.Consumer.Consume(r.Body, &body); err != nil {
|
||||
if err == io.EOF {
|
||||
res = append(res, errors.Required("body", "body", ""))
|
||||
} else {
|
||||
res = append(res, errors.NewParseError("body", "body", "", err))
|
||||
}
|
||||
} else {
|
||||
// validate body object
|
||||
if err := body.Validate(route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
ctx := validate.WithOperationRequest(r.Context())
|
||||
if err := body.ContextValidate(ctx, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
o.Body = &body
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = append(res, errors.Required("body", "body", ""))
|
||||
}
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
|
||||
@@ -65,6 +65,14 @@ func registerLoginHandlers(api *operations.ConsoleAPI) {
|
||||
return middleware.ResponderFunc(func(w http.ResponseWriter, p runtime.Producer) {
|
||||
cookie := NewSessionCookieForConsole(loginResponse.SessionID)
|
||||
http.SetCookie(w, &cookie)
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Path: "/",
|
||||
Name: "idp-refresh-token",
|
||||
Value: loginResponse.IDPRefreshToken,
|
||||
HttpOnly: true,
|
||||
Secure: len(GlobalPublicCerts) > 0,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
authApi.NewLoginOauth2AuthNoContent().WriteResponse(w, p)
|
||||
})
|
||||
})
|
||||
@@ -252,7 +260,8 @@ func getLoginOauth2AuthResponse(params authApi.LoginOauth2AuthParams, openIDProv
|
||||
}
|
||||
// serialize output
|
||||
loginResponse := &models.LoginResponse{
|
||||
SessionID: *token,
|
||||
SessionID: *token,
|
||||
IDPRefreshToken: identityProvider.Client.RefreshToken,
|
||||
}
|
||||
return loginResponse, nil
|
||||
}
|
||||
|
||||
@@ -17,11 +17,17 @@
|
||||
package restapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/pkg/auth/idp/oauth2"
|
||||
"github.com/minio/console/restapi/operations"
|
||||
authApi "github.com/minio/console/restapi/operations/auth"
|
||||
)
|
||||
@@ -29,13 +35,26 @@ import (
|
||||
func registerLogoutHandlers(api *operations.ConsoleAPI) {
|
||||
// logout from console
|
||||
api.AuthLogoutHandler = authApi.LogoutHandlerFunc(func(params authApi.LogoutParams, session *models.Principal) middleware.Responder {
|
||||
getLogoutResponse(session)
|
||||
err := getLogoutResponse(session, params)
|
||||
if err != nil {
|
||||
return authApi.NewLogoutDefault(int(err.Code)).WithPayload(err)
|
||||
}
|
||||
// Custom response writer to expire the session cookies
|
||||
return middleware.ResponderFunc(func(w http.ResponseWriter, p runtime.Producer) {
|
||||
expiredCookie := ExpireSessionCookie()
|
||||
// this will tell the browser to clear the cookie and invalidate user session
|
||||
// additionally we are deleting the cookie from the client side
|
||||
http.SetCookie(w, &expiredCookie)
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Path: "/",
|
||||
Name: "idp-refresh-token",
|
||||
Value: "",
|
||||
MaxAge: -1,
|
||||
Expires: time.Now().Add(-100 * time.Hour),
|
||||
HttpOnly: true,
|
||||
Secure: len(GlobalPublicCerts) > 0,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
authApi.NewLogoutOK().WriteResponse(w, p)
|
||||
})
|
||||
})
|
||||
@@ -47,8 +66,45 @@ func logout(credentials ConsoleCredentialsI) {
|
||||
}
|
||||
|
||||
// getLogoutResponse performs logout() and returns nil or errors
|
||||
func getLogoutResponse(session *models.Principal) {
|
||||
func getLogoutResponse(session *models.Principal, params authApi.LogoutParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
state := params.Body.State
|
||||
if state != "" {
|
||||
if err := logoutFromIDPProvider(params.HTTPRequest, state); err != nil {
|
||||
return ErrorWithContext(ctx, err)
|
||||
}
|
||||
}
|
||||
creds := getConsoleCredentialsFromSession(session)
|
||||
credentials := ConsoleCredentials{ConsoleCredentials: creds}
|
||||
logout(credentials)
|
||||
return nil
|
||||
}
|
||||
|
||||
func logoutFromIDPProvider(r *http.Request, state string) error {
|
||||
decodedRState, err := base64.StdEncoding.DecodeString(state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var requestItems oauth2.LoginURLParams
|
||||
err = json.Unmarshal(decodedRState, &requestItems)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerCfg := GlobalMinIOConfig.OpenIDProviders[requestItems.IDPName]
|
||||
refreshToken, err := r.Cookie("idp-refresh-token")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if providerCfg.EndSessionEndpoint != "" {
|
||||
params := url.Values{}
|
||||
params.Add("client_id", providerCfg.ClientID)
|
||||
params.Add("client_secret", providerCfg.ClientSecret)
|
||||
params.Add("refresh_token", refreshToken.Value)
|
||||
_, err := http.PostForm(providerCfg.EndSessionEndpoint, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user