mirror of https://github.com/k3s-io/k3s
Merge pull request #21409 from fabianofranz/fix_spdy_roundtripper_with_proxy_auth
Auto commit by PR queue botpull/6/head
commit
6b676edab8
|
@ -19,6 +19,7 @@ package spdy
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
@ -97,6 +98,11 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
||||||
Host: targetHost,
|
Host: targetHost,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pa := s.proxyAuth(proxyURL); pa != "" {
|
||||||
|
proxyReq.Header = http.Header{}
|
||||||
|
proxyReq.Header.Set("Proxy-Authorization", pa)
|
||||||
|
}
|
||||||
|
|
||||||
proxyDialConn, err := s.dialWithoutProxy(proxyURL)
|
proxyDialConn, err := s.dialWithoutProxy(proxyURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -183,6 +189,16 @@ func (s *SpdyRoundTripper) dialWithoutProxy(url *url.URL) (net.Conn, error) {
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// proxyAuth returns, for a given proxy URL, the value to be used for the Proxy-Authorization header
|
||||||
|
func (s *SpdyRoundTripper) proxyAuth(proxyURL *url.URL) string {
|
||||||
|
if proxyURL == nil || proxyURL.User == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
credentials := proxyURL.User.String()
|
||||||
|
encodedAuth := base64.StdEncoding.EncodeToString([]byte(credentials))
|
||||||
|
return fmt.Sprintf("Basic %s", encodedAuth)
|
||||||
|
}
|
||||||
|
|
||||||
// RoundTrip executes the Request and upgrades it. After a successful upgrade,
|
// RoundTrip executes the Request and upgrades it. After a successful upgrade,
|
||||||
// clients may call SpdyRoundTripper.Connection() to retrieve the upgraded
|
// clients may call SpdyRoundTripper.Connection() to retrieve the upgraded
|
||||||
// connection.
|
// connection.
|
||||||
|
|
|
@ -19,6 +19,7 @@ package spdy
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
@ -64,6 +65,7 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
serverFunc func(http.Handler) *httptest.Server
|
serverFunc func(http.Handler) *httptest.Server
|
||||||
proxyServerFunc func(http.Handler) *httptest.Server
|
proxyServerFunc func(http.Handler) *httptest.Server
|
||||||
|
proxyAuth *url.Userinfo
|
||||||
clientTLS *tls.Config
|
clientTLS *tls.Config
|
||||||
serverConnectionHeader string
|
serverConnectionHeader string
|
||||||
serverUpgradeHeader string
|
serverUpgradeHeader string
|
||||||
|
@ -146,6 +148,16 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
||||||
serverStatusCode: http.StatusSwitchingProtocols,
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
shouldError: false,
|
shouldError: false,
|
||||||
},
|
},
|
||||||
|
"proxied https with auth (invalid hostname + InsecureSkipVerify) -> http": {
|
||||||
|
serverFunc: httptest.NewServer,
|
||||||
|
proxyServerFunc: httpsServerInvalidHostname,
|
||||||
|
proxyAuth: url.UserPassword("proxyuser", "proxypasswd"),
|
||||||
|
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: false,
|
||||||
|
},
|
||||||
"proxied https (invalid hostname + hostname verification) -> http": {
|
"proxied https (invalid hostname + hostname verification) -> http": {
|
||||||
serverFunc: httptest.NewServer,
|
serverFunc: httptest.NewServer,
|
||||||
proxyServerFunc: httpsServerInvalidHostname,
|
proxyServerFunc: httpsServerInvalidHostname,
|
||||||
|
@ -164,6 +176,16 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
||||||
serverStatusCode: http.StatusSwitchingProtocols,
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
shouldError: false,
|
shouldError: false,
|
||||||
},
|
},
|
||||||
|
"proxied https with auth (valid hostname + RootCAs) -> http": {
|
||||||
|
serverFunc: httptest.NewServer,
|
||||||
|
proxyServerFunc: httpsServerValidHostname,
|
||||||
|
proxyAuth: url.UserPassword("proxyuser", "proxypasswd"),
|
||||||
|
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: false,
|
||||||
|
},
|
||||||
"proxied https (invalid hostname + InsecureSkipVerify) -> https (invalid hostname)": {
|
"proxied https (invalid hostname + InsecureSkipVerify) -> https (invalid hostname)": {
|
||||||
serverFunc: httpsServerInvalidHostname,
|
serverFunc: httpsServerInvalidHostname,
|
||||||
proxyServerFunc: httpsServerInvalidHostname,
|
proxyServerFunc: httpsServerInvalidHostname,
|
||||||
|
@ -173,6 +195,16 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
||||||
serverStatusCode: http.StatusSwitchingProtocols,
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
shouldError: false, // works because the test proxy ignores TLS errors
|
shouldError: false, // works because the test proxy ignores TLS errors
|
||||||
},
|
},
|
||||||
|
"proxied https with auth (invalid hostname + InsecureSkipVerify) -> https (invalid hostname)": {
|
||||||
|
serverFunc: httpsServerInvalidHostname,
|
||||||
|
proxyServerFunc: httpsServerInvalidHostname,
|
||||||
|
proxyAuth: url.UserPassword("proxyuser", "proxypasswd"),
|
||||||
|
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: false, // works because the test proxy ignores TLS errors
|
||||||
|
},
|
||||||
"proxied https (invalid hostname + hostname verification) -> https (invalid hostname)": {
|
"proxied https (invalid hostname + hostname verification) -> https (invalid hostname)": {
|
||||||
serverFunc: httpsServerInvalidHostname,
|
serverFunc: httpsServerInvalidHostname,
|
||||||
proxyServerFunc: httpsServerInvalidHostname,
|
proxyServerFunc: httpsServerInvalidHostname,
|
||||||
|
@ -191,6 +223,16 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
||||||
serverStatusCode: http.StatusSwitchingProtocols,
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
shouldError: false,
|
shouldError: false,
|
||||||
},
|
},
|
||||||
|
"proxied https with auth (valid hostname + RootCAs) -> https (valid hostname + RootCAs)": {
|
||||||
|
serverFunc: httpsServerValidHostname,
|
||||||
|
proxyServerFunc: httpsServerValidHostname,
|
||||||
|
proxyAuth: url.UserPassword("proxyuser", "proxypasswd"),
|
||||||
|
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, testCase := range testCases {
|
for k, testCase := range testCases {
|
||||||
|
@ -238,20 +280,29 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
||||||
|
|
||||||
var proxierCalled bool
|
var proxierCalled bool
|
||||||
var proxyCalledWithHost string
|
var proxyCalledWithHost string
|
||||||
|
var proxyCalledWithAuth bool
|
||||||
|
var proxyCalledWithAuthHeader string
|
||||||
if testCase.proxyServerFunc != nil {
|
if testCase.proxyServerFunc != nil {
|
||||||
proxyHandler := goproxy.NewProxyHttpServer()
|
proxyHandler := goproxy.NewProxyHttpServer()
|
||||||
|
|
||||||
proxyHandler.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
|
proxyHandler.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
|
||||||
proxyCalledWithHost = host
|
proxyCalledWithHost = host
|
||||||
|
|
||||||
|
proxyAuthHeaderName := "Proxy-Authorization"
|
||||||
|
_, proxyCalledWithAuth = ctx.Req.Header[proxyAuthHeaderName]
|
||||||
|
proxyCalledWithAuthHeader = ctx.Req.Header.Get(proxyAuthHeaderName)
|
||||||
return goproxy.OkConnect, host
|
return goproxy.OkConnect, host
|
||||||
})
|
})
|
||||||
|
|
||||||
proxy := testCase.proxyServerFunc(proxyHandler)
|
proxy := testCase.proxyServerFunc(proxyHandler)
|
||||||
|
|
||||||
spdyTransport.proxier = func(proxierReq *http.Request) (*url.URL, error) {
|
spdyTransport.proxier = func(proxierReq *http.Request) (*url.URL, error) {
|
||||||
|
proxierCalled = true
|
||||||
proxyURL, err := url.Parse(proxy.URL)
|
proxyURL, err := url.Parse(proxy.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
proxierCalled = true
|
proxyURL.User = testCase.proxyAuth
|
||||||
return proxyURL, nil
|
return proxyURL, nil
|
||||||
}
|
}
|
||||||
// TODO: Uncomment when fix #19254
|
// TODO: Uncomment when fix #19254
|
||||||
|
@ -311,6 +362,18 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
||||||
t.Fatalf("%s: Expected to see a call to the proxy for backend %q, got %q", k, serverURL.Host, proxyCalledWithHost)
|
t.Fatalf("%s: Expected to see a call to the proxy for backend %q, got %q", k, serverURL.Host, proxyCalledWithHost)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var expectedProxyAuth string
|
||||||
|
if testCase.proxyAuth != nil {
|
||||||
|
encodedCredentials := base64.StdEncoding.EncodeToString([]byte(testCase.proxyAuth.String()))
|
||||||
|
expectedProxyAuth = "Basic " + encodedCredentials
|
||||||
|
}
|
||||||
|
if len(expectedProxyAuth) == 0 && proxyCalledWithAuth {
|
||||||
|
t.Fatalf("%s: Proxy authorization unexpected, got %q", k, proxyCalledWithAuthHeader)
|
||||||
|
}
|
||||||
|
if proxyCalledWithAuthHeader != expectedProxyAuth {
|
||||||
|
t.Fatalf("%s: Expected to see a call to the proxy with credentials %q, got %q", k, testCase.proxyAuth, proxyCalledWithAuthHeader)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue