add: handle trigger of logout for third-party and session_state

This commit is contained in:
ybelMekk
2022-01-23 23:14:25 +01:00
parent e4c47f59e8
commit a23595b9b4
3 changed files with 25 additions and 14 deletions

View File

@@ -1,27 +1,26 @@
package router
import (
"net/http"
log "github.com/sirupsen/logrus"
"net/http"
)
// FrontChannelLogout triggers logout triggered by a third-party.
func (h *Handler) FrontChannelLogout(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
sid := params.Get("sid")
sessionParamKeys := []string{"sid", "session_state"}
externalSessionID := extractExternalSessionID(r, sessionParamKeys)
// Unconditionally destroy all local references to the session.
h.deleteCookie(w, SessionCookieName, h.Cookies)
if len(sid) == 0 {
log.Info("sid parameter not set in request; ignoring")
if len(externalSessionID) == 0 {
log.Infof("any of parameters %q not set in request; ignoring", sessionParamKeys)
h.DeleteSessionFallback(w, r)
w.WriteHeader(http.StatusOK)
return
}
sessionID := h.localSessionID(sid)
sessionID := h.localSessionID(externalSessionID)
err := h.destroySession(w, r, sessionID)
if err != nil {
@@ -31,3 +30,15 @@ func (h *Handler) FrontChannelLogout(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func extractExternalSessionID(r *http.Request, paramKeys []string) string {
params := r.URL.Query()
var sessionId = ""
for _, k := range paramKeys {
sessionId = params.Get(k)
if len(sessionId) == 0 {
continue
}
}
return sessionId
}

View File

@@ -321,7 +321,7 @@ func TestHandler_FrontChannelLogoutWithCheckSessionIframe(t *testing.T) {
ciphertext, err := base64.StdEncoding.DecodeString(sessionCookie.Value)
assert.NoError(t, err)
sid, err := h.Crypter.Decrypt(ciphertext)
sessionState, err := h.Crypter.Decrypt(ciphertext)
assert.NoError(t, err)
frontchannelLogoutURL, err := url.Parse(server.URL)
@@ -330,7 +330,7 @@ func TestHandler_FrontChannelLogoutWithCheckSessionIframe(t *testing.T) {
frontchannelLogoutURL.Path = "/oauth2/logout/frontchannel"
values := url.Values{}
values.Add("sid", string(sid))
values.Add("session_state", string(sessionState))
values.Add("iss", idp.GetOpenIDConfiguration().Issuer)
frontchannelLogoutURL.RawQuery = values.Encode()

View File

@@ -15,13 +15,13 @@ import (
"github.com/nais/wonderwall/pkg/session"
)
// localSessionID prefixes the given `sid` with the given client ID to prevent key collisions.
// `sid` is a key that refers to the user's unique SSO session at the Identity Provider, and the same key is present
// localSessionID prefixes the given `sid` or `session_state` with the given client ID to prevent key collisions.
// `sid` or `session_state` is a key that refers to the user's unique SSO session at the Identity Provider, and the same key is present
// in all tokens acquired by any Relying Party (such as Wonderwall) during that session.
// Thus, we cannot assume that the value of `sid` to uniquely identify the pair of (user, application session)
// Thus, we cannot assume that the value of `sid` or `session_state` to uniquely identify the pair of (user, application session)
// if using a shared session store.
func (h *Handler) localSessionID(sid string) string {
return fmt.Sprintf("%s:%s:%s", h.Config.OpenID.Provider, h.Provider.GetClientConfiguration().GetClientID(), sid)
func (h *Handler) localSessionID(externalSessionID string) string {
return fmt.Sprintf("%s:%s:%s", h.Config.OpenID.Provider, h.Provider.GetClientConfiguration().GetClientID(), externalSessionID)
}
func (h *Handler) getSessionFromCookie(w http.ResponseWriter, r *http.Request) (*session.Data, error) {