Auth: Add support for OIDC RP-Initiated Logout (#70357)

* Fix signout redirect_uri issue

* Fix signout redirect_uri issue

* Update docs/sources/setup-grafana/configure-grafana/_index.md

Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com>

* Update docs/sources/setup-grafana/configure-grafana/_index.md

Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com>

* Update docs/sources/setup-grafana/configure-grafana/_index.md

Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com>

* remove signout url global

* style alignment

* remove legacy handlers for devenv

* Update pkg/api/login.go

---------

Co-authored-by: Rao B V Chalapathi <b_v_chalapathi.rao@nokia.com>
Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com>
Co-authored-by: jguer <me@jguer.space>
This commit is contained in:
venkatbvc
2023-08-29 15:04:11 +05:30
committed by GitHub
parent e8aa74aba2
commit 7c98678188
7 changed files with 66 additions and 10 deletions
+55 -3
View File
@@ -21,7 +21,6 @@ import (
pref "github.com/grafana/grafana/pkg/services/preference"
"github.com/grafana/grafana/pkg/services/secrets"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/errutil"
)
@@ -29,6 +28,8 @@ import (
const (
viewIndex = "index"
loginErrorCookieName = "login_error"
// #nosec G101 - this is not a hardcoded secret
postLogoutRedirectParam = "post_logout_redirect_uri"
)
var setIndexViewData = (*HTTPServer).setIndexViewData
@@ -250,8 +251,20 @@ func (hs *HTTPServer) Logout(c *contextmodel.ReqContext) {
}
}
idTokenHint := ""
oidcLogout := isPostLogoutRedirectConfigured(hs.Cfg.SignoutRedirectUrl)
// Invalidate the OAuth tokens in case the User logged in with OAuth or the last external AuthEntry is an OAuth one
if entry, exists, _ := hs.oauthTokenService.HasOAuthEntry(c.Req.Context(), c.SignedInUser); exists {
token := hs.oauthTokenService.GetCurrentOAuthToken(c.Req.Context(), c.SignedInUser)
if oidcLogout {
if token.Valid() {
idTokenHint = token.Extra("id_token").(string)
} else {
hs.log.Warn("Token is not valid")
}
}
if err := hs.oauthTokenService.InvalidateOAuthTokens(c.Req.Context(), entry); err != nil {
hs.log.Warn("failed to invalidate oauth tokens for user", "userId", c.UserID, "error", err)
}
@@ -264,8 +277,12 @@ func (hs *HTTPServer) Logout(c *contextmodel.ReqContext) {
authn.DeleteSessionCookie(c.Resp, hs.Cfg)
if setting.SignoutRedirectUrl != "" {
c.Redirect(setting.SignoutRedirectUrl)
rdUrl := hs.Cfg.SignoutRedirectUrl
if rdUrl != "" {
if oidcLogout {
rdUrl = getPostRedirectUrl(hs.Cfg.SignoutRedirectUrl, idTokenHint)
}
c.Redirect(rdUrl)
} else {
hs.log.Info("Successful Logout", "User", c.Email)
c.Redirect(hs.Cfg.AppSubURL + "/login")
@@ -374,3 +391,38 @@ func getFirstPublicErrorMessage(err *errutil.Error) string {
return errPublic.Message
}
func isPostLogoutRedirectConfigured(redirectUrl string) bool {
if redirectUrl == "" {
return false
}
u, err := url.Parse(redirectUrl)
if err != nil {
return false
}
q := u.Query()
_, ok := q[postLogoutRedirectParam]
return ok
}
func getPostRedirectUrl(rdUrl string, tokenHint string) string {
if tokenHint == "" {
return rdUrl
}
if rdUrl == "" {
return rdUrl
}
u, err := url.Parse(rdUrl)
if err != nil {
return rdUrl
}
q := u.Query()
q.Set("id_token_hint", tokenHint)
u.RawQuery = q.Encode()
return u.String()
}