summaryrefslogtreecommitdiffstats
path: root/pkg/v1/remote/transport/transport_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/v1/remote/transport/transport_test.go')
-rw-r--r--pkg/v1/remote/transport/transport_test.go282
1 files changed, 282 insertions, 0 deletions
diff --git a/pkg/v1/remote/transport/transport_test.go b/pkg/v1/remote/transport/transport_test.go
new file mode 100644
index 0000000..10389b7
--- /dev/null
+++ b/pkg/v1/remote/transport/transport_test.go
@@ -0,0 +1,282 @@
+// Copyright 2018 Google LLC All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package transport
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "strings"
+ "testing"
+
+ "github.com/google/go-containerregistry/pkg/authn"
+ "github.com/google/go-containerregistry/pkg/name"
+)
+
+var (
+ testReference, _ = name.NewTag("localhost:8080/user/image:latest", name.StrictValidation)
+)
+
+func TestTransportNoActionIfTransportIsAlreadyWrapper(t *testing.T) {
+ server := httptest.NewServer(
+ http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("WWW-Authenticate", `Bearer realm="http://foo.io"`)
+ http.Error(w, "Should not contact the server", http.StatusBadRequest)
+ }))
+ defer server.Close()
+ tprt := &http.Transport{
+ Proxy: func(req *http.Request) (*url.URL, error) {
+ return url.Parse(server.URL)
+ },
+ }
+
+ wTprt := &Wrapper{inner: tprt}
+
+ if _, err := NewWithContext(context.Background(), testReference.Context().Registry, nil, wTprt, []string{testReference.Scope(PullScope)}); err != nil {
+ t.Errorf("NewWithContext unexpected error %s", err)
+ }
+}
+
+func TestTransportSelectionAnonymous(t *testing.T) {
+ // Record the requests we get in the inner transport.
+ cannedResponse := http.Response{
+ Status: http.StatusText(http.StatusOK),
+ StatusCode: http.StatusOK,
+ Body: io.NopCloser(strings.NewReader("")),
+ }
+ recorder := newRecorder(&cannedResponse, nil)
+
+ basic := &authn.Basic{Username: "foo", Password: "bar"}
+ reg := testReference.Context().Registry
+
+ tp, err := NewWithContext(context.Background(), reg, basic, recorder, []string{testReference.Scope(PullScope)})
+ if err != nil {
+ t.Errorf("NewWithContext() = %v", err)
+ }
+
+ req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/v2/anything", reg), nil)
+ if err != nil {
+ t.Fatalf("Unexpected error during NewRequest: %v", err)
+ }
+ if _, err := tp.RoundTrip(req); err != nil {
+ t.Fatalf("Unexpected error during RoundTrip: %v", err)
+ }
+
+ if got, want := len(recorder.reqs), 2; got != want {
+ t.Fatalf("expected %d requests, got %d", want, got)
+ }
+ recorded := recorder.reqs[1]
+ if got, want := recorded.URL.Scheme, "https"; got != want {
+ t.Errorf("wrong scheme, want %s got %s", want, got)
+ }
+}
+
+func TestTransportSelectionBasic(t *testing.T) {
+ server := httptest.NewServer(
+ http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("WWW-Authenticate", `Basic`)
+ http.Error(w, "Unauthorized", http.StatusUnauthorized)
+ }))
+ defer server.Close()
+ tprt := &http.Transport{
+ Proxy: func(req *http.Request) (*url.URL, error) {
+ return url.Parse(server.URL)
+ },
+ }
+
+ basic := &authn.Basic{Username: "foo", Password: "bar"}
+
+ tp, err := NewWithContext(context.Background(), testReference.Context().Registry, basic, tprt, []string{testReference.Scope(PullScope)})
+ if err != nil {
+ t.Errorf("NewWithContext() = %v", err)
+ }
+ if tpw, ok := tp.(*Wrapper); !ok {
+ t.Errorf("NewWithContext(); got %T, want *Wrapper", tp)
+ } else if _, ok := tpw.inner.(*basicTransport); !ok {
+ t.Errorf("NewWithContext(); got %T, want *basicTransport", tp)
+ }
+}
+
+type badAuth struct{}
+
+func (a *badAuth) Authorization() (*authn.AuthConfig, error) {
+ return nil, errors.New("sorry dave, I'm afraid I can't let you do that")
+}
+
+func TestTransportBadAuth(t *testing.T) {
+ server := httptest.NewServer(
+ http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("WWW-Authenticate", `Bearer realm="http://foo.io"`)
+ http.Error(w, "Unauthorized", http.StatusUnauthorized)
+ }))
+ defer server.Close()
+ tprt := &http.Transport{
+ Proxy: func(req *http.Request) (*url.URL, error) {
+ return url.Parse(server.URL)
+ },
+ }
+
+ if _, err := NewWithContext(context.Background(), testReference.Context().Registry, &badAuth{}, tprt, []string{testReference.Scope(PullScope)}); err == nil {
+ t.Errorf("NewWithContext() expected err, got nil")
+ }
+}
+
+func TestTransportSelectionBearer(t *testing.T) {
+ request := 0
+ server := httptest.NewServer(
+ http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ request++
+ switch request {
+ case 1:
+ // This is an https request that fails, causing us to fall back to http.
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+ case 2:
+ w.Header().Set("WWW-Authenticate", `Bearer realm="http://foo.io"`)
+ http.Error(w, "Unauthorized", http.StatusUnauthorized)
+ case 3:
+ hdr := r.Header.Get("Authorization")
+ if !strings.HasPrefix(hdr, "Basic ") {
+ t.Errorf("Header.Get(Authorization); got %v, want Basic prefix", hdr)
+ }
+ if got, want := r.FormValue("scope"), testReference.Scope(PullScope); got != want {
+ t.Errorf("FormValue(scope); got %v, want %v", got, want)
+ }
+ // Check that the service isn't set (we didn't specify it above)
+ // https://github.com/google/go-containerregistry/issues/1359
+ if got, want := r.FormValue("service"), ""; got != want {
+ t.Errorf("FormValue(service); got %q, want %q", got, want)
+ }
+ w.Write([]byte(`{"token": "dfskdjhfkhsjdhfkjhsdf"}`))
+ }
+ }))
+ defer server.Close()
+ tprt := &http.Transport{
+ Proxy: func(req *http.Request) (*url.URL, error) {
+ return url.Parse(server.URL)
+ },
+ }
+
+ basic := &authn.Basic{Username: "foo", Password: "bar"}
+ tp, err := NewWithContext(context.Background(), testReference.Context().Registry, basic, tprt, []string{testReference.Scope(PullScope)})
+ if err != nil {
+ t.Errorf("NewWithContext() = %v", err)
+ }
+ if tpw, ok := tp.(*Wrapper); !ok {
+ t.Errorf("NewWithContext(); got %T, want *Wrapper", tp)
+ } else if _, ok := tpw.inner.(*bearerTransport); !ok {
+ t.Errorf("NewWithContext(); got %T, want *bearerTransport", tp)
+ }
+}
+
+func TestTransportSelectionBearerMissingRealm(t *testing.T) {
+ server := httptest.NewServer(
+ http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("WWW-Authenticate", `Bearer service="gcr.io"`)
+ http.Error(w, "Unauthorized", http.StatusUnauthorized)
+ }))
+ defer server.Close()
+ tprt := &http.Transport{
+ Proxy: func(req *http.Request) (*url.URL, error) {
+ return url.Parse(server.URL)
+ },
+ }
+
+ basic := &authn.Basic{Username: "foo", Password: "bar"}
+ tp, err := NewWithContext(context.Background(), testReference.Context().Registry, basic, tprt, []string{testReference.Scope(PullScope)})
+ if err == nil || !strings.Contains(err.Error(), "missing realm") {
+ t.Errorf("NewWithContext() = %v, %v", tp, err)
+ }
+}
+
+func TestTransportSelectionBearerAuthError(t *testing.T) {
+ request := 0
+ server := httptest.NewServer(
+ http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ request++
+ switch request {
+ case 1:
+ w.Header().Set("WWW-Authenticate", `Bearer realm="http://foo.io"`)
+ http.Error(w, "Unauthorized", http.StatusUnauthorized)
+ case 2:
+ http.Error(w, "Oops", http.StatusInternalServerError)
+ }
+ }))
+ defer server.Close()
+ tprt := &http.Transport{
+ Proxy: func(req *http.Request) (*url.URL, error) {
+ return url.Parse(server.URL)
+ },
+ }
+
+ basic := &authn.Basic{Username: "foo", Password: "bar"}
+ tp, err := NewWithContext(context.Background(), testReference.Context().Registry, basic, tprt, []string{testReference.Scope(PullScope)})
+ if err == nil {
+ t.Errorf("NewWithContext() = %v", tp)
+ }
+}
+
+func TestTransportSelectionUnrecognizedChallenge(t *testing.T) {
+ server := httptest.NewServer(
+ http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("WWW-Authenticate", `Unrecognized`)
+ http.Error(w, "Unauthorized", http.StatusUnauthorized)
+ }))
+ defer server.Close()
+ tprt := &http.Transport{
+ Proxy: func(req *http.Request) (*url.URL, error) {
+ return url.Parse(server.URL)
+ },
+ }
+
+ basic := &authn.Basic{Username: "foo", Password: "bar"}
+ tp, err := NewWithContext(context.Background(), testReference.Context().Registry, basic, tprt, []string{testReference.Scope(PullScope)})
+ if err == nil || !strings.Contains(err.Error(), "challenge") {
+ t.Errorf("NewWithContext() = %v, %v", tp, err)
+ }
+}
+
+func TestTransportAlwaysTriesHttps(t *testing.T) {
+ // Use a NewTLSServer so that this speaks TLS even though it's localhost.
+ // This ensures that we try https even for local registries.
+ count := 0
+ server := httptest.NewTLSServer(
+ http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ count++
+ w.Write([]byte(`{"token": "dfskdjhfkhsjdhfkjhsdf"}`))
+ }))
+ defer server.Close()
+
+ u, err := url.Parse(server.URL)
+ if err != nil {
+ t.Errorf("Unexpected error during url.Parse: %v", err)
+ }
+ registry, err := name.NewRegistry(u.Host, name.WeakValidation)
+ if err != nil {
+ t.Errorf("Unexpected error during NewRegistry: %v", err)
+ }
+
+ basic := &authn.Basic{Username: "foo", Password: "bar"}
+ tp, err := NewWithContext(context.Background(), registry, basic, server.Client().Transport, []string{testReference.Scope(PullScope)})
+ if err != nil {
+ t.Fatalf("NewWithContext() = %v, %v", tp, err)
+ }
+ if count == 0 {
+ t.Errorf("failed to call TLS localhost server")
+ }
+}