diff --git a/etcdserver/etcdhttp/client_security.go b/etcdserver/etcdhttp/client_security.go index a43a6fbf6..824362701 100644 --- a/etcdserver/etcdhttp/client_security.go +++ b/etcdserver/etcdhttp/client_security.go @@ -24,6 +24,7 @@ import ( "github.com/coreos/etcd/etcdserver" "github.com/coreos/etcd/etcdserver/etcdhttp/httptypes" "github.com/coreos/etcd/etcdserver/security" + "github.com/coreos/etcd/pkg/netutil" ) type securityHandler struct { @@ -46,7 +47,7 @@ func hasRootAccess(sec *security.Store, r *http.Request) bool { if !sec.SecurityEnabled() { return true } - username, password, ok := r.BasicAuth() + username, password, ok := netutil.BasicAuth(r) if !ok { return false } @@ -73,7 +74,7 @@ func hasKeyPrefixAccess(sec *security.Store, r *http.Request, key string) bool { if !sec.SecurityEnabled() { return true } - username, password, ok := r.BasicAuth() + username, password, ok := netutil.BasicAuth(r) if !ok { return false } diff --git a/pkg/netutil/netutil.go b/pkg/netutil/netutil.go index 7de3c4203..cb95ffaeb 100644 --- a/pkg/netutil/netutil.go +++ b/pkg/netutil/netutil.go @@ -15,10 +15,13 @@ package netutil import ( + "encoding/base64" "log" "net" + "net/http" "net/url" "reflect" + "strings" ) var ( @@ -99,3 +102,36 @@ func URLStringsEqual(a []string, b []string) bool { return URLsEqual(urlsA, urlsB) } + +// BasicAuth returns the username and password provided in the request's +// Authorization header, if the request uses HTTP Basic Authentication. +// See RFC 2617, Section 2. +// Based on the BasicAuth method from the Golang standard lib. +// TODO: use the standard lib BasicAuth method when we move to Go 1.4. +func BasicAuth(r *http.Request) (username, password string, ok bool) { + auth := r.Header.Get("Authorization") + if auth == "" { + return + } + return parseBasicAuth(auth) +} + +// parseBasicAuth parses an HTTP Basic Authentication string. +// "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true). +// Taken from the Golang standard lib. +// TODO: use the standard lib BasicAuth method when we move to Go 1.4. +func parseBasicAuth(auth string) (username, password string, ok bool) { + if !strings.HasPrefix(auth, "Basic ") { + return + } + c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic ")) + if err != nil { + return + } + cs := string(c) + s := strings.IndexByte(cs, ':') + if s < 0 { + return + } + return cs[:s], cs[s+1:], true +}