mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
API: Fix redirect issue when configured to use a subpath (#21652)
* request uri will contain the subpath
This commit is contained in:
parent
0cde7decd7
commit
0e2d874ecf
@ -35,7 +35,9 @@ func (hs *HTTPServer) validateRedirectTo(redirectTo string) error {
|
|||||||
if to.IsAbs() {
|
if to.IsAbs() {
|
||||||
return login.ErrAbsoluteRedirectTo
|
return login.ErrAbsoluteRedirectTo
|
||||||
}
|
}
|
||||||
if hs.Cfg.AppSubUrl != "" && !strings.HasPrefix(to.Path, "/"+hs.Cfg.AppSubUrl) {
|
// when using a subUrl, the redirect_to should have a relative or absolute path that includes the subUrl, otherwise the redirect
|
||||||
|
// will send the user to the wrong location
|
||||||
|
if hs.Cfg.AppSubUrl != "" && !strings.HasPrefix(to.Path, hs.Cfg.AppSubUrl) && !strings.HasPrefix(to.Path, "/"+hs.Cfg.AppSubUrl) {
|
||||||
return login.ErrInvalidRedirectTo
|
return login.ErrInvalidRedirectTo
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -177,6 +179,11 @@ func (hs *HTTPServer) LoginPost(c *models.ReqContext, cmd dtos.LoginCommand) Res
|
|||||||
|
|
||||||
if redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")); len(redirectTo) > 0 {
|
if redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")); len(redirectTo) > 0 {
|
||||||
if err := hs.validateRedirectTo(redirectTo); err == nil {
|
if err := hs.validateRedirectTo(redirectTo); err == nil {
|
||||||
|
// remove subpath if it exists at the beginning of the redirect_to
|
||||||
|
// LoginCtrl.tsx is already prepending the redirectUrl with the subpath
|
||||||
|
if setting.AppSubUrl != "" && strings.Index(redirectTo, setting.AppSubUrl) == 0 {
|
||||||
|
redirectTo = strings.Replace(redirectTo, setting.AppSubUrl, "", 1)
|
||||||
|
}
|
||||||
result["redirectUrl"] = redirectTo
|
result["redirectUrl"] = redirectTo
|
||||||
} else {
|
} else {
|
||||||
log.Info("Ignored invalid redirect_to cookie value: %v", redirectTo)
|
log.Info("Ignored invalid redirect_to cookie value: %v", redirectTo)
|
||||||
|
@ -72,6 +72,7 @@ type redirectCase struct {
|
|||||||
err error
|
err error
|
||||||
appURL string
|
appURL string
|
||||||
appSubURL string
|
appSubURL string
|
||||||
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoginErrorCookieApiEndpoint(t *testing.T) {
|
func TestLoginErrorCookieApiEndpoint(t *testing.T) {
|
||||||
@ -154,6 +155,7 @@ func TestLoginViewRedirect(t *testing.T) {
|
|||||||
desc: "grafana relative url without subpath",
|
desc: "grafana relative url without subpath",
|
||||||
url: "/profile",
|
url: "/profile",
|
||||||
appURL: "http://localhost:3000",
|
appURL: "http://localhost:3000",
|
||||||
|
path: "/",
|
||||||
status: 302,
|
status: 302,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -161,6 +163,15 @@ func TestLoginViewRedirect(t *testing.T) {
|
|||||||
url: "/grafana/profile",
|
url: "/grafana/profile",
|
||||||
appURL: "http://localhost:3000",
|
appURL: "http://localhost:3000",
|
||||||
appSubURL: "grafana",
|
appSubURL: "grafana",
|
||||||
|
path: "grafana/",
|
||||||
|
status: 302,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "grafana slashed relative url with subpath",
|
||||||
|
url: "/grafana/profile",
|
||||||
|
appURL: "http://localhost:3000",
|
||||||
|
appSubURL: "grafana",
|
||||||
|
path: "/grafana/",
|
||||||
status: 302,
|
status: 302,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -168,13 +179,23 @@ func TestLoginViewRedirect(t *testing.T) {
|
|||||||
url: "/profile",
|
url: "/profile",
|
||||||
appURL: "http://localhost:3000",
|
appURL: "http://localhost:3000",
|
||||||
appSubURL: "grafana",
|
appSubURL: "grafana",
|
||||||
|
path: "grafana/",
|
||||||
status: 200,
|
status: 200,
|
||||||
err: login.ErrInvalidRedirectTo,
|
err: login.ErrInvalidRedirectTo,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "grafana subpath absolute url",
|
||||||
|
url: "http://localhost:3000/grafana/profile",
|
||||||
|
appURL: "http://localhost:3000",
|
||||||
|
appSubURL: "grafana",
|
||||||
|
path: "/grafana/profile",
|
||||||
|
status: 200,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "grafana absolute url",
|
desc: "grafana absolute url",
|
||||||
url: "http://localhost:3000/profile",
|
url: "http://localhost:3000/profile",
|
||||||
appURL: "http://localhost:3000",
|
appURL: "http://localhost:3000",
|
||||||
|
path: "/",
|
||||||
status: 200,
|
status: 200,
|
||||||
err: login.ErrAbsoluteRedirectTo,
|
err: login.ErrAbsoluteRedirectTo,
|
||||||
},
|
},
|
||||||
@ -182,6 +203,7 @@ func TestLoginViewRedirect(t *testing.T) {
|
|||||||
desc: "non grafana absolute url",
|
desc: "non grafana absolute url",
|
||||||
url: "http://example.com",
|
url: "http://example.com",
|
||||||
appURL: "http://localhost:3000",
|
appURL: "http://localhost:3000",
|
||||||
|
path: "/",
|
||||||
status: 200,
|
status: 200,
|
||||||
err: login.ErrAbsoluteRedirectTo,
|
err: login.ErrAbsoluteRedirectTo,
|
||||||
},
|
},
|
||||||
@ -189,6 +211,7 @@ func TestLoginViewRedirect(t *testing.T) {
|
|||||||
desc: "invalid url",
|
desc: "invalid url",
|
||||||
url: ":foo",
|
url: ":foo",
|
||||||
appURL: "http://localhost:3000",
|
appURL: "http://localhost:3000",
|
||||||
|
path: "/",
|
||||||
status: 200,
|
status: 200,
|
||||||
err: login.ErrInvalidRedirectTo,
|
err: login.ErrInvalidRedirectTo,
|
||||||
},
|
},
|
||||||
@ -203,7 +226,7 @@ func TestLoginViewRedirect(t *testing.T) {
|
|||||||
MaxAge: 60,
|
MaxAge: 60,
|
||||||
Value: c.url,
|
Value: c.url,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Path: hs.Cfg.AppSubUrl + "/",
|
Path: c.path,
|
||||||
Secure: hs.Cfg.CookieSecure,
|
Secure: hs.Cfg.CookieSecure,
|
||||||
SameSite: hs.Cfg.CookieSameSiteMode,
|
SameSite: hs.Cfg.CookieSameSiteMode,
|
||||||
}
|
}
|
||||||
@ -219,7 +242,7 @@ func TestLoginViewRedirect(t *testing.T) {
|
|||||||
assert.True(t, ok, "Set-Cookie exists")
|
assert.True(t, ok, "Set-Cookie exists")
|
||||||
assert.Greater(t, len(setCookie), 0)
|
assert.Greater(t, len(setCookie), 0)
|
||||||
var redirectToCookieFound bool
|
var redirectToCookieFound bool
|
||||||
expCookieValue := fmt.Sprintf("redirect_to=%v; Path=%v; Max-Age=60; HttpOnly; Secure", c.url, hs.Cfg.AppSubUrl+"/")
|
expCookieValue := fmt.Sprintf("redirect_to=%v; Path=%v; Max-Age=60; HttpOnly; Secure", c.url, c.path)
|
||||||
for _, cookieValue := range setCookie {
|
for _, cookieValue := range setCookie {
|
||||||
if cookieValue == expCookieValue {
|
if cookieValue == expCookieValue {
|
||||||
redirectToCookieFound = true
|
redirectToCookieFound = true
|
||||||
@ -281,6 +304,12 @@ func TestLoginPostRedirect(t *testing.T) {
|
|||||||
appURL: "https://localhost:3000",
|
appURL: "https://localhost:3000",
|
||||||
appSubURL: "grafana",
|
appSubURL: "grafana",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "grafana no slash relative url with subpath",
|
||||||
|
url: "grafana/profile",
|
||||||
|
appURL: "https://localhost:3000",
|
||||||
|
appSubURL: "grafana",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "relative url with missing subpath",
|
desc: "relative url with missing subpath",
|
||||||
url: "/profile",
|
url: "/profile",
|
||||||
|
@ -47,7 +47,7 @@ func notAuthorized(c *m.ReqContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteCookie(c.Resp, "redirect_to", url.QueryEscape(setting.AppSubUrl+c.Req.RequestURI), 0, newCookieOptions)
|
WriteCookie(c.Resp, "redirect_to", url.QueryEscape(c.Req.RequestURI), 0, newCookieOptions)
|
||||||
|
|
||||||
c.Redirect(setting.AppSubUrl + "/login")
|
c.Redirect(setting.AppSubUrl + "/login")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user