From d535bc7af3290c6f09eeb391e0ef00f374f9b743 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Alberto=20Garc=C3=ADa=20Hierro?= Date: Tue, 14 May 2013 15:33:46 -0700 Subject: [PATCH] net/http: Fix basic authentication with empty password The encoded string must include the : separating the username and the password, even when the latter is empty. See http://www.ietf.org/rfc/rfc2617.txt for more information. R=golang-dev, bradfitz, adg CC=golang-dev https://golang.org/cl/8475043 --- src/pkg/net/http/client.go | 13 +++++++++++- src/pkg/net/http/client_test.go | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/pkg/net/http/client.go b/src/pkg/net/http/client.go index a34d47be1f..828422f84c 100644 --- a/src/pkg/net/http/client.go +++ b/src/pkg/net/http/client.go @@ -161,7 +161,18 @@ func send(req *Request, t RoundTripper) (resp *Response, err error) { } if u := req.URL.User; u != nil { - req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(u.String()))) + 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 += ":" + } + req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(auth))) } resp, err = t.RoundTrip(req) if err != nil { diff --git a/src/pkg/net/http/client_test.go b/src/pkg/net/http/client_test.go index 73f1fe3c10..e82fafd57f 100644 --- a/src/pkg/net/http/client_test.go +++ b/src/pkg/net/http/client_test.go @@ -10,6 +10,7 @@ import ( "bytes" "crypto/tls" "crypto/x509" + "encoding/base64" "errors" "fmt" "io" @@ -700,3 +701,37 @@ func TestClientHeadContentLength(t *testing.T) { } } } + +func TestEmptyPasswordAuth(t *testing.T) { + defer afterTest(t) + gopher := "gopher" + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + auth := r.Header.Get("Authorization") + if strings.HasPrefix(auth, "Basic ") { + encoded := auth[6:] + decoded, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + t.Fatal(err) + } + expected := gopher + ":" + s := string(decoded) + if expected != s { + t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected) + } + } else { + t.Errorf("Invalid auth %q", auth) + } + })) + defer ts.Close() + c := &Client{} + req, err := NewRequest("GET", ts.URL, nil) + if err != nil { + t.Fatal(err) + } + req.URL.User = url.User(gopher) + resp, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() +} -- 2.48.1