diff --git a/staging/src/k8s.io/client-go/transport/round_trippers.go b/staging/src/k8s.io/client-go/transport/round_trippers.go index 117a9c8c4de..844ee9a21b7 100644 --- a/staging/src/k8s.io/client-go/transport/round_trippers.go +++ b/staging/src/k8s.io/client-go/transport/round_trippers.go @@ -409,6 +409,38 @@ func (rt *debuggingRoundTripper) CancelRequest(req *http.Request) { } } +var knownAuthTypes = map[string]bool{ + "bearer": true, + "basic": true, + "negotiate": true, +} + +// maskValue masks credential content from authorization headers +// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization +func maskValue(key string, value string) string { + if !strings.EqualFold(key, "Authorization") { + return value + } + if len(value) == 0 { + return "" + } + var authType string + if i := strings.Index(value, " "); i > 0 { + authType = value[0:i] + } else { + authType = value + } + if !knownAuthTypes[strings.ToLower(authType)] { + return "" + } + if len(value) > len(authType)+1 { + value = authType + " " + } else { + value = authType + } + return value +} + func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { reqInfo := newRequestInfo(req) @@ -423,6 +455,7 @@ func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, e klog.Infof("Request Headers:") for key, values := range reqInfo.RequestHeaders { for _, value := range values { + value = maskValue(key, value) klog.Infof(" %s: %s", key, value) } } diff --git a/staging/src/k8s.io/client-go/transport/round_trippers_test.go b/staging/src/k8s.io/client-go/transport/round_trippers_test.go index abe5ab53d97..ac8de24084d 100644 --- a/staging/src/k8s.io/client-go/transport/round_trippers_test.go +++ b/staging/src/k8s.io/client-go/transport/round_trippers_test.go @@ -35,6 +35,91 @@ func (rt *testRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) return rt.Response, rt.Err } +func TestMaskValue(t *testing.T) { + tcs := []struct { + key string + value string + expected string + }{ + { + key: "Authorization", + value: "Basic YWxhZGRpbjpvcGVuc2VzYW1l", + expected: "Basic ", + }, + { + key: "Authorization", + value: "basic", + expected: "basic", + }, + { + key: "Authorization", + value: "Basic", + expected: "Basic", + }, + { + key: "Authorization", + value: "Bearer cn389ncoiwuencr", + expected: "Bearer ", + }, + { + key: "Authorization", + value: "Bearer", + expected: "Bearer", + }, + { + key: "Authorization", + value: "bearer", + expected: "bearer", + }, + { + key: "Authorization", + value: "bearer ", + expected: "bearer", + }, + { + key: "Authorization", + value: "Negotiate cn389ncoiwuencr", + expected: "Negotiate ", + }, + { + key: "ABC", + value: "Negotiate cn389ncoiwuencr", + expected: "Negotiate cn389ncoiwuencr", + }, + { + key: "Authorization", + value: "Negotiate", + expected: "Negotiate", + }, + { + key: "Authorization", + value: "Negotiate ", + expected: "Negotiate", + }, + { + key: "Authorization", + value: "negotiate", + expected: "negotiate", + }, + { + key: "Authorization", + value: "abc cn389ncoiwuencr", + expected: "", + }, + { + key: "Authorization", + value: "", + expected: "", + }, + } + for _, tc := range tcs { + maskedValue := maskValue(tc.key, tc.value) + if tc.expected != maskedValue { + t.Errorf("unexpected value %s, given %s.", maskedValue, tc.value) + } + } +} + func TestBearerAuthRoundTripper(t *testing.T) { rt := &testRoundTripper{} req := &http.Request{} diff --git a/test/e2e/kubectl/kubectl.go b/test/e2e/kubectl/kubectl.go index 11c085ae7bf..dd2a0030bee 100644 --- a/test/e2e/kubectl/kubectl.go +++ b/test/e2e/kubectl/kubectl.go @@ -722,7 +722,6 @@ metadata: framework.ExpectError(err) gomega.Expect(err).To(gomega.ContainSubstring("Using in-cluster namespace")) gomega.Expect(err).To(gomega.ContainSubstring("Using in-cluster configuration")) - gomega.Expect(err).To(gomega.ContainSubstring("Authorization: Bearer invalid")) gomega.Expect(err).To(gomega.ContainSubstring("Response Status: 401 Unauthorized")) ginkgo.By("trying to use kubectl with invalid server")