Skip to content
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

net/url: do not URL-escape auth info before base64 encoding #5970

Closed
dustin opened this issue Jul 27, 2013 · 6 comments
Closed

net/url: do not URL-escape auth info before base64 encoding #5970

dustin opened this issue Jul 27, 2013 · 6 comments
Labels
FrozenDueToAge Suggested Issues that may be good for new contributors looking for work to do.
Milestone

Comments

@dustin
Copy link

dustin commented Jul 27, 2013

What steps will reproduce the problem?
If possible, include a link to a program on play.golang.org.

A good example is this:  http://play.golang.org/p/3bwbg8LLGE

What is the expected output?

The encoding according to the RFC is as follows:

      basic-credentials = base64-user-pass
      base64-user-pass  = <base64 [4] encoding of user-pass,
                       except not limited to 76 char/line>
      user-pass   = userid ":" password
      userid      = *<TEXT excluding ":">
      password    = *TEXT

In particular, you do not encode the username and password, just split on ':' -- the
only special bit is that the username isn't allowed to have a : itself.

Then the entire thing is base64 encoded.

What do you see instead?

URL escaped stuff.

Which compiler are you using (5g, 6g, 8g, gccgo)?

8g

Which operating system are you using?

OSX/Linux

Which version are you using?  (run 'go version')

1.1.1
@rsc
Copy link
Contributor

rsc commented Jul 30, 2013

Comment 1:

Labels changed: added priority-later, go1.2, suggested, removed priority-triage.

Status changed to Accepted.

@PieterD
Copy link
Contributor

PieterD commented Aug 3, 2013

Comment 2:

Userinfo.String() urlencodes because that's how it's presented in the URL. It would be
unwise to change this.
The problem is that net/http/client.go directly uses String(), and Base64encodes it.
This is a bug.
CL: https://golang.org/cl/12397043/

@rsc
Copy link
Contributor

rsc commented Aug 7, 2013

Comment 3:

Issue #6066 has been merged into this issue.

@rsc
Copy link
Contributor

rsc commented Aug 7, 2013

Comment 4:

This seems to work but it needs tests, both in net/url and net/http.
diff -r 045269edbbee src/pkg/net/http/client.go
--- a/src/pkg/net/http/client.go    Tue Aug 06 14:49:55 2013 -0400
+++ b/src/pkg/net/http/client.go    Wed Aug 07 02:30:08 2013 -0400
@@ -10,7 +10,6 @@
 package http
 
 import (
-   "encoding/base64"
    "errors"
    "fmt"
    "io"
@@ -161,18 +160,11 @@
    }
 
    if u := req.URL.User; u != nil {
-       auth := u.String()
-       // UserInfo.String() only returns the colon when the
-       // password is set, so we must add it here.
-       //
-       // See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt
-       // "To receive authorization, the client sends the userid and password,
-       // separated by a single colon (":") character, within a base64
-       // encoded string in the credentials."
-       if _, hasPassword := u.Password(); !hasPassword {
-           auth += ":"
+       auth, err := u.BasicAuth()
+       if err != nil {
+           return nil, err
        }
-       req.Header.Set("Authorization", "Basic
"+base64.URLEncoding.EncodeToString([]byte(auth)))
+       req.Header.Set("Authorization", "Basic "+auth)
    }
    resp, err = t.RoundTrip(req)
    if err != nil {
diff -r 045269edbbee src/pkg/net/url/url.go
--- a/src/pkg/net/url/url.go    Tue Aug 06 14:49:55 2013 -0400
+++ b/src/pkg/net/url/url.go    Wed Aug 07 02:30:08 2013 -0400
@@ -8,6 +8,7 @@
 
 import (
    "bytes"
+   "encoding/base64"
    "errors"
    "sort"
    "strconv"
@@ -277,8 +278,8 @@
    return "", false
 }
 
-// String returns the encoded userinfo information in the standard form
-// of "username[:password]".
+// String returns the user information in the standard form
+// of "username[:password]", with special characters URL-encoded.
 func (u *Userinfo) String() string {
    s := escape(u.username, encodeUserPassword)
    if u.passwordSet {
@@ -287,6 +288,17 @@
    return s
 }
 
+var errUsername = errors.New("url: invalid user name")
+
+// BasicAuth returns the user information in the base64-encoded
+// form used by the ``Basic'' authorization header.
+func (u *Userinfo) BasicAuth() (string, error) {
+   if strings.Contains(u.username, ":") {
+       return "", errUsername
+   }
+   return base64.URLEncoding.EncodeToString([]byte(u.username + ":" + u.password)), nil
+}
+
 // Maybe rawurl is of the form scheme:path.
 // (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
 // If so, return scheme, path; else return "", rawurl.

@PieterD
Copy link
Contributor

PieterD commented Aug 7, 2013

Comment 5:

There are more problems. Sometimes StdEncoding/Decoding is used, sometimes
URLEncoding/Decoding. It should be StdEncoding, according to rfc 2045 (from 2617 [4]).
Please comment on my CL, https://golang.org/cl/12397043/

@bradfitz
Copy link
Contributor

bradfitz commented Aug 7, 2013

Comment 6:

This issue was closed by revision a08b1d1.

Status changed to Fixed.

@dustin dustin added fixed Suggested Issues that may be good for new contributors looking for work to do. labels Aug 7, 2013
@rsc rsc added this to the Go1.2 milestone Apr 14, 2015
@rsc rsc removed the go1.2 label Apr 14, 2015
@golang golang locked and limited conversation to collaborators Jun 24, 2016
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge Suggested Issues that may be good for new contributors looking for work to do.
Projects
None yet
Development

No branches or pull requests

5 participants