From 1fcc97819b5d4fc3032045e339125978a61fe418 Mon Sep 17 00:00:00 2001 From: Trong Huu Nguyen Date: Mon, 23 Aug 2021 10:26:47 +0200 Subject: [PATCH] feat: implement self-initiated logout Co-authored-by: Kent Daleng --- pkg/config/config.go | 37 ++++++++++++++++++++----------------- pkg/router/router.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index b2004ef..5ba004e 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -16,26 +16,28 @@ type Config struct { } type IDPorten struct { - ClientID string `json:"client-id"` - ClientJWK string `json:"client-jwk"` - RedirectURI string `json:"redirect-uri"` - WellKnownURL string `json:"well-known-url"` - WellKnown IDPortenWellKnown `json:"well-known"` - Locale string `json:"locale"` - SecurityLevel string `json:"security-level"` + ClientID string `json:"client-id"` + ClientJWK string `json:"client-jwk"` + RedirectURI string `json:"redirect-uri"` + WellKnownURL string `json:"well-known-url"` + WellKnown IDPortenWellKnown `json:"well-known"` + Locale string `json:"locale"` + SecurityLevel string `json:"security-level"` + PostLogoutRedirectURI string `json:"post-logout-redirect-uri"` } const ( - BindAddress = "bind-address" - UpstreamHost = "upstream-host" - LogFormat = "log-format" - LogLevel = "log-level" - IDPortenClientID = "idporten.client-id" - IDPortenClientJWK = "idporten.client-jwk" - IDPortenRedirectURI = "idporten.redirect-uri" - IDPortenWellKnownURL = "idporten.well-known-url" - IDPortenLocale = "idporten.locale" - IDPortenSecurityLevel = "idporten.security-level" + BindAddress = "bind-address" + UpstreamHost = "upstream-host" + LogFormat = "log-format" + LogLevel = "log-level" + IDPortenClientID = "idporten.client-id" + IDPortenClientJWK = "idporten.client-jwk" + IDPortenRedirectURI = "idporten.redirect-uri" + IDPortenWellKnownURL = "idporten.well-known-url" + IDPortenLocale = "idporten.locale" + IDPortenSecurityLevel = "idporten.security-level" + IDPortenPostLogoutRedirectURI = "idporten.post-logout-redirect-uri" ) func bindNAIS() { @@ -55,6 +57,7 @@ func Initialize() *Config { flag.String(UpstreamHost, "127.0.0.1:8080", "Address of upstream host.") flag.String(IDPortenSecurityLevel, "Level4", "Requested security level, either Level3 or Level4.") flag.String(IDPortenLocale, "nb", "Locale for OAuth2 consent screen.") + flag.String(IDPortenPostLogoutRedirectURI, "https://nav.no", "URI for redirecting the user after successful logout at IDPorten.") return &Config{} } diff --git a/pkg/router/router.go b/pkg/router/router.go index c1df6e2..2665e4c 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -361,11 +361,52 @@ func (h *Handler) Default(w http.ResponseWriter, r *http.Request) { io.Copy(w, upstreamResponse.Body) } +// Logout triggers self-initiated for the current user +func (h *Handler) Logout(w http.ResponseWriter, r *http.Request) { + sessionCookie, err := r.Cookie(SessionCookieName) + if err != nil { + log.Tracef("no session cookie; should redirect to /oauth2/login") + http.Redirect(w, r, "/oauth2/login", http.StatusTemporaryRedirect) + return + } + + _, ok := h.sessions[sessionCookie.Value] + if !ok { + log.Tracef("no token stored for session %s; needs garbage collection client side", sessionCookie.Value) + http.Redirect(w, r, "/oauth2/login", http.StatusTemporaryRedirect) + return + } + + delete(h.sessions, sessionCookie.Value) + + http.SetCookie(w, &http.Cookie{ + Name: SessionCookieName, + Value: "", + Path: "/", + Expires: time.Unix(0,0), + Secure: true, + SameSite: http.SameSiteLaxMode, + }) + + u, err := url.Parse(h.Config.WellKnown.EndSessionEndpoint) + if err != nil { + log.Error(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + v := u.Query() + v.Add("post_logout_redirect_uri", h.Config.PostLogoutRedirectURI) + u.RawQuery = v.Encode() + + http.Redirect(w, r, u.String(), http.StatusTemporaryRedirect) +} + func New(handler *Handler) chi.Router { r := chi.NewRouter() r.With(middleware.DefaultLogger) r.Get("/oauth2/login", handler.Login) r.Get("/oauth2/callback", handler.Callback) + r.Get("/oauth2/logout_self", handler.Logout) r.HandleFunc("/*", handler.Default) return r }