浏览代码

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

Signed-off-by: Matt Moore <mattmoor@google.com>
Matt Moore 10 年之前
父节点
当前提交
bd2575cc4f
共有 3 个文件被更改,包括 31 次插入5 次删除
  1. 4 0
      graph/pull.go
  2. 4 0
      graph/push.go
  3. 23 5
      registry/auth.go

+ 4 - 0
graph/pull.go

@@ -482,6 +482,10 @@ func (s *TagStore) pullV2Repository(r *registry.Session, out io.Writer, repoInfo
 	if err != nil {
 		return fmt.Errorf("error getting authorization: %s", err)
 	}
+	if !auth.CanAuthorizeV2() {
+		return ErrV2RegistryUnavailable
+	}
+
 	var layersDownloaded bool
 	if tag == "" {
 		logrus.Debugf("Pulling tag list from V2 registry for %s", repoInfo.CanonicalName)

+ 4 - 0
graph/push.go

@@ -322,6 +322,9 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o
 	if err != nil {
 		return fmt.Errorf("error getting authorization: %s", err)
 	}
+	if !auth.CanAuthorizeV2() {
+		return ErrV2RegistryUnavailable
+	}
 
 	for _, tag := range tags {
 		logrus.Debugf("Pushing repository: %s:%s", repoInfo.CanonicalName, tag)
@@ -549,6 +552,7 @@ func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) erro
 		if err != ErrV2RegistryUnavailable {
 			return fmt.Errorf("Error pushing to registry: %s", err)
 		}
+		logrus.Debug("V2 registry is unavailable, falling back on V1")
 	}
 
 	if err := s.pushRepository(r, imagePushConfig.OutStream, repoInfo, localRepo, imagePushConfig.Tag, sf); err != nil {

+ 23 - 5
registry/auth.go

@@ -74,6 +74,19 @@ func (auth *RequestAuthorization) getToken() (string, error) {
 	return "", nil
 }
 
+// Checks that requests to the v2 registry can be authorized.
+func (auth *RequestAuthorization) CanAuthorizeV2() bool {
+	if len(auth.registryEndpoint.AuthChallenges) == 0 {
+		return true
+	}
+	scope := fmt.Sprintf("%s:%s:%s", auth.resource, auth.scope, strings.Join(auth.actions, ","))
+	if _, err := loginV2(auth.authConfig, auth.registryEndpoint, scope); err != nil {
+		logrus.Debugf("Cannot authorize against V2 endpoint: %s", auth.registryEndpoint)
+		return false
+	}
+	return true
+}
+
 func (auth *RequestAuthorization) Authorize(req *http.Request) error {
 	token, err := auth.getToken()
 	if err != nil {
@@ -91,7 +104,7 @@ func (auth *RequestAuthorization) Authorize(req *http.Request) error {
 func Login(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (string, error) {
 	// Separates the v2 registry login logic from the v1 logic.
 	if registryEndpoint.Version == APIVersion2 {
-		return loginV2(authConfig, registryEndpoint)
+		return loginV2(authConfig, registryEndpoint, "" /* scope */)
 	}
 	return loginV1(authConfig, registryEndpoint)
 }
@@ -209,7 +222,7 @@ func loginV1(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (stri
 // now, users should create their account through other means like directly from a web page
 // served by the v2 registry service provider. Whether this will be supported in the future
 // is to be determined.
-func loginV2(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (string, error) {
+func loginV2(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint, scope string) (string, error) {
 	logrus.Debugf("attempting v2 login to registry endpoint %s", registryEndpoint)
 	var (
 		err       error
@@ -217,13 +230,18 @@ func loginV2(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (stri
 	)
 
 	for _, challenge := range registryEndpoint.AuthChallenges {
-		logrus.Debugf("trying %q auth challenge with params %s", challenge.Scheme, challenge.Parameters)
+		params := make(map[string]string, len(challenge.Parameters)+1)
+		for k, v := range challenge.Parameters {
+			params[k] = v
+		}
+		params["scope"] = scope
+		logrus.Debugf("trying %q auth challenge with params %v", challenge.Scheme, params)
 
 		switch strings.ToLower(challenge.Scheme) {
 		case "basic":
-			err = tryV2BasicAuthLogin(authConfig, challenge.Parameters, registryEndpoint)
+			err = tryV2BasicAuthLogin(authConfig, params, registryEndpoint)
 		case "bearer":
-			err = tryV2TokenAuthLogin(authConfig, challenge.Parameters, registryEndpoint)
+			err = tryV2TokenAuthLogin(authConfig, params, registryEndpoint)
 		default:
 			// Unsupported challenge types are explicitly skipped.
 			err = fmt.Errorf("unsupported auth scheme: %q", challenge.Scheme)