feat: implement self-initiated logout

Co-authored-by: Kent Daleng <kent.daleng@nav.no>
This commit is contained in:
Trong Huu Nguyen
2021-08-23 10:26:47 +02:00
parent f36848babe
commit 1fcc97819b
2 changed files with 61 additions and 17 deletions

View File

@@ -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{}
}

View File

@@ -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
}