Browse code

distribution: add test to ensure pass-thru registry token is host-bound

Signed-off-by: Tibor Vass <tibor@docker.com>

Tibor Vass authored on 2016/01/27 07:14:13
Showing 1 changed files
... ...
@@ -16,24 +16,27 @@ import (
16 16
 	"golang.org/x/net/context"
17 17
 )
18 18
 
19
-func TestTokenPassThru(t *testing.T) {
20
-	authConfig := &types.AuthConfig{
21
-		RegistryToken: "mysecrettoken",
19
+const secretRegistryToken = "mysecrettoken"
20
+
21
+type tokenPassThruHandler struct {
22
+	reached       bool
23
+	gotToken      bool
24
+	shouldSend401 func(url string) bool
25
+}
26
+
27
+func (h *tokenPassThruHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
28
+	h.reached = true
29
+	if strings.Contains(r.Header.Get("Authorization"), secretRegistryToken) {
30
+		logrus.Debug("Detected registry token in auth header")
31
+		h.gotToken = true
22 32
 	}
23
-	gotToken := false
24
-	handler := func(w http.ResponseWriter, r *http.Request) {
25
-		if strings.Contains(r.Header.Get("Authorization"), authConfig.RegistryToken) {
26
-			logrus.Debug("Detected registry token in auth header")
27
-			gotToken = true
28
-		}
29
-		if r.RequestURI == "/v2/" {
30
-			w.Header().Set("WWW-Authenticate", `Bearer realm="foorealm"`)
31
-			w.WriteHeader(401)
32
-		}
33
+	if h.shouldSend401 == nil || h.shouldSend401(r.RequestURI) {
34
+		w.Header().Set("WWW-Authenticate", `Bearer realm="foorealm"`)
35
+		w.WriteHeader(401)
33 36
 	}
34
-	ts := httptest.NewServer(http.HandlerFunc(handler))
35
-	defer ts.Close()
37
+}
36 38
 
39
+func testTokenPassThru(t *testing.T, ts *httptest.Server) {
37 40
 	tmp, err := utils.TestDirectory("")
38 41
 	if err != nil {
39 42
 		t.Fatal(err)
... ...
@@ -62,7 +65,9 @@ func TestTokenPassThru(t *testing.T) {
62 62
 	}
63 63
 	imagePullConfig := &ImagePullConfig{
64 64
 		MetaHeaders: http.Header{},
65
-		AuthConfig:  authConfig,
65
+		AuthConfig: &types.AuthConfig{
66
+			RegistryToken: secretRegistryToken,
67
+		},
66 68
 	}
67 69
 	puller, err := newPuller(endpoint, repoInfo, imagePullConfig)
68 70
 	if err != nil {
... ...
@@ -79,9 +84,44 @@ func TestTokenPassThru(t *testing.T) {
79 79
 	// We expect it to fail, since we haven't mock'd the full registry exchange in our handler above
80 80
 	tag, _ := reference.WithTag(n, "tag_goes_here")
81 81
 	_ = p.pullV2Repository(ctx, tag)
82
+}
82 83
 
83
-	if !gotToken {
84
+func TestTokenPassThru(t *testing.T) {
85
+	handler := &tokenPassThruHandler{shouldSend401: func(url string) bool { return url == "/v2/" }}
86
+	ts := httptest.NewServer(handler)
87
+	defer ts.Close()
88
+
89
+	testTokenPassThru(t, ts)
90
+
91
+	if !handler.reached {
92
+		t.Fatal("Handler not reached")
93
+	}
94
+	if !handler.gotToken {
84 95
 		t.Fatal("Failed to receive registry token")
85 96
 	}
97
+}
98
+
99
+func TestTokenPassThruDifferentHost(t *testing.T) {
100
+	handler := new(tokenPassThruHandler)
101
+	ts := httptest.NewServer(handler)
102
+	defer ts.Close()
103
+
104
+	tsredirect := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
105
+		if r.RequestURI == "/v2/" {
106
+			w.Header().Set("WWW-Authenticate", `Bearer realm="foorealm"`)
107
+			w.WriteHeader(401)
108
+			return
109
+		}
110
+		http.Redirect(w, r, ts.URL+r.URL.Path, http.StatusMovedPermanently)
111
+	}))
112
+	defer tsredirect.Close()
86 113
 
114
+	testTokenPassThru(t, tsredirect)
115
+
116
+	if !handler.reached {
117
+		t.Fatal("Handler not reached")
118
+	}
119
+	if handler.gotToken {
120
+		t.Fatal("Redirect should not forward Authorization header to another host")
121
+	}
87 122
 }