-
Notifications
You must be signed in to change notification settings - Fork 12k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API: Fix redirect issues #22285
API: Fix redirect issues #22285
Conversation
ctx.Redirect(redirectTo) | ||
return | ||
if err := hs.validateRedirectTo(redirectTo); err == nil { | ||
middleware.DeleteCookie(ctx.Resp, "redirect_to", hs.cookieOptionsFromCfg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
happen to understand this enough to add a comment explaining why the cookie is deleted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the cookie is no longer needed since it held the redirect_to location. this code path is going to send the browser to the new location, and should not retain the redirect_to cookie (could end up in a redirect loop, but mainly it is no longer needed).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exactly; the cookie is deleted because it's has fulfilled its purpose.
Don't understand this enough to approve it, but an exemplar pull request message :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks great!
ctx.Redirect(redirectTo) | ||
return | ||
if err := hs.validateRedirectTo(redirectTo); err == nil { | ||
middleware.DeleteCookie(ctx.Resp, "redirect_to", hs.cookieOptionsFromCfg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the cookie is no longer needed since it held the redirect_to location. this code path is going to send the browser to the new location, and should not retain the redirect_to cookie (could end up in a redirect loop, but mainly it is no longer needed).
I have not fully understood the details here, but I think it makes sense to use the logic from #22265 alongside this PR that allows cookies to be passed along to
Thanks for working on this! |
In that case, this validation returns error and the redirect_to cookie is ignored and delete it and the logged in user is navigated to the home page.
This is true.
@consideRatio It's also a bit concerning that two different people have difficulty understanding the modifications in this PR therefore I would love some feedback from anybody with better insight than me. |
I have pushed a modification for fixing this. |
The fix will still make It makes a visit to
This is the key discussion in my mind. Cookie handling is indeed a delicate and complicated matter. I have never really felt confident about them, but after the references you found I've started to feel that I understand them somewhat. That makes me want to tackle the question if the change suggested in #22265 actually would cause issues head on. If #22265 isn't going to cause issues, it would actually solve the issue I described above with the workaround in 4e52076 and remove the need to bounce the user to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry being late to the party. I probably lack a lot of context, but added some comments/questions.
@@ -47,7 +47,11 @@ func notAuthorized(c *m.ReqContext) { | |||
return | |||
} | |||
|
|||
WriteCookie(c.Resp, "redirect_to", url.QueryEscape(c.Req.RequestURI), 0, newCookieOptions) | |||
redirectTo := c.Req.RequestURI | |||
if setting.AppSubUrl != "" && !strings.HasPrefix(redirectTo, setting.AppSubUrl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why doesn't c.Req.RequestURI
include AppSubUrl
? Would it help to use c.Req.URL
instead to skip writing the appSubUrl in cookie?
c.Req.Request.URI
: /grafana/d/5SdHCadmz/panel-tests-graph?orgId=1
c.Req.Request.URL.String()
: /d/5SdHCadmz/panel-tests-graph?orgId=1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why doesn't c.Req.RequestURI include AppSubUrl?
As far as I understand, the user can request whatever URL.
For instance, the user can request http://localhost:3000
even though the subpath is /grafana
.
In addition to this, we always prepended the subpath before this change which was introduced for fixing this problematic situation.
Probably now that we have validation for the redirects (and if it's working correctly) we no more need to prepend it
because invalid redirect paths are ignored.
But I think it's safer to keep it here, since it appends it only if it's missing.
@@ -104,9 +104,17 @@ export class LoginCtrl extends PureComponent<Props, State> { | |||
const params = this.props.routeParams; | |||
// Use window.location.href to force page reload | |||
if (params.redirect && params.redirect[0] === '/') { | |||
window.location.href = config.appSubUrl + params.redirect; | |||
if (config.appSubUrl !== '' && !params.redirect.startsWith(config.appSubUrl)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need frontend logic at all for redirect, couldn't the backend make sure to always return the correct url? Wait why are we using redirect query param here - thought we always had redirect in cookie?
* Fix redirect validation * Fix tests * Add removed redirect validation comment * Chore: Add test for parse of app url and app sub url Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
* Prepand subpath in redirect URL only if it's missing * Change frontend to prepend the subpath only if needed
* Fix login view in case of invalid redirect If the user is authenticated and redirect_to cookie points to an invalid path, the user should be navigated to the home page instead of rendering the login page with error. * Fix TestLoginViewRedirect
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A: Logout scenario with anonymous auth disabled:
- Login
- Browse dashboard X
- Clear cookies
- Refresh browser. Should be redirected to login page
- Login
- Should be redirected to dashboard X
B: Anonymous scenario:
- Browse dashboard X
- Click on login in sidemenu and redirect to login page
- Login
- Should be redirected to dashboard X
Root url default without sub path using Grafana auth:
A: Works as expected
B: Works as expected
Root url default without sub path using OAuth:
A: Works as expected
B: No, redirected to home page
Root url http://localhost:3000/grafana with serve_from_sub_path using Grafana auth:
A: Works as expected
B: Works as expected
Root url http://localhost:3000/grafana with serve_from_sub_path using OAuth:
A: Works as expected
B: No, redirected to home page
Root url http://grafana.myproxy.com:10080/grafana without serve_from_sub_path using nginx and Grafana auth:
A: Works as expected
B: Works as expected
Root url http://grafana.myproxy.com:10080/grafana without serve_from_sub_path using nginx and OAuth:
A: Works as expected
B: No, redirected to home page
Also confirmed this resolves #22227
@papagian Not sure if B scenario using OAuth is a new or existing regression? We could create a new issue if there's no existing one and fix that for 6.7 stable maybe?
What this PR does / why we need it:
The 6.6.1 has the following issues:
/<appSubUrl>blahblah
./grafana
ends up to/grafana/grafana
)This fix addresses the above issues by removing the subpath from redirects in the backend.
However it does not work optimally when redirects occur in the backend before reaching the frontend (like in the OAuth flow) because the session cookie path is set to
appSubUrl/
and requests without the appSubUrl can not read it.This fixes the above issue by removing the trailing slash from the cookie path.
The reason for this is that addresses the causes of the problem instead of the symptoms.
This PR:
redirect_to
value is invalid but the user is authenticated so as the user is navigated to the home page instead of rendering login page with error. (Fix invalid redirect for authenticated user #22678)Which issue(s) this PR fixes:
Fixes #22227
Fixes #22461
Special notes for your reviewer:
I have tested it with the following scenarios:
with subpath
/grafana
:without subpath: