-
-
Notifications
You must be signed in to change notification settings - Fork 358
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
fix: redirct_url with query escape character outside of query is failing #480
Conversation
Thank you for working on this. I have reported this issue in the past in #464. So this is not the only place where this code logic exist, so it would be great if you could also go around the full codebase (just search for |
authorize_helper.go
Outdated
@@ -41,11 +41,17 @@ import ( | |||
func GetRedirectURIFromRequestValues(values url.Values) (string, error) { | |||
// rfc6749 3.1. Authorization Endpoint | |||
// The endpoint URI MAY include an "application/x-www-form-urlencoded" formatted (per Appendix B) query component | |||
redirectURI, err := url.QueryUnescape(values.Get("redirect_uri")) | |||
redirectURI, err := url.Parse(values.Get("redirect_uri")) |
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.
I think this is correct. We just want to validate the redirect_uri
value.
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.
I'm also wondering if values.Get
isn't already unescaped?
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.
Yes. That is the root of the issue.
authorize_helper.go
Outdated
if err != nil { | ||
return "", errors.WithStack(ErrInvalidRequest.WithHint(`The "redirect_uri" parameter is malformed or missing.`).WithCause(err).WithDebug(err.Error())) | ||
} | ||
return redirectURI, nil | ||
rawQuery, err := url.QueryUnescape(redirectURI.RawQuery) |
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.
But I do not think this is necessary. values
should already include correctly parsed parameter from the form payload, so no further unescaping of the redirect_uri
should be necessary. We should just pass it on as-is. We should just validate that the redirect_uri
is valid URL.
Do you have a test case where QueryUnescape
is necessary?
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.
Without escaping the query part, one existing test case fails.
According to this test case, During the client registration, if redirct_uri has an url-encoded query parameter, it is expected to be escaped. I am not sure if it is expected according to the spec.
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.
But that unescaping should be done by accessing the query string using Query()
, no? So form payload unparses it once as a whole redirect_uri
parameter. And then URL
as result of url.Parse
has Query()
method which unescapes when needed. There is no point in doing redirectURI.RawQuery = url.QueryUnescape(redirectURI.RawQuery)
.
I think the confusion here is from this sentence in the spec:
The endpoint URI MAY include an "application/x-www-form-urlencoded" formatted (per Appendix B) query component ([RFC3986] Section 3.4), which MUST be retained when adding additional query parameters.
I think confusion here is that this does not mean that there is extra escaping going on, but that standard query string escaping is what should be done, or is expected that it has been done in the provided redirect URI. That standard escaping is called application/x-www-form-urlencoded
escaping. Also, both urlescape("param1=value1¶m2=value2")
and "param1=" + urlescape(value1) + "¶m2=" + urlescape(value2)
form are both exactly equivalent and should be processed the same by url.Query()
call. See this seciton (referenced from RFC section referenced from the test you linked above) which says:
However, as query components are often used to carry identifying information in the form of "key=value" pairs and one frequently used value is a reference to another URI, it is sometimes better for usability to avoid percent-encoding those characters.
So urlescaping also +
and =
characters in the query string is fine. But it is not necessary for usability. But both of those are demeed to be "application/x-www-form-urlencoded" formatted
. In any case, we do not have to double unescape things. We just have to make sure that we append additional query values to existing. Which we should be doing by calling url.Query()
(which would unescape things), add additional ones, and then encode them back. Which I think we are doing? See here. So there we unescape at that point, add more query values, and escape back.
I think the point the spec is trying to make is that you should expect that proper escaping of the query string has been done and use that knowledge to parse the query string to be able to append new things.
So, no need for double decoding here.
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.
Yes. I completely agree with you. So, we can get rid of GetRedirectURIFromRequestValues
method and the associated test case.
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.
No, we can keep it, just to verify the redirect URI.
You should probably update the test case accordingly.
In other places[1][2][3][4], WDYT? [1] fosite/introspection_request_handler.go Line 140 in b53f8f5
[2] fosite/introspection_request_handler.go Line 145 in b53f8f5
[3] fosite/client_authentication.go Line 277 in b53f8f5
[4] fosite/client_authentication.go Line 279 in b53f8f5
|
You are right. Those are the only ones left. And yes, those should be kept in as per RFC itself. So cool, this is then the only place left to fix this. |
// "application/x-www-form-urlencoded" formatted (per Appendix B) query | ||
// component ([RFC3986] Section 3.4), which MUST be retained when adding | ||
// additional query parameters. | ||
func GetRedirectURIFromRequestValues(values url.Values) (string, error) { |
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.
No, as I mentioned. You should still validate that the url is correct. So just parse the URL, check error return value, and this is it.
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, I realized that this function does not have to validate anything, it is written in its description and redirect URI validation is done later in MatchRedirectURIWithClientRedirectURIs
.
I do agree that it could probably just be removed. But let's wait for @aeneasr to confirm.
72dcfe8
to
94ab1a2
Compare
authorize_helper.go
Outdated
if err != nil { | ||
return "", errors.WithStack(ErrInvalidRequest.WithHint(`The "redirect_uri" parameter is malformed or missing.`).WithCause(err).WithDebug(err.Error())) | ||
} else if rawRedirectURI != "" && (redirectURI.Scheme == "" || redirectURI.Host == "") { |
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.
Any particular reason to add this additional check at this point?
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.
-
According to the test case empty
redirect_uri
is allowed -
Golang url.parse doesn't catch bad URL scheme or host thus the method fails to catch urls like
https//google.com/foo=bar
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.
That's why we have url.ParseRequestURI("https//google.com/foo=bar")
:)
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.
Please keep in mind that this errors if the string is empty, so you need to handle that as a special case!
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.
But this function should not be doing any validation based on its docstring!
So see other comments. Both @ajanthan and me think now that this function should just be removed and replaced with simply calling values.Get("redirect_uri")
. The validation happens anyway in MatchRedirectURIWithClientRedirectURIs
.
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.
Right, overlooked that - makes sense!
@ajanthan are you still up for the changes? :) If you need any help, let us know! |
…edir � Conflicts: � authorize_helper_test.go
…ecial characters again in the query parameters
@aeneasr updated the pr |
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 good to me.
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.
Awesome 🎉
Thank you for your contribution!
Related issue
ory/hydra#2055
Proposed changes
Updated the GetRedirectURIFromRequestValues() method to unescape the query parameters only.
Checklist
vulnerability. If this pull request addresses a security vulnerability, I
confirm that I got green light (please contact
[email protected]) from the maintainers to push
the changes.
Further comments