...

Source file src/github.com/google/go-containerregistry/pkg/v1/remote/transport/transport_test.go

Documentation: github.com/google/go-containerregistry/pkg/v1/remote/transport

     1  // Copyright 2018 Google LLC All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package transport
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"fmt"
    21  	"io"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"net/url"
    25  	"strings"
    26  	"testing"
    27  
    28  	"github.com/google/go-containerregistry/pkg/authn"
    29  	"github.com/google/go-containerregistry/pkg/name"
    30  )
    31  
    32  var (
    33  	testReference, _ = name.NewTag("localhost:8080/user/image:latest", name.StrictValidation)
    34  )
    35  
    36  func TestTransportNoActionIfTransportIsAlreadyWrapper(t *testing.T) {
    37  	server := httptest.NewServer(
    38  		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    39  			w.Header().Set("WWW-Authenticate", `Bearer realm="http://foo.io"`)
    40  			http.Error(w, "Should not contact the server", http.StatusBadRequest)
    41  		}))
    42  	defer server.Close()
    43  	tprt := &http.Transport{
    44  		Proxy: func(req *http.Request) (*url.URL, error) {
    45  			return url.Parse(server.URL)
    46  		},
    47  	}
    48  
    49  	wTprt := &Wrapper{inner: tprt}
    50  
    51  	if _, err := NewWithContext(context.Background(), testReference.Context().Registry, nil, wTprt, []string{testReference.Scope(PullScope)}); err != nil {
    52  		t.Errorf("NewWithContext unexpected error %s", err)
    53  	}
    54  }
    55  
    56  func TestTransportSelectionAnonymous(t *testing.T) {
    57  	// Record the requests we get in the inner transport.
    58  	cannedResponse := http.Response{
    59  		Status:     http.StatusText(http.StatusOK),
    60  		StatusCode: http.StatusOK,
    61  		Body:       io.NopCloser(strings.NewReader("")),
    62  	}
    63  	recorder := newRecorder(&cannedResponse, nil)
    64  
    65  	basic := &authn.Basic{Username: "foo", Password: "bar"}
    66  	reg := testReference.Context().Registry
    67  
    68  	tp, err := NewWithContext(context.Background(), reg, basic, recorder, []string{testReference.Scope(PullScope)})
    69  	if err != nil {
    70  		t.Errorf("NewWithContext() = %v", err)
    71  	}
    72  
    73  	req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/v2/anything", reg), nil)
    74  	if err != nil {
    75  		t.Fatalf("Unexpected error during NewRequest: %v", err)
    76  	}
    77  	if _, err := tp.RoundTrip(req); err != nil {
    78  		t.Fatalf("Unexpected error during RoundTrip: %v", err)
    79  	}
    80  
    81  	if got, want := len(recorder.reqs), 2; got != want {
    82  		t.Fatalf("expected %d requests, got %d", want, got)
    83  	}
    84  	recorded := recorder.reqs[1]
    85  	if got, want := recorded.URL.Scheme, "https"; got != want {
    86  		t.Errorf("wrong scheme, want %s got %s", want, got)
    87  	}
    88  }
    89  
    90  func TestTransportSelectionBasic(t *testing.T) {
    91  	server := httptest.NewServer(
    92  		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    93  			w.Header().Set("WWW-Authenticate", `Basic`)
    94  			http.Error(w, "Unauthorized", http.StatusUnauthorized)
    95  		}))
    96  	defer server.Close()
    97  	tprt := &http.Transport{
    98  		Proxy: func(req *http.Request) (*url.URL, error) {
    99  			return url.Parse(server.URL)
   100  		},
   101  	}
   102  
   103  	basic := &authn.Basic{Username: "foo", Password: "bar"}
   104  
   105  	tp, err := NewWithContext(context.Background(), testReference.Context().Registry, basic, tprt, []string{testReference.Scope(PullScope)})
   106  	if err != nil {
   107  		t.Errorf("NewWithContext() = %v", err)
   108  	}
   109  	if tpw, ok := tp.(*Wrapper); !ok {
   110  		t.Errorf("NewWithContext(); got %T, want *Wrapper", tp)
   111  	} else if _, ok := tpw.inner.(*basicTransport); !ok {
   112  		t.Errorf("NewWithContext(); got %T, want *basicTransport", tp)
   113  	}
   114  }
   115  
   116  type badAuth struct{}
   117  
   118  func (a *badAuth) Authorization() (*authn.AuthConfig, error) {
   119  	return nil, errors.New("sorry dave, I'm afraid I can't let you do that")
   120  }
   121  
   122  func TestTransportBadAuth(t *testing.T) {
   123  	server := httptest.NewServer(
   124  		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   125  			w.Header().Set("WWW-Authenticate", `Bearer realm="http://foo.io"`)
   126  			http.Error(w, "Unauthorized", http.StatusUnauthorized)
   127  		}))
   128  	defer server.Close()
   129  	tprt := &http.Transport{
   130  		Proxy: func(req *http.Request) (*url.URL, error) {
   131  			return url.Parse(server.URL)
   132  		},
   133  	}
   134  
   135  	if _, err := NewWithContext(context.Background(), testReference.Context().Registry, &badAuth{}, tprt, []string{testReference.Scope(PullScope)}); err == nil {
   136  		t.Errorf("NewWithContext() expected err, got nil")
   137  	}
   138  }
   139  
   140  func TestTransportSelectionBearer(t *testing.T) {
   141  	request := 0
   142  	server := httptest.NewServer(
   143  		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   144  			request++
   145  			switch request {
   146  			case 1:
   147  				// This is an https request that fails, causing us to fall back to http.
   148  				http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
   149  			case 2:
   150  				w.Header().Set("WWW-Authenticate", `Bearer realm="http://foo.io"`)
   151  				http.Error(w, "Unauthorized", http.StatusUnauthorized)
   152  			case 3:
   153  				hdr := r.Header.Get("Authorization")
   154  				if !strings.HasPrefix(hdr, "Basic ") {
   155  					t.Errorf("Header.Get(Authorization); got %v, want Basic prefix", hdr)
   156  				}
   157  				if got, want := r.FormValue("scope"), testReference.Scope(PullScope); got != want {
   158  					t.Errorf("FormValue(scope); got %v, want %v", got, want)
   159  				}
   160  				// Check that the service isn't set (we didn't specify it above)
   161  				// https://github.com/google/go-containerregistry/issues/1359
   162  				if got, want := r.FormValue("service"), ""; got != want {
   163  					t.Errorf("FormValue(service); got %q, want %q", got, want)
   164  				}
   165  				w.Write([]byte(`{"token": "dfskdjhfkhsjdhfkjhsdf"}`))
   166  			}
   167  		}))
   168  	defer server.Close()
   169  	tprt := &http.Transport{
   170  		Proxy: func(req *http.Request) (*url.URL, error) {
   171  			return url.Parse(server.URL)
   172  		},
   173  	}
   174  
   175  	basic := &authn.Basic{Username: "foo", Password: "bar"}
   176  	tp, err := NewWithContext(context.Background(), testReference.Context().Registry, basic, tprt, []string{testReference.Scope(PullScope)})
   177  	if err != nil {
   178  		t.Errorf("NewWithContext() = %v", err)
   179  	}
   180  	if tpw, ok := tp.(*Wrapper); !ok {
   181  		t.Errorf("NewWithContext(); got %T, want *Wrapper", tp)
   182  	} else if _, ok := tpw.inner.(*bearerTransport); !ok {
   183  		t.Errorf("NewWithContext(); got %T, want *bearerTransport", tp)
   184  	}
   185  }
   186  
   187  func TestTransportSelectionBearerMissingRealm(t *testing.T) {
   188  	server := httptest.NewServer(
   189  		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   190  			w.Header().Set("WWW-Authenticate", `Bearer service="gcr.io"`)
   191  			http.Error(w, "Unauthorized", http.StatusUnauthorized)
   192  		}))
   193  	defer server.Close()
   194  	tprt := &http.Transport{
   195  		Proxy: func(req *http.Request) (*url.URL, error) {
   196  			return url.Parse(server.URL)
   197  		},
   198  	}
   199  
   200  	basic := &authn.Basic{Username: "foo", Password: "bar"}
   201  	tp, err := NewWithContext(context.Background(), testReference.Context().Registry, basic, tprt, []string{testReference.Scope(PullScope)})
   202  	if err == nil || !strings.Contains(err.Error(), "missing realm") {
   203  		t.Errorf("NewWithContext() = %v, %v", tp, err)
   204  	}
   205  }
   206  
   207  func TestTransportSelectionBearerAuthError(t *testing.T) {
   208  	request := 0
   209  	server := httptest.NewServer(
   210  		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   211  			request++
   212  			switch request {
   213  			case 1:
   214  				w.Header().Set("WWW-Authenticate", `Bearer realm="http://foo.io"`)
   215  				http.Error(w, "Unauthorized", http.StatusUnauthorized)
   216  			case 2:
   217  				http.Error(w, "Oops", http.StatusInternalServerError)
   218  			}
   219  		}))
   220  	defer server.Close()
   221  	tprt := &http.Transport{
   222  		Proxy: func(req *http.Request) (*url.URL, error) {
   223  			return url.Parse(server.URL)
   224  		},
   225  	}
   226  
   227  	basic := &authn.Basic{Username: "foo", Password: "bar"}
   228  	tp, err := NewWithContext(context.Background(), testReference.Context().Registry, basic, tprt, []string{testReference.Scope(PullScope)})
   229  	if err == nil {
   230  		t.Errorf("NewWithContext() = %v", tp)
   231  	}
   232  }
   233  
   234  func TestTransportAlwaysTriesHttps(t *testing.T) {
   235  	// Use a NewTLSServer so that this speaks TLS even though it's localhost.
   236  	// This ensures that we try https even for local registries.
   237  	count := 0
   238  	server := httptest.NewTLSServer(
   239  		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   240  			count++
   241  			w.Write([]byte(`{"token": "dfskdjhfkhsjdhfkjhsdf"}`))
   242  		}))
   243  	defer server.Close()
   244  
   245  	u, err := url.Parse(server.URL)
   246  	if err != nil {
   247  		t.Errorf("Unexpected error during url.Parse: %v", err)
   248  	}
   249  	registry, err := name.NewRegistry(u.Host, name.WeakValidation)
   250  	if err != nil {
   251  		t.Errorf("Unexpected error during NewRegistry: %v", err)
   252  	}
   253  
   254  	basic := &authn.Basic{Username: "foo", Password: "bar"}
   255  	tp, err := NewWithContext(context.Background(), registry, basic, server.Client().Transport, []string{testReference.Scope(PullScope)})
   256  	if err != nil {
   257  		t.Fatalf("NewWithContext() = %v, %v", tp, err)
   258  	}
   259  	if count == 0 {
   260  		t.Errorf("failed to call TLS localhost server")
   261  	}
   262  }
   263  

View as plain text