Browse code

Make the v2 logic fallback on v1 when v2 requests cannot be authorized.

Signed-off-by: Matt Moore <mattmoor@google.com>

Matt Moore authored on 2015/05/29 12:46:20
Showing 3 changed files
... ...
@@ -482,6 +482,10 @@ func (s *TagStore) pullV2Repository(r *registry.Session, out io.Writer, repoInfo
482 482
 	if err != nil {
483 483
 		return fmt.Errorf("error getting authorization: %s", err)
484 484
 	}
485
+	if !auth.CanAuthorizeV2() {
486
+		return ErrV2RegistryUnavailable
487
+	}
488
+
485 489
 	var layersDownloaded bool
486 490
 	if tag == "" {
487 491
 		logrus.Debugf("Pulling tag list from V2 registry for %s", repoInfo.CanonicalName)
... ...
@@ -322,6 +322,9 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o
322 322
 	if err != nil {
323 323
 		return fmt.Errorf("error getting authorization: %s", err)
324 324
 	}
325
+	if !auth.CanAuthorizeV2() {
326
+		return ErrV2RegistryUnavailable
327
+	}
325 328
 
326 329
 	for _, tag := range tags {
327 330
 		logrus.Debugf("Pushing repository: %s:%s", repoInfo.CanonicalName, tag)
... ...
@@ -549,6 +552,7 @@ func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) erro
549 549
 		if err != ErrV2RegistryUnavailable {
550 550
 			return fmt.Errorf("Error pushing to registry: %s", err)
551 551
 		}
552
+		logrus.Debug("V2 registry is unavailable, falling back on V1")
552 553
 	}
553 554
 
554 555
 	if err := s.pushRepository(r, imagePushConfig.OutStream, repoInfo, localRepo, imagePushConfig.Tag, sf); err != nil {
... ...
@@ -74,6 +74,19 @@ func (auth *RequestAuthorization) getToken() (string, error) {
74 74
 	return "", nil
75 75
 }
76 76
 
77
+// Checks that requests to the v2 registry can be authorized.
78
+func (auth *RequestAuthorization) CanAuthorizeV2() bool {
79
+	if len(auth.registryEndpoint.AuthChallenges) == 0 {
80
+		return true
81
+	}
82
+	scope := fmt.Sprintf("%s:%s:%s", auth.resource, auth.scope, strings.Join(auth.actions, ","))
83
+	if _, err := loginV2(auth.authConfig, auth.registryEndpoint, scope); err != nil {
84
+		logrus.Debugf("Cannot authorize against V2 endpoint: %s", auth.registryEndpoint)
85
+		return false
86
+	}
87
+	return true
88
+}
89
+
77 90
 func (auth *RequestAuthorization) Authorize(req *http.Request) error {
78 91
 	token, err := auth.getToken()
79 92
 	if err != nil {
... ...
@@ -91,7 +104,7 @@ func (auth *RequestAuthorization) Authorize(req *http.Request) error {
91 91
 func Login(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (string, error) {
92 92
 	// Separates the v2 registry login logic from the v1 logic.
93 93
 	if registryEndpoint.Version == APIVersion2 {
94
-		return loginV2(authConfig, registryEndpoint)
94
+		return loginV2(authConfig, registryEndpoint, "" /* scope */)
95 95
 	}
96 96
 	return loginV1(authConfig, registryEndpoint)
97 97
 }
... ...
@@ -209,7 +222,7 @@ func loginV1(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (stri
209 209
 // now, users should create their account through other means like directly from a web page
210 210
 // served by the v2 registry service provider. Whether this will be supported in the future
211 211
 // is to be determined.
212
-func loginV2(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (string, error) {
212
+func loginV2(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint, scope string) (string, error) {
213 213
 	logrus.Debugf("attempting v2 login to registry endpoint %s", registryEndpoint)
214 214
 	var (
215 215
 		err       error
... ...
@@ -217,13 +230,18 @@ func loginV2(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (stri
217 217
 	)
218 218
 
219 219
 	for _, challenge := range registryEndpoint.AuthChallenges {
220
-		logrus.Debugf("trying %q auth challenge with params %s", challenge.Scheme, challenge.Parameters)
220
+		params := make(map[string]string, len(challenge.Parameters)+1)
221
+		for k, v := range challenge.Parameters {
222
+			params[k] = v
223
+		}
224
+		params["scope"] = scope
225
+		logrus.Debugf("trying %q auth challenge with params %v", challenge.Scheme, params)
221 226
 
222 227
 		switch strings.ToLower(challenge.Scheme) {
223 228
 		case "basic":
224
-			err = tryV2BasicAuthLogin(authConfig, challenge.Parameters, registryEndpoint)
229
+			err = tryV2BasicAuthLogin(authConfig, params, registryEndpoint)
225 230
 		case "bearer":
226
-			err = tryV2TokenAuthLogin(authConfig, challenge.Parameters, registryEndpoint)
231
+			err = tryV2TokenAuthLogin(authConfig, params, registryEndpoint)
227 232
 		default:
228 233
 			// Unsupported challenge types are explicitly skipped.
229 234
 			err = fmt.Errorf("unsupported auth scheme: %q", challenge.Scheme)