From 2132d15266bcf47ecd5b602767e166583d2382a6 Mon Sep 17 00:00:00 2001 From: Luiz Henrique Gomes Palacio Date: Wed, 28 Aug 2024 17:42:18 -0300 Subject: [PATCH] Fix HTTP proxy authentication to support both preemptive and challenge-response auth --- http.go | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/http.go b/http.go index 9fa7932..ebaa822 100644 --- a/http.go +++ b/http.go @@ -31,23 +31,23 @@ func (s *HTTPServer) authenticate(req *http.Request) (int, error) { } auth := req.Header.Get(proxyAuthHeaderKey) - if auth != "" { - enc := strings.TrimPrefix(auth, "Basic ") - str, err := base64.StdEncoding.DecodeString(enc) - if err != nil { - return http.StatusNotAcceptable, fmt.Errorf("decode username and password failed: %w", err) - } - pairs := bytes.SplitN(str, []byte(":"), 2) - if len(pairs) != 2 { - return http.StatusLengthRequired, fmt.Errorf("username and password format invalid") - } - if s.auth.Valid(string(pairs[0]), string(pairs[1])) { - return 0, nil - } - return http.StatusUnauthorized, fmt.Errorf("username and password not matching") + if auth == "" { + return http.StatusProxyAuthRequired, fmt.Errorf(http.StatusText(http.StatusProxyAuthRequired)) } - return http.StatusProxyAuthRequired, fmt.Errorf(http.StatusText(http.StatusProxyAuthRequired)) + enc := strings.TrimPrefix(auth, "Basic ") + str, err := base64.StdEncoding.DecodeString(enc) + if err != nil { + return http.StatusNotAcceptable, fmt.Errorf("decode username and password failed: %w", err) + } + pairs := bytes.SplitN(str, []byte(":"), 2) + if len(pairs) != 2 { + return http.StatusLengthRequired, fmt.Errorf("username and password format invalid") + } + if s.auth.Valid(string(pairs[0]), string(pairs[1])) { + return 0, nil + } + return http.StatusUnauthorized, fmt.Errorf("username and password not matching") } func (s *HTTPServer) handleConn(req *http.Request, conn net.Conn) (peer net.Conn, err error) { @@ -103,7 +103,11 @@ func (s *HTTPServer) serve(conn net.Conn) { code, err := s.authenticate(req) if err != nil { - _ = responseWith(req, code).Write(conn) + resp := responseWith(req, code) + if code == http.StatusProxyAuthRequired { + resp.Header.Set("Proxy-Authenticate", "Basic realm=\"Proxy\"") + } + _ = resp.Write(conn) log.Println(err) return }