Ver código fonte

Merge pull request #43885 from thaJeztah/auth_header_refactor

Move AuthConfig to types/registry, and implement utilities for encoding/decoding
Tianon Gravi 2 anos atrás
pai
commit
e60bddcc60
66 arquivos alterados com 462 adições e 345 exclusões
  1. 2 1
      api/server/middleware/cors.go
  2. 3 2
      api/server/router/build/build_routes.go
  3. 2 2
      api/server/router/distribution/backend.go
  4. 6 20
      api/server/router/distribution/distribution_routes.go
  5. 3 3
      api/server/router/image/backend.go
  6. 21 41
      api/server/router/image/image_routes.go
  7. 12 11
      api/server/router/plugin/backend.go
  8. 4 14
      api/server/router/plugin/plugin_routes.go
  9. 3 2
      api/server/router/swarm/cluster_routes.go
  10. 2 1
      api/server/router/system/backend.go
  11. 1 1
      api/server/router/system/system_routes.go
  12. 5 20
      api/types/auth.go
  13. 2 1
      api/types/backend/build.go
  14. 2 1
      api/types/client.go
  15. 99 0
      api/types/registry/authconfig.go
  16. 59 0
      api/types/registry/authconfig_test.go
  17. 4 4
      client/distribution_inspect.go
  18. 2 1
      client/image_build_test.go
  19. 2 1
      client/image_create.go
  20. 3 2
      client/image_create_test.go
  21. 4 3
      client/image_pull_test.go
  22. 2 1
      client/image_push.go
  23. 3 2
      client/image_push_test.go
  24. 1 1
      client/image_search.go
  25. 2 2
      client/image_search_test.go
  26. 1 1
      client/interface.go
  27. 1 2
      client/login.go
  28. 3 2
      client/plugin_install.go
  29. 3 1
      client/plugin_push.go
  30. 3 2
      client/plugin_push_test.go
  31. 2 1
      client/plugin_upgrade.go
  32. 2 1
      client/service_create.go
  33. 2 1
      client/service_update.go
  34. 2 2
      daemon/auth.go
  35. 15 14
      daemon/cluster/controllers/plugin/controller.go
  36. 8 7
      daemon/cluster/controllers/plugin/controller_test.go
  37. 6 5
      daemon/cluster/executor/backend.go
  38. 2 1
      daemon/cluster/executor/container/adapter.go
  39. 28 27
      daemon/cluster/services.go
  40. 3 3
      daemon/containerd/image_pull.go
  41. 2 2
      daemon/containerd/image_push.go
  42. 2 3
      daemon/containerd/image_search.go
  43. 4 4
      daemon/image_service.go
  44. 5 5
      daemon/images/image_builder.go
  45. 4 4
      daemon/images/image_pull.go
  46. 2 2
      daemon/images/image_push.go
  47. 5 6
      daemon/images/image_search.go
  48. 36 37
      daemon/images/image_search_test.go
  49. 4 4
      distribution/config.go
  50. 2 2
      distribution/metadata/v2_metadata_service.go
  51. 1 2
      distribution/pull_v2_test.go
  52. 6 6
      distribution/push_v2_test.go
  53. 2 2
      distribution/registry.go
  54. 6 7
      distribution/registry_unit_test.go
  55. 2 1
      integration/plugin/common/plugin_test.go
  56. 4 4
      integration/system/login_test.go
  57. 8 7
      plugin/backend_linux.go
  58. 5 4
      plugin/backend_unsupported.go
  59. 2 2
      plugin/fetch_linux.go
  60. 3 3
      plugin/registry.go
  61. 6 7
      registry/auth.go
  62. 7 8
      registry/auth_test.go
  63. 1 2
      registry/registry_test.go
  64. 4 5
      registry/service.go
  65. 3 4
      registry/session.go
  66. 6 5
      testutil/fixtures/plugin/plugin.go

+ 2 - 1
api/server/middleware/cors.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"net/http"
 
+	"github.com/docker/docker/api/types/registry"
 	"github.com/sirupsen/logrus"
 )
 
@@ -30,7 +31,7 @@ func (c CORSMiddleware) WrapHandler(handler func(ctx context.Context, w http.Res
 
 		logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
 		w.Header().Add("Access-Control-Allow-Origin", corsHeaders)
-		w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
+		w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, "+registry.AuthHeader)
 		w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
 		return handler(ctx, w, r, vars)
 	}

+ 3 - 2
api/server/router/build/build_routes.go

@@ -19,6 +19,7 @@ import (
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/api/types/versions"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/pkg/ioutils"
@@ -296,8 +297,8 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
 	return nil
 }
 
-func getAuthConfigs(header http.Header) map[string]types.AuthConfig {
-	authConfigs := map[string]types.AuthConfig{}
+func getAuthConfigs(header http.Header) map[string]registry.AuthConfig {
+	authConfigs := map[string]registry.AuthConfig{}
 	authConfigsEncoded := header.Get("X-Registry-Config")
 
 	if authConfigsEncoded == "" {

+ 2 - 2
api/server/router/distribution/backend.go

@@ -5,11 +5,11 @@ import (
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/reference"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 )
 
 // Backend is all the methods that need to be implemented
 // to provide image specific functionality.
 type Backend interface {
-	GetRepository(context.Context, reference.Named, *types.AuthConfig) (distribution.Repository, error)
+	GetRepository(context.Context, reference.Named, *registry.AuthConfig) (distribution.Repository, error)
 }

+ 6 - 20
api/server/router/distribution/distribution_routes.go

@@ -2,18 +2,15 @@ package distribution // import "github.com/docker/docker/api/server/router/distr
 
 import (
 	"context"
-	"encoding/base64"
 	"encoding/json"
 	"net/http"
-	"strings"
 
 	"github.com/docker/distribution/manifest/manifestlist"
 	"github.com/docker/distribution/manifest/schema1"
 	"github.com/docker/distribution/manifest/schema2"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/server/httputils"
-	"github.com/docker/docker/api/types"
-	registrytypes "github.com/docker/docker/api/types/registry"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 	v1 "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
@@ -26,21 +23,6 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
 
 	w.Header().Set("Content-Type", "application/json")
 
-	var (
-		config              = &types.AuthConfig{}
-		authEncoded         = r.Header.Get("X-Registry-Auth")
-		distributionInspect registrytypes.DistributionInspect
-	)
-
-	if authEncoded != "" {
-		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
-		if err := json.NewDecoder(authJSON).Decode(&config); err != nil {
-			// for a search it is not an error if no auth was given
-			// to increase compatibility with the existing api it is defaulting to be empty
-			config = &types.AuthConfig{}
-		}
-	}
-
 	image := vars["name"]
 
 	// TODO why is reference.ParseAnyReference() / reference.ParseNormalizedNamed() not using the reference.ErrTagInvalidFormat (and so on) errors?
@@ -57,12 +39,16 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
 		return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", image))
 	}
 
-	distrepo, err := s.backend.GetRepository(ctx, namedRef, config)
+	// For a search it is not an error if no auth was given. Ignore invalid
+	// AuthConfig to increase compatibility with the existing API.
+	authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader))
+	distrepo, err := s.backend.GetRepository(ctx, namedRef, authConfig)
 	if err != nil {
 		return err
 	}
 	blobsrvc := distrepo.Blobs(ctx)
 
+	var distributionInspect registry.DistributionInspect
 	if canonicalRef, ok := namedRef.(reference.Canonical); !ok {
 		namedRef = reference.TagNameOnly(namedRef)
 

+ 3 - 3
api/server/router/image/backend.go

@@ -36,7 +36,7 @@ type importExportBackend interface {
 }
 
 type registryBackend interface {
-	PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
-	PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
-	SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error)
+	PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
+	PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
+	SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *registry.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error)
 }

+ 21 - 41
api/server/router/image/image_routes.go

@@ -2,8 +2,6 @@ package image // import "github.com/docker/docker/api/server/router/image"
 
 import (
 	"context"
-	"encoding/base64"
-	"encoding/json"
 	"net/http"
 	"strconv"
 	"strings"
@@ -14,6 +12,7 @@ import (
 	"github.com/docker/docker/api/server/httputils"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/api/types/versions"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/image"
@@ -63,16 +62,9 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite
 			}
 		}
 
-		authEncoded := r.Header.Get("X-Registry-Auth")
-		authConfig := &types.AuthConfig{}
-		if authEncoded != "" {
-			authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
-			if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
-				// for a pull it is not an error if no auth was given
-				// to increase compatibility with the existing api it is defaulting to be empty
-				authConfig = &types.AuthConfig{}
-			}
-		}
+		// For a pull it is not an error if no auth was given. Ignore invalid
+		// AuthConfig to increase compatibility with the existing API.
+		authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader))
 		progressErr = s.backend.PullImage(ctx, image, tag, platform, metaHeaders, authConfig, output)
 	} else { // import
 		src := r.Form.Get("fromSrc")
@@ -98,32 +90,29 @@ func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter,
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 	}
-	authConfig := &types.AuthConfig{}
 
-	authEncoded := r.Header.Get("X-Registry-Auth")
-	if authEncoded != "" {
-		// the new format is to handle the authConfig as a header
-		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
-		if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
-			// to increase compatibility to existing api it is defaulting to be empty
-			authConfig = &types.AuthConfig{}
-		}
+	var authConfig *registry.AuthConfig
+	if authEncoded := r.Header.Get(registry.AuthHeader); authEncoded != "" {
+		// the new format is to handle the authConfig as a header. Ignore invalid
+		// AuthConfig to increase compatibility with the existing API.
+		authConfig, _ = registry.DecodeAuthConfig(authEncoded)
 	} else {
 		// the old format is supported for compatibility if there was no authConfig header
-		if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
-			return errors.Wrap(errdefs.InvalidParameter(err), "Bad parameters and missing X-Registry-Auth")
+		var err error
+		authConfig, err = registry.DecodeAuthConfigBody(r.Body)
+		if err != nil {
+			return errors.Wrap(err, "bad parameters and missing X-Registry-Auth")
 		}
 	}
 
-	image := vars["name"]
-	tag := r.Form.Get("tag")
-
 	output := ioutils.NewWriteFlusher(w)
 	defer output.Close()
 
 	w.Header().Set("Content-Type", "application/json")
 
-	if err := s.backend.PushImage(ctx, image, tag, metaHeaders, authConfig, output); err != nil {
+	img := vars["name"]
+	tag := r.Form.Get("tag")
+	if err := s.backend.PushImage(ctx, img, tag, metaHeaders, authConfig, output); err != nil {
 		if !output.Flushed() {
 			return err
 		}
@@ -358,20 +347,8 @@ func (s *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter
 	if err := httputils.ParseForm(r); err != nil {
 		return err
 	}
-	var (
-		config      *types.AuthConfig
-		authEncoded = r.Header.Get("X-Registry-Auth")
-		headers     = map[string][]string{}
-	)
 
-	if authEncoded != "" {
-		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
-		if err := json.NewDecoder(authJSON).Decode(&config); err != nil {
-			// for a search it is not an error if no auth was given
-			// to increase compatibility with the existing api it is defaulting to be empty
-			config = &types.AuthConfig{}
-		}
-	}
+	var headers = map[string][]string{}
 	for k, v := range r.Header {
 		if strings.HasPrefix(k, "X-Meta-") {
 			headers[k] = v
@@ -391,7 +368,10 @@ func (s *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter
 		return err
 	}
 
-	query, err := s.backend.SearchRegistryForImages(ctx, searchFilters, r.Form.Get("term"), limit, config, headers)
+	// For a search it is not an error if no auth was given. Ignore invalid
+	// AuthConfig to increase compatibility with the existing API.
+	authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader))
+	query, err := s.backend.SearchRegistryForImages(ctx, searchFilters, r.Form.Get("term"), limit, authConfig, headers)
 	if err != nil {
 		return err
 	}

+ 12 - 11
api/server/router/plugin/backend.go

@@ -6,22 +6,23 @@ import (
 	"net/http"
 
 	"github.com/docker/distribution/reference"
-	enginetypes "github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/plugin"
 )
 
 // Backend for Plugin
 type Backend interface {
-	Disable(name string, config *enginetypes.PluginDisableConfig) error
-	Enable(name string, config *enginetypes.PluginEnableConfig) error
-	List(filters.Args) ([]enginetypes.Plugin, error)
-	Inspect(name string) (*enginetypes.Plugin, error)
-	Remove(name string, config *enginetypes.PluginRmConfig) error
+	Disable(name string, config *types.PluginDisableConfig) error
+	Enable(name string, config *types.PluginEnableConfig) error
+	List(filters.Args) ([]types.Plugin, error)
+	Inspect(name string) (*types.Plugin, error)
+	Remove(name string, config *types.PluginRmConfig) error
 	Set(name string, args []string) error
-	Privileges(ctx context.Context, ref reference.Named, metaHeaders http.Header, authConfig *enginetypes.AuthConfig) (enginetypes.PluginPrivileges, error)
-	Pull(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges, outStream io.Writer, opts ...plugin.CreateOpt) error
-	Push(ctx context.Context, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, outStream io.Writer) error
-	Upgrade(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges, outStream io.Writer) error
-	CreateFromContext(ctx context.Context, tarCtx io.ReadCloser, options *enginetypes.PluginCreateOptions) error
+	Privileges(ctx context.Context, ref reference.Named, metaHeaders http.Header, authConfig *registry.AuthConfig) (types.PluginPrivileges, error)
+	Pull(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer, opts ...plugin.CreateOpt) error
+	Push(ctx context.Context, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, outStream io.Writer) error
+	Upgrade(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer) error
+	CreateFromContext(ctx context.Context, tarCtx io.ReadCloser, options *types.PluginCreateOptions) error
 }

+ 4 - 14
api/server/router/plugin/plugin_routes.go

@@ -2,8 +2,6 @@ package plugin // import "github.com/docker/docker/api/server/router/plugin"
 
 import (
 	"context"
-	"encoding/base64"
-	"encoding/json"
 	"net/http"
 	"strconv"
 	"strings"
@@ -12,13 +10,13 @@ import (
 	"github.com/docker/docker/api/server/httputils"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/streamformatter"
 	"github.com/pkg/errors"
 )
 
-func parseHeaders(headers http.Header) (map[string][]string, *types.AuthConfig) {
-
+func parseHeaders(headers http.Header) (map[string][]string, *registry.AuthConfig) {
 	metaHeaders := map[string][]string{}
 	for k, v := range headers {
 		if strings.HasPrefix(k, "X-Meta-") {
@@ -26,16 +24,8 @@ func parseHeaders(headers http.Header) (map[string][]string, *types.AuthConfig)
 		}
 	}
 
-	// Get X-Registry-Auth
-	authEncoded := headers.Get("X-Registry-Auth")
-	authConfig := &types.AuthConfig{}
-	if authEncoded != "" {
-		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
-		if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
-			authConfig = &types.AuthConfig{}
-		}
-	}
-
+	// Ignore invalid AuthConfig to increase compatibility with the existing API.
+	authConfig, _ := registry.DecodeAuthConfig(headers.Get(registry.AuthHeader))
 	return metaHeaders, authConfig
 }
 

+ 3 - 2
api/server/router/swarm/cluster_routes.go

@@ -10,6 +10,7 @@ import (
 	basictypes "github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/api/types/registry"
 	types "github.com/docker/docker/api/types/swarm"
 	"github.com/docker/docker/api/types/versions"
 	"github.com/docker/docker/errdefs"
@@ -207,7 +208,7 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
 	}
 
 	// Get returns "" if the header does not exist
-	encodedAuth := r.Header.Get("X-Registry-Auth")
+	encodedAuth := r.Header.Get(registry.AuthHeader)
 	queryRegistry := false
 	if v := httputils.VersionFromContext(ctx); v != "" {
 		if versions.LessThan(v, "1.30") {
@@ -240,7 +241,7 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
 	var flags basictypes.ServiceUpdateOptions
 
 	// Get returns "" if the header does not exist
-	flags.EncodedRegistryAuth = r.Header.Get("X-Registry-Auth")
+	flags.EncodedRegistryAuth = r.Header.Get(registry.AuthHeader)
 	flags.RegistryAuthFrom = r.URL.Query().Get("registryAuthFrom")
 	flags.Rollback = r.URL.Query().Get("rollback")
 	queryRegistry := false

+ 2 - 1
api/server/router/system/backend.go

@@ -7,6 +7,7 @@ import (
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/events"
 	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/api/types/swarm"
 )
 
@@ -30,7 +31,7 @@ type Backend interface {
 	SystemDiskUsage(ctx context.Context, opts DiskUsageOptions) (*types.DiskUsage, error)
 	SubscribeToEvents(since, until time.Time, ef filters.Args) ([]events.Message, chan interface{})
 	UnsubscribeFromEvents(chan interface{})
-	AuthenticateToRegistry(ctx context.Context, authConfig *types.AuthConfig) (string, string, error)
+	AuthenticateToRegistry(ctx context.Context, authConfig *registry.AuthConfig) (string, string, error)
 }
 
 // ClusterBackend is all the methods that need to be implemented

+ 1 - 1
api/server/router/system/system_routes.go

@@ -281,7 +281,7 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
 }
 
 func (s *systemRouter) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	var config *types.AuthConfig
+	var config *registry.AuthConfig
 	err := json.NewDecoder(r.Body).Decode(&config)
 	r.Body.Close()
 	if err != nil {

+ 5 - 20
api/types/auth.go

@@ -1,22 +1,7 @@
 package types // import "github.com/docker/docker/api/types"
+import "github.com/docker/docker/api/types/registry"
 
-// AuthConfig contains authorization information for connecting to a Registry
-type AuthConfig struct {
-	Username string `json:"username,omitempty"`
-	Password string `json:"password,omitempty"`
-	Auth     string `json:"auth,omitempty"`
-
-	// Email is an optional value associated with the username.
-	// This field is deprecated and will be removed in a later
-	// version of docker.
-	Email string `json:"email,omitempty"`
-
-	ServerAddress string `json:"serveraddress,omitempty"`
-
-	// IdentityToken is used to authenticate the user and get
-	// an access token for the registry.
-	IdentityToken string `json:"identitytoken,omitempty"`
-
-	// RegistryToken is a bearer token to be sent to a registry
-	RegistryToken string `json:"registrytoken,omitempty"`
-}
+// AuthConfig contains authorization information for connecting to a Registry.
+//
+// Deprecated: use github.com/docker/docker/api/types/registry.AuthConfig
+type AuthConfig = registry.AuthConfig

+ 2 - 1
api/types/backend/build.go

@@ -4,6 +4,7 @@ import (
 	"io"
 
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/pkg/streamformatter"
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
@@ -39,7 +40,7 @@ type BuildConfig struct {
 // GetImageAndLayerOptions are the options supported by GetImageAndReleasableLayer
 type GetImageAndLayerOptions struct {
 	PullOption PullOption
-	AuthConfig map[string]types.AuthConfig
+	AuthConfig map[string]registry.AuthConfig
 	Output     io.Writer
 	Platform   *specs.Platform
 }

+ 2 - 1
api/types/client.go

@@ -7,6 +7,7 @@ import (
 
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/api/types/registry"
 	units "github.com/docker/go-units"
 )
 
@@ -180,7 +181,7 @@ type ImageBuildOptions struct {
 	// at all (nil). See the parsing of buildArgs in
 	// api/server/router/build/build_routes.go for even more info.
 	BuildArgs   map[string]*string
-	AuthConfigs map[string]AuthConfig
+	AuthConfigs map[string]registry.AuthConfig
 	Context     io.Reader
 	Labels      map[string]string
 	// squash the resulting image's layers to the parent

+ 99 - 0
api/types/registry/authconfig.go

@@ -0,0 +1,99 @@
+package registry // import "github.com/docker/docker/api/types/registry"
+import (
+	"encoding/base64"
+	"encoding/json"
+	"io"
+	"strings"
+
+	"github.com/pkg/errors"
+)
+
+// AuthHeader is the name of the header used to send encoded registry
+// authorization credentials for registry operations (push/pull).
+const AuthHeader = "X-Registry-Auth"
+
+// AuthConfig contains authorization information for connecting to a Registry.
+type AuthConfig struct {
+	Username string `json:"username,omitempty"`
+	Password string `json:"password,omitempty"`
+	Auth     string `json:"auth,omitempty"`
+
+	// Email is an optional value associated with the username.
+	// This field is deprecated and will be removed in a later
+	// version of docker.
+	Email string `json:"email,omitempty"`
+
+	ServerAddress string `json:"serveraddress,omitempty"`
+
+	// IdentityToken is used to authenticate the user and get
+	// an access token for the registry.
+	IdentityToken string `json:"identitytoken,omitempty"`
+
+	// RegistryToken is a bearer token to be sent to a registry
+	RegistryToken string `json:"registrytoken,omitempty"`
+}
+
+// EncodeAuthConfig serializes the auth configuration as a base64url encoded
+// RFC4648, section 5) JSON string for sending through the X-Registry-Auth header.
+//
+// For details on base64url encoding, see:
+// - RFC4648, section 5:   https://tools.ietf.org/html/rfc4648#section-5
+func EncodeAuthConfig(authConfig AuthConfig) (string, error) {
+	buf, err := json.Marshal(authConfig)
+	if err != nil {
+		return "", errInvalidParameter{err}
+	}
+	return base64.URLEncoding.EncodeToString(buf), nil
+}
+
+// DecodeAuthConfig decodes base64url encoded (RFC4648, section 5) JSON
+// authentication information as sent through the X-Registry-Auth header.
+//
+// This function always returns an AuthConfig, even if an error occurs. It is up
+// to the caller to decide if authentication is required, and if the error can
+// be ignored.
+//
+// For details on base64url encoding, see:
+// - RFC4648, section 5:   https://tools.ietf.org/html/rfc4648#section-5
+func DecodeAuthConfig(authEncoded string) (*AuthConfig, error) {
+	if authEncoded == "" {
+		return &AuthConfig{}, nil
+	}
+
+	authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
+	return decodeAuthConfigFromReader(authJSON)
+}
+
+// DecodeAuthConfigBody decodes authentication information as sent as JSON in the
+// body of a request. This function is to provide backward compatibility with old
+// clients and API versions. Current clients and API versions expect authentication
+// to be provided through the X-Registry-Auth header.
+//
+// Like DecodeAuthConfig, this function always returns an AuthConfig, even if an
+// error occurs. It is up to the caller to decide if authentication is required,
+// and if the error can be ignored.
+func DecodeAuthConfigBody(rdr io.ReadCloser) (*AuthConfig, error) {
+	return decodeAuthConfigFromReader(rdr)
+}
+
+func decodeAuthConfigFromReader(rdr io.Reader) (*AuthConfig, error) {
+	authConfig := &AuthConfig{}
+	if err := json.NewDecoder(rdr).Decode(authConfig); err != nil {
+		// always return an (empty) AuthConfig to increase compatibility with
+		// the existing API.
+		return &AuthConfig{}, invalid(err)
+	}
+	return authConfig, nil
+}
+
+func invalid(err error) error {
+	return errInvalidParameter{errors.Wrap(err, "invalid X-Registry-Auth header")}
+}
+
+type errInvalidParameter struct{ error }
+
+func (errInvalidParameter) InvalidParameter() {}
+
+func (e errInvalidParameter) Cause() error { return e.error }
+
+func (e errInvalidParameter) Unwrap() error { return e.error }

+ 59 - 0
api/types/registry/authconfig_test.go

@@ -0,0 +1,59 @@
+package registry // import "github.com/docker/docker/api/types/registry"
+import (
+	"io"
+	"strings"
+	"testing"
+
+	"gotest.tools/v3/assert"
+)
+
+const (
+	unencoded        = `{"username":"testuser","password":"testpassword","serveraddress":"example.com"}`
+	encoded          = `eyJ1c2VybmFtZSI6InRlc3R1c2VyIiwicGFzc3dvcmQiOiJ0ZXN0cGFzc3dvcmQiLCJzZXJ2ZXJhZGRyZXNzIjoiZXhhbXBsZS5jb20ifQ==`
+	encodedNoPadding = `eyJ1c2VybmFtZSI6InRlc3R1c2VyIiwicGFzc3dvcmQiOiJ0ZXN0cGFzc3dvcmQiLCJzZXJ2ZXJhZGRyZXNzIjoiZXhhbXBsZS5jb20ifQ`
+)
+
+var expected = AuthConfig{
+	Username:      "testuser",
+	Password:      "testpassword",
+	ServerAddress: "example.com",
+}
+
+func TestDecodeAuthConfig(t *testing.T) {
+	t.Run("valid", func(t *testing.T) {
+		token, err := DecodeAuthConfig(encoded)
+		assert.NilError(t, err)
+		assert.Equal(t, *token, expected)
+	})
+
+	t.Run("empty", func(t *testing.T) {
+		token, err := DecodeAuthConfig("")
+		assert.NilError(t, err)
+		assert.Equal(t, *token, AuthConfig{})
+	})
+
+	// We currently only support base64url encoding with padding, so
+	// un-padded should produce an error.
+	//
+	// RFC4648, section 5: https://tools.ietf.org/html/rfc4648#section-5
+	// RFC4648, section 3.2: https://tools.ietf.org/html/rfc4648#section-3.2
+	t.Run("invalid encoding", func(t *testing.T) {
+		token, err := DecodeAuthConfig(encodedNoPadding)
+
+		assert.ErrorType(t, err, errInvalidParameter{})
+		assert.ErrorContains(t, err, "invalid X-Registry-Auth header: unexpected EOF")
+		assert.Equal(t, *token, AuthConfig{})
+	})
+}
+
+func TestDecodeAuthConfigBody(t *testing.T) {
+	token, err := DecodeAuthConfigBody(io.NopCloser(strings.NewReader(unencoded)))
+	assert.NilError(t, err)
+	assert.Equal(t, *token, expected)
+}
+
+func TestEncodeAuthConfig(t *testing.T) {
+	token, err := EncodeAuthConfig(expected)
+	assert.NilError(t, err)
+	assert.Equal(t, token, encoded)
+}

+ 4 - 4
client/distribution_inspect.go

@@ -5,13 +5,13 @@ import (
 	"encoding/json"
 	"net/url"
 
-	registrytypes "github.com/docker/docker/api/types/registry"
+	"github.com/docker/docker/api/types/registry"
 )
 
 // DistributionInspect returns the image digest with the full manifest.
-func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registrytypes.DistributionInspect, error) {
+func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registry.DistributionInspect, error) {
 	// Contact the registry to retrieve digest and platform information
-	var distributionInspect registrytypes.DistributionInspect
+	var distributionInspect registry.DistributionInspect
 	if image == "" {
 		return distributionInspect, objectNotFoundError{object: "distribution", id: image}
 	}
@@ -23,7 +23,7 @@ func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegist
 
 	if encodedRegistryAuth != "" {
 		headers = map[string][]string{
-			"X-Registry-Auth": {encodedRegistryAuth},
+			registry.AuthHeader: {encodedRegistryAuth},
 		}
 	}
 

+ 2 - 1
client/image_build_test.go

@@ -12,6 +12,7 @@ import (
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 	units "github.com/docker/go-units"
 )
@@ -144,7 +145,7 @@ func TestImageBuild(t *testing.T) {
 		},
 		{
 			buildOptions: types.ImageBuildOptions{
-				AuthConfigs: map[string]types.AuthConfig{
+				AuthConfigs: map[string]registry.AuthConfig{
 					"https://index.docker.io/v1/": {
 						Auth: "dG90bwo=",
 					},

+ 2 - 1
client/image_create.go

@@ -8,6 +8,7 @@ import (
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 )
 
 // ImageCreate creates a new image based on the parent options.
@@ -32,6 +33,6 @@ func (cli *Client) ImageCreate(ctx context.Context, parentReference string, opti
 }
 
 func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
+	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
 	return cli.post(ctx, "/images/create", query, nil, headers)
 }

+ 3 - 2
client/image_create_test.go

@@ -10,6 +10,7 @@ import (
 	"testing"
 
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 )
 
@@ -34,9 +35,9 @@ func TestImageCreate(t *testing.T) {
 			if !strings.HasPrefix(r.URL.Path, expectedURL) {
 				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, r.URL)
 			}
-			registryAuth := r.Header.Get("X-Registry-Auth")
+			registryAuth := r.Header.Get(registry.AuthHeader)
 			if registryAuth != expectedRegistryAuth {
-				return nil, fmt.Errorf("X-Registry-Auth header not properly set in the request. Expected '%s', got %s", expectedRegistryAuth, registryAuth)
+				return nil, fmt.Errorf("%s header not properly set in the request. Expected '%s', got %s", registry.AuthHeader, expectedRegistryAuth, registryAuth)
 			}
 
 			query := r.URL.Query()

+ 4 - 3
client/image_pull_test.go

@@ -10,6 +10,7 @@ import (
 	"testing"
 
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 )
 
@@ -81,9 +82,9 @@ func TestImagePullWithPrivilegedFuncNoError(t *testing.T) {
 	client := &Client{
 		client: newMockClient(func(req *http.Request) (*http.Response, error) {
 			if !strings.HasPrefix(req.URL.Path, expectedURL) {
-				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
+				return nil, fmt.Errorf("expected URL '%s', got '%s'", expectedURL, req.URL)
 			}
-			auth := req.Header.Get("X-Registry-Auth")
+			auth := req.Header.Get(registry.AuthHeader)
 			if auth == "NotValid" {
 				return &http.Response{
 					StatusCode: http.StatusUnauthorized,
@@ -91,7 +92,7 @@ func TestImagePullWithPrivilegedFuncNoError(t *testing.T) {
 				}, nil
 			}
 			if auth != "IAmValid" {
-				return nil, fmt.Errorf("Invalid auth header : expected %s, got %s", "IAmValid", auth)
+				return nil, fmt.Errorf("invalid auth header: expected %s, got %s", "IAmValid", auth)
 			}
 			query := req.URL.Query()
 			fromImage := query.Get("fromImage")

+ 2 - 1
client/image_push.go

@@ -8,6 +8,7 @@ import (
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 )
 
@@ -49,6 +50,6 @@ func (cli *Client) ImagePush(ctx context.Context, image string, options types.Im
 }
 
 func (cli *Client) tryImagePush(ctx context.Context, imageID string, query url.Values, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
+	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
 	return cli.post(ctx, "/images/"+imageID+"/push", query, nil, headers)
 }

+ 3 - 2
client/image_push_test.go

@@ -10,6 +10,7 @@ import (
 	"testing"
 
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 )
 
@@ -88,7 +89,7 @@ func TestImagePushWithPrivilegedFuncNoError(t *testing.T) {
 			if !strings.HasPrefix(req.URL.Path, expectedURL) {
 				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
 			}
-			auth := req.Header.Get("X-Registry-Auth")
+			auth := req.Header.Get(registry.AuthHeader)
 			if auth == "NotValid" {
 				return &http.Response{
 					StatusCode: http.StatusUnauthorized,
@@ -96,7 +97,7 @@ func TestImagePushWithPrivilegedFuncNoError(t *testing.T) {
 				}, nil
 			}
 			if auth != "IAmValid" {
-				return nil, fmt.Errorf("Invalid auth header : expected %s, got %s", "IAmValid", auth)
+				return nil, fmt.Errorf("invalid auth header: expected %s, got %s", "IAmValid", auth)
 			}
 			query := req.URL.Query()
 			tag := query.Get("tag")

+ 1 - 1
client/image_search.go

@@ -48,6 +48,6 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I
 }
 
 func (cli *Client) tryImageSearch(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
+	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
 	return cli.get(ctx, "/images/search", query, headers)
 }

+ 2 - 2
client/image_search_test.go

@@ -73,7 +73,7 @@ func TestImageSearchWithPrivilegedFuncNoError(t *testing.T) {
 			if !strings.HasPrefix(req.URL.Path, expectedURL) {
 				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
 			}
-			auth := req.Header.Get("X-Registry-Auth")
+			auth := req.Header.Get(registry.AuthHeader)
 			if auth == "NotValid" {
 				return &http.Response{
 					StatusCode: http.StatusUnauthorized,
@@ -81,7 +81,7 @@ func TestImageSearchWithPrivilegedFuncNoError(t *testing.T) {
 				}, nil
 			}
 			if auth != "IAmValid" {
-				return nil, fmt.Errorf("Invalid auth header : expected 'IAmValid', got %s", auth)
+				return nil, fmt.Errorf("invalid auth header: expected 'IAmValid', got %s", auth)
 			}
 			query := req.URL.Query()
 			term := query.Get("term")

+ 1 - 1
client/interface.go

@@ -166,7 +166,7 @@ type SwarmAPIClient interface {
 type SystemAPIClient interface {
 	Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error)
 	Info(ctx context.Context) (types.Info, error)
-	RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error)
+	RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error)
 	DiskUsage(ctx context.Context, options types.DiskUsageOptions) (types.DiskUsage, error)
 	Ping(ctx context.Context) (types.Ping, error)
 }

+ 1 - 2
client/login.go

@@ -5,13 +5,12 @@ import (
 	"encoding/json"
 	"net/url"
 
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/registry"
 )
 
 // RegistryLogin authenticates the docker server with a given docker registry.
 // It returns unauthorizedError when the authentication fails.
-func (cli *Client) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error) {
+func (cli *Client) RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error) {
 	resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil)
 	defer ensureReaderClosed(resp)
 

+ 3 - 2
client/plugin_install.go

@@ -8,6 +8,7 @@ import (
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 	"github.com/pkg/errors"
 )
@@ -67,12 +68,12 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
 }
 
 func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
+	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
 	return cli.get(ctx, "/plugins/privileges", query, headers)
 }
 
 func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges types.PluginPrivileges, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
+	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
 	return cli.post(ctx, "/plugins/pull", query, privileges, headers)
 }
 

+ 3 - 1
client/plugin_push.go

@@ -3,11 +3,13 @@ package client // import "github.com/docker/docker/client"
 import (
 	"context"
 	"io"
+
+	"github.com/docker/docker/api/types/registry"
 )
 
 // PluginPush pushes a plugin to a registry
 func (cli *Client) PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error) {
-	headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
+	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
 	resp, err := cli.post(ctx, "/plugins/"+name+"/push", nil, nil, headers)
 	if err != nil {
 		return nil, err

+ 3 - 2
client/plugin_push_test.go

@@ -9,6 +9,7 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 )
 
@@ -34,9 +35,9 @@ func TestPluginPush(t *testing.T) {
 			if req.Method != http.MethodPost {
 				return nil, fmt.Errorf("expected POST method, got %s", req.Method)
 			}
-			auth := req.Header.Get("X-Registry-Auth")
+			auth := req.Header.Get(registry.AuthHeader)
 			if auth != "authtoken" {
-				return nil, fmt.Errorf("Invalid auth header : expected 'authtoken', got %s", auth)
+				return nil, fmt.Errorf("invalid auth header: expected 'authtoken', got %s", auth)
 			}
 			return &http.Response{
 				StatusCode: http.StatusOK,

+ 2 - 1
client/plugin_upgrade.go

@@ -7,6 +7,7 @@ import (
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/pkg/errors"
 )
 
@@ -34,6 +35,6 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options types
 }
 
 func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges types.PluginPrivileges, name, registryAuth string) (serverResponse, error) {
-	headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
+	headers := map[string][]string{registry.AuthHeader: {registryAuth}}
 	return cli.post(ctx, "/plugins/"+name+"/upgrade", query, privileges, headers)
 }

+ 2 - 1
client/service_create.go

@@ -8,6 +8,7 @@ import (
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/api/types/swarm"
 	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
@@ -21,7 +22,7 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
 	}
 
 	if options.EncodedRegistryAuth != "" {
-		headers["X-Registry-Auth"] = []string{options.EncodedRegistryAuth}
+		headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth}
 	}
 
 	// Make sure containerSpec is not nil when no runtime is set or the runtime is set to container

+ 2 - 1
client/service_update.go

@@ -6,6 +6,7 @@ import (
 	"net/url"
 
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/api/types/swarm"
 )
 
@@ -23,7 +24,7 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
 	}
 
 	if options.EncodedRegistryAuth != "" {
-		headers["X-Registry-Auth"] = []string{options.EncodedRegistryAuth}
+		headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth}
 	}
 
 	if options.RegistryAuthFrom != "" {

+ 2 - 2
daemon/auth.go

@@ -3,11 +3,11 @@ package daemon // import "github.com/docker/docker/daemon"
 import (
 	"context"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/dockerversion"
 )
 
 // AuthenticateToRegistry checks the validity of credentials in authConfig
-func (daemon *Daemon) AuthenticateToRegistry(ctx context.Context, authConfig *types.AuthConfig) (string, string, error) {
+func (daemon *Daemon) AuthenticateToRegistry(ctx context.Context, authConfig *registry.AuthConfig) (string, string, error) {
 	return daemon.registryService.Auth(ctx, authConfig, dockerversion.DockerUserAgent(ctx))
 }

+ 15 - 14
daemon/cluster/controllers/plugin/controller.go

@@ -6,7 +6,8 @@ import (
 	"net/http"
 
 	"github.com/docker/distribution/reference"
-	enginetypes "github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/api/types/swarm/runtime"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/plugin"
@@ -41,11 +42,11 @@ type Controller struct {
 // Backend is the interface for interacting with the plugin manager
 // Controller actions are passed to the configured backend to do the real work.
 type Backend interface {
-	Disable(name string, config *enginetypes.PluginDisableConfig) error
-	Enable(name string, config *enginetypes.PluginEnableConfig) error
-	Remove(name string, config *enginetypes.PluginRmConfig) error
-	Pull(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges, outStream io.Writer, opts ...plugin.CreateOpt) error
-	Upgrade(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges, outStream io.Writer) error
+	Disable(name string, config *types.PluginDisableConfig) error
+	Enable(name string, config *types.PluginEnableConfig) error
+	Remove(name string, config *types.PluginRmConfig) error
+	Pull(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer, opts ...plugin.CreateOpt) error
+	Upgrade(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer) error
 	Get(name string) (*v2.Plugin, error)
 	SubscribeEvents(buffer int, events ...plugin.Event) (eventCh <-chan interface{}, cancel func())
 }
@@ -96,7 +97,7 @@ func (p *Controller) Prepare(ctx context.Context) (err error) {
 		p.spec.Name = remote.String()
 	}
 
-	var authConfig enginetypes.AuthConfig
+	var authConfig registry.AuthConfig
 	privs := convertPrivileges(p.spec.Privileges)
 
 	pl, err := p.backend.Get(p.spec.Name)
@@ -112,7 +113,7 @@ func (p *Controller) Prepare(ctx context.Context) (err error) {
 			return errors.Errorf("plugin already exists: %s", p.spec.Name)
 		}
 		if pl.IsEnabled() {
-			if err := p.backend.Disable(pl.GetID(), &enginetypes.PluginDisableConfig{ForceDisable: true}); err != nil {
+			if err := p.backend.Disable(pl.GetID(), &types.PluginDisableConfig{ForceDisable: true}); err != nil {
 				p.logger.WithError(err).Debug("could not disable plugin before running upgrade")
 			}
 		}
@@ -143,12 +144,12 @@ func (p *Controller) Start(ctx context.Context) error {
 
 	if p.spec.Disabled {
 		if pl.IsEnabled() {
-			return p.backend.Disable(p.pluginID, &enginetypes.PluginDisableConfig{ForceDisable: false})
+			return p.backend.Disable(p.pluginID, &types.PluginDisableConfig{ForceDisable: false})
 		}
 		return nil
 	}
 	if !pl.IsEnabled() {
-		return p.backend.Enable(p.pluginID, &enginetypes.PluginEnableConfig{Timeout: 30})
+		return p.backend.Enable(p.pluginID, &types.PluginEnableConfig{Timeout: 30})
 	}
 	return nil
 }
@@ -232,7 +233,7 @@ func (p *Controller) Remove(ctx context.Context) error {
 
 	// This may error because we have exactly 1 plugin, but potentially multiple
 	// tasks which are calling remove.
-	err = p.backend.Remove(p.pluginID, &enginetypes.PluginRmConfig{ForceRemove: true})
+	err = p.backend.Remove(p.pluginID, &types.PluginRmConfig{ForceRemove: true})
 	if isNotFound(err) {
 		return nil
 	}
@@ -245,10 +246,10 @@ func (p *Controller) Close() error {
 	return nil
 }
 
-func convertPrivileges(ls []*runtime.PluginPrivilege) enginetypes.PluginPrivileges {
-	var out enginetypes.PluginPrivileges
+func convertPrivileges(ls []*runtime.PluginPrivilege) types.PluginPrivileges {
+	var out types.PluginPrivileges
 	for _, p := range ls {
-		pp := enginetypes.PluginPrivilege{
+		pp := types.PluginPrivilege{
 			Name:        p.Name,
 			Description: p.Description,
 			Value:       p.Value,

+ 8 - 7
daemon/cluster/controllers/plugin/controller_test.go

@@ -10,7 +10,8 @@ import (
 	"time"
 
 	"github.com/docker/distribution/reference"
-	enginetypes "github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/api/types/swarm/runtime"
 	"github.com/docker/docker/pkg/pubsub"
 	"github.com/docker/docker/plugin"
@@ -341,27 +342,27 @@ type mockBackend struct {
 	pub *pubsub.Publisher
 }
 
-func (m *mockBackend) Disable(name string, config *enginetypes.PluginDisableConfig) error {
+func (m *mockBackend) Disable(name string, config *types.PluginDisableConfig) error {
 	m.p.PluginObj.Enabled = false
 	m.pub.Publish(plugin.EventDisable{})
 	return nil
 }
 
-func (m *mockBackend) Enable(name string, config *enginetypes.PluginEnableConfig) error {
+func (m *mockBackend) Enable(name string, config *types.PluginEnableConfig) error {
 	m.p.PluginObj.Enabled = true
 	m.pub.Publish(plugin.EventEnable{})
 	return nil
 }
 
-func (m *mockBackend) Remove(name string, config *enginetypes.PluginRmConfig) error {
+func (m *mockBackend) Remove(name string, config *types.PluginRmConfig) error {
 	m.p = nil
 	m.pub.Publish(plugin.EventRemove{})
 	return nil
 }
 
-func (m *mockBackend) Pull(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges, outStream io.Writer, opts ...plugin.CreateOpt) error {
+func (m *mockBackend) Pull(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer, opts ...plugin.CreateOpt) error {
 	m.p = &v2.Plugin{
-		PluginObj: enginetypes.Plugin{
+		PluginObj: types.Plugin{
 			ID:              "1234",
 			Name:            name,
 			PluginReference: ref.String(),
@@ -370,7 +371,7 @@ func (m *mockBackend) Pull(ctx context.Context, ref reference.Named, name string
 	return nil
 }
 
-func (m *mockBackend) Upgrade(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges, outStream io.Writer) error {
+func (m *mockBackend) Upgrade(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer) error {
 	m.p.PluginObj.PluginReference = pluginTestRemoteUpgrade
 	return nil
 }

+ 6 - 5
daemon/cluster/executor/backend.go

@@ -13,7 +13,8 @@ import (
 	"github.com/docker/docker/api/types/events"
 	"github.com/docker/docker/api/types/filters"
 	"github.com/docker/docker/api/types/network"
-	swarmtypes "github.com/docker/docker/api/types/swarm"
+	"github.com/docker/docker/api/types/registry"
+	"github.com/docker/docker/api/types/swarm"
 	"github.com/docker/docker/api/types/volume"
 	containerpkg "github.com/docker/docker/container"
 	clustertypes "github.com/docker/docker/daemon/cluster/provider"
@@ -48,8 +49,8 @@ type Backend interface {
 	ContainerRm(name string, config *types.ContainerRmConfig) error
 	ContainerKill(name string, sig string) error
 	SetContainerDependencyStore(name string, store exec.DependencyGetter) error
-	SetContainerSecretReferences(name string, refs []*swarmtypes.SecretReference) error
-	SetContainerConfigReferences(name string, refs []*swarmtypes.ConfigReference) error
+	SetContainerSecretReferences(name string, refs []*swarm.SecretReference) error
+	SetContainerConfigReferences(name string, refs []*swarm.ConfigReference) error
 	SystemInfo() *types.Info
 	Containers(config *types.ContainerListOptions) ([]*types.Container, error)
 	SetNetworkBootstrapKeys([]*networktypes.EncryptionKey) error
@@ -73,7 +74,7 @@ type VolumeBackend interface {
 
 // ImageBackend is used by an executor to perform image operations
 type ImageBackend interface {
-	PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
-	GetRepository(context.Context, reference.Named, *types.AuthConfig) (distribution.Repository, error)
+	PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
+	GetRepository(context.Context, reference.Named, *registry.AuthConfig) (distribution.Repository, error)
 	GetImage(refOrID string, platform *specs.Platform) (retImg *image.Image, retErr error)
 }

+ 2 - 1
daemon/cluster/executor/container/adapter.go

@@ -16,6 +16,7 @@ import (
 	"github.com/docker/docker/api/types/backend"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/events"
+	"github.com/docker/docker/api/types/registry"
 	containerpkg "github.com/docker/docker/container"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/daemon/cluster/convert"
@@ -87,7 +88,7 @@ func (c *containerAdapter) pullImage(ctx context.Context) error {
 		encodedAuthConfig = spec.PullOptions.RegistryAuth
 	}
 
-	authConfig := &types.AuthConfig{}
+	authConfig := &registry.AuthConfig{}
 	if encodedAuthConfig != "" {
 		if err := json.NewDecoder(base64.NewDecoder(base64.URLEncoding, strings.NewReader(encodedAuthConfig))).Decode(authConfig); err != nil {
 			logrus.Warnf("invalid authconfig: %v", err)

+ 28 - 27
daemon/cluster/services.go

@@ -12,9 +12,10 @@ import (
 	"time"
 
 	"github.com/docker/distribution/reference"
-	apitypes "github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
-	types "github.com/docker/docker/api/types/swarm"
+	"github.com/docker/docker/api/types/registry"
+	"github.com/docker/docker/api/types/swarm"
 	timetypes "github.com/docker/docker/api/types/time"
 	"github.com/docker/docker/daemon/cluster/convert"
 	"github.com/docker/docker/errdefs"
@@ -27,7 +28,7 @@ import (
 )
 
 // GetServices returns all services of a managed swarm cluster.
-func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Service, error) {
+func (c *Cluster) GetServices(options types.ServiceListOptions) ([]swarm.Service, error) {
 	c.mu.RLock()
 	defer c.mu.RUnlock()
 
@@ -53,7 +54,7 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
 
 	if len(options.Filters.Get("runtime")) == 0 {
 		// Default to using the container runtime filter
-		options.Filters.Add("runtime", string(types.RuntimeContainer))
+		options.Filters.Add("runtime", string(swarm.RuntimeContainer))
 	}
 
 	filters := &swarmapi.ListServicesRequest_Filters{
@@ -75,7 +76,7 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
 		return nil, err
 	}
 
-	services := make([]types.Service, 0, len(r.Services))
+	services := make([]swarm.Service, 0, len(r.Services))
 
 	// if the  user requests the service statuses, we'll store the IDs needed
 	// in this slice
@@ -132,9 +133,9 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
 		// result would be quadratic. instead, make a mapping of service IDs to
 		// service statuses so that this is roughly linear. additionally,
 		// convert the status response to an engine api service status here.
-		serviceMap := map[string]*types.ServiceStatus{}
+		serviceMap := map[string]*swarm.ServiceStatus{}
 		for _, status := range resp.Statuses {
-			serviceMap[status.ServiceID] = &types.ServiceStatus{
+			serviceMap[status.ServiceID] = &swarm.ServiceStatus{
 				RunningTasks:   status.RunningTasks,
 				DesiredTasks:   status.DesiredTasks,
 				CompletedTasks: status.CompletedTasks,
@@ -159,7 +160,7 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
 }
 
 // GetService returns a service based on an ID or name.
-func (c *Cluster) GetService(input string, insertDefaults bool) (types.Service, error) {
+func (c *Cluster) GetService(input string, insertDefaults bool) (swarm.Service, error) {
 	var service *swarmapi.Service
 	if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
 		s, err := getService(ctx, state.controlClient, input, insertDefaults)
@@ -169,18 +170,18 @@ func (c *Cluster) GetService(input string, insertDefaults bool) (types.Service,
 		service = s
 		return nil
 	}); err != nil {
-		return types.Service{}, err
+		return swarm.Service{}, err
 	}
 	svc, err := convert.ServiceFromGRPC(*service)
 	if err != nil {
-		return types.Service{}, err
+		return swarm.Service{}, err
 	}
 	return svc, nil
 }
 
 // CreateService creates a new service in a managed swarm cluster.
-func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string, queryRegistry bool) (*apitypes.ServiceCreateResponse, error) {
-	var resp *apitypes.ServiceCreateResponse
+func (c *Cluster) CreateService(s swarm.ServiceSpec, encodedAuth string, queryRegistry bool) (*types.ServiceCreateResponse, error) {
+	var resp *types.ServiceCreateResponse
 	err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
 		err := c.populateNetworkID(ctx, state.controlClient, &s)
 		if err != nil {
@@ -192,17 +193,17 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string, queryRe
 			return errdefs.InvalidParameter(err)
 		}
 
-		resp = &apitypes.ServiceCreateResponse{}
+		resp = &types.ServiceCreateResponse{}
 
 		switch serviceSpec.Task.Runtime.(type) {
 		case *swarmapi.TaskSpec_Attachment:
-			return fmt.Errorf("invalid task spec: spec type %q not supported", types.RuntimeNetworkAttachment)
+			return fmt.Errorf("invalid task spec: spec type %q not supported", swarm.RuntimeNetworkAttachment)
 		// handle other runtimes here
 		case *swarmapi.TaskSpec_Generic:
 			switch serviceSpec.Task.GetGeneric().Kind {
-			case string(types.RuntimePlugin):
+			case string(swarm.RuntimePlugin):
 				if !c.config.Backend.HasExperimental() {
-					return fmt.Errorf("runtime type %q only supported in experimental", types.RuntimePlugin)
+					return fmt.Errorf("runtime type %q only supported in experimental", swarm.RuntimePlugin)
 				}
 				if s.TaskTemplate.PluginSpec == nil {
 					return errors.New("plugin spec must be set")
@@ -228,7 +229,7 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string, queryRe
 			}
 
 			// retrieve auth config from encoded auth
-			authConfig := &apitypes.AuthConfig{}
+			authConfig := &registry.AuthConfig{}
 			if encodedAuth != "" {
 				authReader := strings.NewReader(encodedAuth)
 				dec := json.NewDecoder(base64.NewDecoder(base64.URLEncoding, authReader))
@@ -282,8 +283,8 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string, queryRe
 }
 
 // UpdateService updates existing service to match new properties.
-func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec types.ServiceSpec, flags apitypes.ServiceUpdateOptions, queryRegistry bool) (*apitypes.ServiceUpdateResponse, error) {
-	var resp *apitypes.ServiceUpdateResponse
+func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec swarm.ServiceSpec, flags types.ServiceUpdateOptions, queryRegistry bool) (*types.ServiceUpdateResponse, error) {
+	var resp *types.ServiceUpdateResponse
 
 	err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
 
@@ -302,14 +303,14 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ
 			return err
 		}
 
-		resp = &apitypes.ServiceUpdateResponse{}
+		resp = &types.ServiceUpdateResponse{}
 
 		switch serviceSpec.Task.Runtime.(type) {
 		case *swarmapi.TaskSpec_Attachment:
-			return fmt.Errorf("invalid task spec: spec type %q not supported", types.RuntimeNetworkAttachment)
+			return fmt.Errorf("invalid task spec: spec type %q not supported", swarm.RuntimeNetworkAttachment)
 		case *swarmapi.TaskSpec_Generic:
 			switch serviceSpec.Task.GetGeneric().Kind {
-			case string(types.RuntimePlugin):
+			case string(swarm.RuntimePlugin):
 				if spec.TaskTemplate.PluginSpec == nil {
 					return errors.New("plugin spec must be set")
 				}
@@ -328,9 +329,9 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ
 				// shouldn't lose it, and continue to use the one that was already present
 				var ctnr *swarmapi.ContainerSpec
 				switch flags.RegistryAuthFrom {
-				case apitypes.RegistryAuthFromSpec, "":
+				case types.RegistryAuthFromSpec, "":
 					ctnr = currentService.Spec.Task.GetContainer()
-				case apitypes.RegistryAuthFromPreviousSpec:
+				case types.RegistryAuthFromPreviousSpec:
 					if currentService.PreviousSpec == nil {
 						return errors.New("service does not have a previous spec")
 					}
@@ -349,7 +350,7 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ
 			}
 
 			// retrieve auth config from encoded auth
-			authConfig := &apitypes.AuthConfig{}
+			authConfig := &registry.AuthConfig{}
 			if encodedAuth != "" {
 				if err := json.NewDecoder(base64.NewDecoder(base64.URLEncoding, strings.NewReader(encodedAuth))).Decode(authConfig); err != nil {
 					logrus.Warnf("invalid authconfig: %v", err)
@@ -425,7 +426,7 @@ func (c *Cluster) RemoveService(input string) error {
 }
 
 // ServiceLogs collects service logs and writes them back to `config.OutStream`
-func (c *Cluster) ServiceLogs(ctx context.Context, selector *backend.LogSelector, config *apitypes.ContainerLogsOptions) (<-chan *backend.LogMessage, error) {
+func (c *Cluster) ServiceLogs(ctx context.Context, selector *backend.LogSelector, config *types.ContainerLogsOptions) (<-chan *backend.LogMessage, error) {
 	c.mu.RLock()
 	defer c.mu.RUnlock()
 
@@ -612,7 +613,7 @@ func convertSelector(ctx context.Context, cc swarmapi.ControlClient, selector *b
 
 // imageWithDigestString takes an image such as name or name:tag
 // and returns the image pinned to a digest, such as name@sha256:34234
-func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authConfig *apitypes.AuthConfig) (string, error) {
+func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authConfig *registry.AuthConfig) (string, error) {
 	ref, err := reference.ParseAnyReference(image)
 	if err != nil {
 		return "", err

+ 3 - 3
daemon/containerd/image_pull.go

@@ -8,7 +8,7 @@ import (
 	"github.com/containerd/containerd/platforms"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/reference"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 	"github.com/opencontainers/go-digest"
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
@@ -16,7 +16,7 @@ import (
 
 // PullImage initiates a pull operation. image is the repository name to pull, and
 // tagOrDigest may be either empty, or indicate a specific tag or digest to pull.
-func (i *ImageService) PullImage(ctx context.Context, image, tagOrDigest string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
+func (i *ImageService) PullImage(ctx context.Context, image, tagOrDigest string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
 	var opts []containerd.RemoteOpt
 	if platform != nil {
 		opts = append(opts, containerd.WithPlatform(platforms.Format(*platform)))
@@ -46,6 +46,6 @@ func (i *ImageService) PullImage(ctx context.Context, image, tagOrDigest string,
 }
 
 // GetRepository returns a repository from the registry.
-func (i *ImageService) GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (distribution.Repository, error) {
+func (i *ImageService) GetRepository(ctx context.Context, ref reference.Named, authConfig *registry.AuthConfig) (distribution.Repository, error) {
 	panic("not implemented")
 }

+ 2 - 2
daemon/containerd/image_push.go

@@ -4,10 +4,10 @@ import (
 	"context"
 	"io"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 )
 
 // PushImage initiates a push operation on the repository named localName.
-func (i *ImageService) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
+func (i *ImageService) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
 	panic("not implemented")
 }

+ 2 - 3
daemon/containerd/image_search.go

@@ -3,9 +3,8 @@ package containerd
 import (
 	"context"
 
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
-	registrytypes "github.com/docker/docker/api/types/registry"
+	"github.com/docker/docker/api/types/registry"
 )
 
 // SearchRegistryForImages queries the registry for images matching
@@ -13,6 +12,6 @@ import (
 //
 // TODO: this could be implemented in a registry service instead of the image
 // service.
-func (i *ImageService) SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registrytypes.SearchResults, error) {
+func (i *ImageService) SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *registry.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error) {
 	panic("not implemented")
 }

+ 4 - 4
daemon/image_service.go

@@ -25,8 +25,8 @@ import (
 type ImageService interface {
 	// Images
 
-	PullImage(ctx context.Context, image, tag string, platform *v1.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
-	PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
+	PullImage(ctx context.Context, image, tag string, platform *v1.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
+	PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
 	CreateImage(config []byte, parent string) (builder.Image, error)
 	ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
 	ExportImage(names []string, outStream io.Writer) error
@@ -67,8 +67,8 @@ type ImageService interface {
 
 	// Other
 
-	GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (distribution.Repository, error)
-	SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *types.AuthConfig, headers map[string][]string) (*registry.SearchResults, error)
+	GetRepository(ctx context.Context, ref reference.Named, authConfig *registry.AuthConfig) (distribution.Repository, error)
+	SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *registry.AuthConfig, headers map[string][]string) (*registry.SearchResults, error)
 	DistributionServices() images.DistributionServices
 	Children(id image.ID) []image.ID
 	Cleanup() error

+ 5 - 5
daemon/images/image_builder.go

@@ -7,8 +7,8 @@ import (
 
 	"github.com/containerd/containerd/platforms"
 	"github.com/docker/distribution/reference"
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/image"
@@ -18,7 +18,7 @@ import (
 	"github.com/docker/docker/pkg/streamformatter"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/system"
-	"github.com/docker/docker/registry"
+	registrypkg "github.com/docker/docker/registry"
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
@@ -144,14 +144,14 @@ func newROLayerForImage(img *image.Image, layerStore layer.Store) (builder.ROLay
 }
 
 // TODO: could this use the regular daemon PullImage ?
-func (i *ImageService) pullForBuilder(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer, platform *specs.Platform) (*image.Image, error) {
+func (i *ImageService) pullForBuilder(ctx context.Context, name string, authConfigs map[string]registry.AuthConfig, output io.Writer, platform *specs.Platform) (*image.Image, error) {
 	ref, err := reference.ParseNormalizedNamed(name)
 	if err != nil {
 		return nil, err
 	}
 	ref = reference.TagNameOnly(ref)
 
-	pullRegistryAuth := &types.AuthConfig{}
+	pullRegistryAuth := &registry.AuthConfig{}
 	if len(authConfigs) > 0 {
 		// The request came with a full auth config, use it
 		repoInfo, err := i.registryService.ResolveRepository(ref)
@@ -159,7 +159,7 @@ func (i *ImageService) pullForBuilder(ctx context.Context, name string, authConf
 			return nil, err
 		}
 
-		resolvedConfig := registry.ResolveAuthConfig(authConfigs, repoInfo.Index)
+		resolvedConfig := registrypkg.ResolveAuthConfig(authConfigs, repoInfo.Index)
 		pullRegistryAuth = &resolvedConfig
 	}
 

+ 4 - 4
daemon/images/image_pull.go

@@ -10,7 +10,7 @@ import (
 	"github.com/containerd/containerd/namespaces"
 	dist "github.com/docker/distribution"
 	"github.com/docker/distribution/reference"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/distribution"
 	progressutils "github.com/docker/docker/distribution/utils"
 	"github.com/docker/docker/errdefs"
@@ -24,7 +24,7 @@ import (
 
 // PullImage initiates a pull operation. image is the repository name to pull, and
 // tag may be either empty, or indicate a specific tag to pull.
-func (i *ImageService) PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
+func (i *ImageService) PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
 	start := time.Now()
 	// Special case: "pull -a" may send an image name with a
 	// trailing :. This is ugly, but let's not break API
@@ -77,7 +77,7 @@ func (i *ImageService) PullImage(ctx context.Context, image, tag string, platfor
 	return nil
 }
 
-func (i *ImageService) pullImageWithReference(ctx context.Context, ref reference.Named, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
+func (i *ImageService) pullImageWithReference(ctx context.Context, ref reference.Named, platform *specs.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
 	// Include a buffer so that slow client connections don't affect
 	// transfer performance.
 	progressChan := make(chan progress.Progress, 100)
@@ -132,7 +132,7 @@ func (i *ImageService) pullImageWithReference(ctx context.Context, ref reference
 }
 
 // GetRepository returns a repository from the registry.
-func (i *ImageService) GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (dist.Repository, error) {
+func (i *ImageService) GetRepository(ctx context.Context, ref reference.Named, authConfig *registry.AuthConfig) (dist.Repository, error) {
 	return distribution.GetRepository(ctx, ref, &distribution.ImagePullConfig{
 		Config: distribution.Config{
 			AuthConfig:      authConfig,

+ 2 - 2
daemon/images/image_push.go

@@ -7,14 +7,14 @@ import (
 
 	"github.com/docker/distribution/manifest/schema2"
 	"github.com/docker/distribution/reference"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/distribution"
 	progressutils "github.com/docker/docker/distribution/utils"
 	"github.com/docker/docker/pkg/progress"
 )
 
 // PushImage initiates a push operation on the repository named localName.
-func (i *ImageService) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
+func (i *ImageService) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
 	start := time.Now()
 	ref, err := reference.ParseNormalizedNamed(image)
 	if err != nil {

+ 5 - 6
daemon/images/image_search.go

@@ -4,9 +4,8 @@ import (
 	"context"
 	"strconv"
 
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
-	registrytypes "github.com/docker/docker/api/types/registry"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/dockerversion"
 )
 
@@ -22,8 +21,8 @@ var acceptedSearchFilterTags = map[string]bool{
 // TODO: this could be implemented in a registry service instead of the image
 // service.
 func (i *ImageService) SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int,
-	authConfig *types.AuthConfig,
-	headers map[string][]string) (*registrytypes.SearchResults, error) {
+	authConfig *registry.AuthConfig,
+	headers map[string][]string) (*registry.SearchResults, error) {
 
 	if err := searchFilters.Validate(acceptedSearchFilterTags); err != nil {
 		return nil, err
@@ -63,7 +62,7 @@ func (i *ImageService) SearchRegistryForImages(ctx context.Context, searchFilter
 		return nil, err
 	}
 
-	filteredResults := []registrytypes.SearchResult{}
+	filteredResults := []registry.SearchResult{}
 	for _, result := range unfilteredResult.Results {
 		if searchFilters.Contains("is-automated") {
 			if isAutomated != result.IsAutomated {
@@ -83,7 +82,7 @@ func (i *ImageService) SearchRegistryForImages(ctx context.Context, searchFilter
 		filteredResults = append(filteredResults, result)
 	}
 
-	return &registrytypes.SearchResults{
+	return &registry.SearchResults{
 		Query:      unfilteredResult.Query,
 		NumResults: len(filteredResults),
 		Results:    filteredResults,

+ 36 - 37
daemon/images/image_search_test.go

@@ -5,27 +5,26 @@ import (
 	"errors"
 	"testing"
 
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
-	registrytypes "github.com/docker/docker/api/types/registry"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
-	"github.com/docker/docker/registry"
+	registrypkg "github.com/docker/docker/registry"
 	"gotest.tools/v3/assert"
 )
 
 type fakeService struct {
-	registry.Service
+	registrypkg.Service
 	shouldReturnError bool
 
 	term    string
-	results []registrytypes.SearchResult
+	results []registry.SearchResult
 }
 
-func (s *fakeService) Search(ctx context.Context, term string, limit int, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error) {
+func (s *fakeService) Search(ctx context.Context, term string, limit int, authConfig *registry.AuthConfig, userAgent string, headers map[string][]string) (*registry.SearchResults, error) {
 	if s.shouldReturnError {
 		return nil, errdefs.Unknown(errors.New("search unknown error"))
 	}
-	return &registrytypes.SearchResults{
+	return &registry.SearchResults{
 		Query:      s.term,
 		NumResults: len(s.results),
 		Results:    s.results,
@@ -104,23 +103,23 @@ func TestSearchRegistryForImages(t *testing.T) {
 	successCases := []struct {
 		name            string
 		filtersArgs     filters.Args
-		registryResults []registrytypes.SearchResult
-		expectedResults []registrytypes.SearchResult
+		registryResults []registry.SearchResult
+		expectedResults []registry.SearchResult
 	}{
 		{
 			name:            "empty results",
-			registryResults: []registrytypes.SearchResult{},
-			expectedResults: []registrytypes.SearchResult{},
+			registryResults: []registry.SearchResult{},
+			expectedResults: []registry.SearchResult{},
 		},
 		{
 			name: "no filter",
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{
+			expectedResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
@@ -130,25 +129,25 @@ func TestSearchRegistryForImages(t *testing.T) {
 		{
 			name:        "is-automated=true, no results",
 			filtersArgs: filters.NewArgs(filters.Arg("is-automated", "true")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{},
+			expectedResults: []registry.SearchResult{},
 		},
 		{
 			name:        "is-automated=true",
 			filtersArgs: filters.NewArgs(filters.Arg("is-automated", "true")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 					IsAutomated: true,
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{
+			expectedResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
@@ -159,26 +158,26 @@ func TestSearchRegistryForImages(t *testing.T) {
 		{
 			name:        "is-automated=false, no results",
 			filtersArgs: filters.NewArgs(filters.Arg("is-automated", "false")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 					IsAutomated: true,
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{},
+			expectedResults: []registry.SearchResult{},
 		},
 		{
 			name:        "is-automated=false",
 			filtersArgs: filters.NewArgs(filters.Arg("is-automated", "false")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 					IsAutomated: false,
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{
+			expectedResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
@@ -189,25 +188,25 @@ func TestSearchRegistryForImages(t *testing.T) {
 		{
 			name:        "is-official=true, no results",
 			filtersArgs: filters.NewArgs(filters.Arg("is-official", "true")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{},
+			expectedResults: []registry.SearchResult{},
 		},
 		{
 			name:        "is-official=true",
 			filtersArgs: filters.NewArgs(filters.Arg("is-official", "true")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 					IsOfficial:  true,
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{
+			expectedResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
@@ -218,26 +217,26 @@ func TestSearchRegistryForImages(t *testing.T) {
 		{
 			name:        "is-official=false, no results",
 			filtersArgs: filters.NewArgs(filters.Arg("is-official", "false")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 					IsOfficial:  true,
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{},
+			expectedResults: []registry.SearchResult{},
 		},
 		{
 			name:        "is-official=false",
 			filtersArgs: filters.NewArgs(filters.Arg("is-official", "false")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 					IsOfficial:  false,
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{
+			expectedResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
@@ -248,14 +247,14 @@ func TestSearchRegistryForImages(t *testing.T) {
 		{
 			name:        "stars=0",
 			filtersArgs: filters.NewArgs(filters.Arg("stars", "0")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 					StarCount:   0,
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{
+			expectedResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
@@ -266,19 +265,19 @@ func TestSearchRegistryForImages(t *testing.T) {
 		{
 			name:        "stars=0, no results",
 			filtersArgs: filters.NewArgs(filters.Arg("stars", "1")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name",
 					Description: "description",
 					StarCount:   0,
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{},
+			expectedResults: []registry.SearchResult{},
 		},
 		{
 			name:        "stars=1",
 			filtersArgs: filters.NewArgs(filters.Arg("stars", "1")),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name0",
 					Description: "description0",
@@ -290,7 +289,7 @@ func TestSearchRegistryForImages(t *testing.T) {
 					StarCount:   1,
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{
+			expectedResults: []registry.SearchResult{
 				{
 					Name:        "name1",
 					Description: "description1",
@@ -305,7 +304,7 @@ func TestSearchRegistryForImages(t *testing.T) {
 				filters.Arg("is-official", "true"),
 				filters.Arg("is-automated", "true"),
 			),
-			registryResults: []registrytypes.SearchResult{
+			registryResults: []registry.SearchResult{
 				{
 					Name:        "name0",
 					Description: "description0",
@@ -335,7 +334,7 @@ func TestSearchRegistryForImages(t *testing.T) {
 					IsAutomated: true,
 				},
 			},
-			expectedResults: []registrytypes.SearchResult{
+			expectedResults: []registry.SearchResult{
 				{
 					Name:        "name3",
 					Description: "description3",

+ 4 - 4
distribution/config.go

@@ -8,7 +8,7 @@ import (
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/manifest/schema2"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/distribution/metadata"
 	"github.com/docker/docker/distribution/xfer"
 	"github.com/docker/docker/image"
@@ -16,7 +16,7 @@ import (
 	"github.com/docker/docker/pkg/progress"
 	"github.com/docker/docker/pkg/system"
 	refstore "github.com/docker/docker/reference"
-	"github.com/docker/docker/registry"
+	registrypkg "github.com/docker/docker/registry"
 	"github.com/docker/libtrust"
 	"github.com/opencontainers/go-digest"
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
@@ -30,13 +30,13 @@ type Config struct {
 	MetaHeaders map[string][]string
 	// AuthConfig holds authentication credentials for authenticating with
 	// the registry.
-	AuthConfig *types.AuthConfig
+	AuthConfig *registry.AuthConfig
 	// ProgressOutput is the interface for showing the status of the pull
 	// operation.
 	ProgressOutput progress.Output
 	// RegistryService is the registry service to use for TLS configuration
 	// and endpoint lookup.
-	RegistryService registry.Service
+	RegistryService registrypkg.Service
 	// ImageEventLogger notifies events for a given image
 	ImageEventLogger func(id, name, action string)
 	// MetadataStore is the storage backend for distribution-specific

+ 2 - 2
distribution/metadata/v2_metadata_service.go

@@ -7,7 +7,7 @@ import (
 	"encoding/json"
 	"errors"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/layer"
 	"github.com/opencontainers/go-digest"
 )
@@ -69,7 +69,7 @@ func ComputeV2MetadataHMAC(key []byte, meta *V2Metadata) string {
 
 // ComputeV2MetadataHMACKey returns a key for the given "authConfig" that can be used to hash v2 metadata
 // entries.
-func ComputeV2MetadataHMACKey(authConfig *types.AuthConfig) ([]byte, error) {
+func ComputeV2MetadataHMACKey(authConfig *registry.AuthConfig) ([]byte, error) {
 	if authConfig == nil {
 		return nil, nil
 	}

+ 1 - 2
distribution/pull_v2_test.go

@@ -16,7 +16,6 @@ import (
 
 	"github.com/docker/distribution/manifest/schema1"
 	"github.com/docker/distribution/reference"
-	"github.com/docker/docker/api/types"
 	registrytypes "github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/registry"
@@ -351,7 +350,7 @@ func testNewPuller(t *testing.T, rawurl string) *puller {
 	imagePullConfig := &ImagePullConfig{
 		Config: Config{
 			MetaHeaders: http.Header{},
-			AuthConfig: &types.AuthConfig{
+			AuthConfig: &registrytypes.AuthConfig{
 				RegistryToken: secretRegistryToken,
 			},
 		},

+ 6 - 6
distribution/push_v2_test.go

@@ -11,12 +11,12 @@ import (
 	"github.com/docker/distribution/manifest/schema2"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/registry/api/errcode"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/distribution/metadata"
 	"github.com/docker/docker/layer"
 	"github.com/docker/docker/pkg/progress"
 	refstore "github.com/docker/docker/reference"
-	"github.com/docker/docker/registry"
+	registrypkg "github.com/docker/docker/registry"
 	"github.com/opencontainers/go-digest"
 )
 
@@ -515,7 +515,7 @@ func TestWhenEmptyAuthConfig(t *testing.T) {
 		},
 	} {
 		imagePushConfig := &ImagePushConfig{}
-		imagePushConfig.AuthConfig = &types.AuthConfig{
+		imagePushConfig.AuthConfig = &registry.AuthConfig{
 			Username:      authInfo.username,
 			Password:      authInfo.password,
 			RegistryToken: authInfo.registryToken,
@@ -524,15 +524,15 @@ func TestWhenEmptyAuthConfig(t *testing.T) {
 		repoInfo, _ := reference.ParseNormalizedNamed("xujihui1985/test.img")
 		pusher := &pusher{
 			config: imagePushConfig,
-			repoInfo: &registry.RepositoryInfo{
+			repoInfo: &registrypkg.RepositoryInfo{
 				Name: repoInfo,
 			},
-			endpoint: registry.APIEndpoint{
+			endpoint: registrypkg.APIEndpoint{
 				URL: &url.URL{
 					Scheme: "https",
 					Host:   "index.docker.io",
 				},
-				Version:      registry.APIVersion2,
+				Version:      registrypkg.APIVersion2,
 				TrimHostname: true,
 			},
 		}

+ 2 - 2
distribution/registry.go

@@ -13,7 +13,7 @@ import (
 	"github.com/docker/distribution/registry/client"
 	"github.com/docker/distribution/registry/client/auth"
 	"github.com/docker/distribution/registry/client/transport"
-	"github.com/docker/docker/api/types"
+	registrytypes "github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/registry"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -58,7 +58,7 @@ func init() {
 // remote API version.
 func newRepository(
 	ctx context.Context, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint,
-	metaHeaders http.Header, authConfig *types.AuthConfig, actions ...string,
+	metaHeaders http.Header, authConfig *registrytypes.AuthConfig, actions ...string,
 ) (repo distribution.Repository, err error) {
 	repoName := repoInfo.Name.Name()
 	// If endpoint does not support CanonicalName, use the RemoteName instead

+ 6 - 7
distribution/registry_unit_test.go

@@ -9,9 +9,8 @@ import (
 	"testing"
 
 	"github.com/docker/distribution/reference"
-	"github.com/docker/docker/api/types"
-	registrytypes "github.com/docker/docker/api/types/registry"
-	"github.com/docker/docker/registry"
+	"github.com/docker/docker/api/types/registry"
+	registrypkg "github.com/docker/docker/registry"
 	"github.com/sirupsen/logrus"
 )
 
@@ -41,7 +40,7 @@ func testTokenPassThru(t *testing.T, ts *httptest.Server) {
 		t.Fatalf("could not parse url from test server: %v", err)
 	}
 
-	endpoint := registry.APIEndpoint{
+	endpoint := registrypkg.APIEndpoint{
 		Mirror:       false,
 		URL:          uri,
 		Version:      2,
@@ -50,9 +49,9 @@ func testTokenPassThru(t *testing.T, ts *httptest.Server) {
 		TLSConfig:    nil,
 	}
 	n, _ := reference.ParseNormalizedNamed("testremotename")
-	repoInfo := &registry.RepositoryInfo{
+	repoInfo := &registrypkg.RepositoryInfo{
 		Name: n,
-		Index: &registrytypes.IndexInfo{
+		Index: &registry.IndexInfo{
 			Name:     "testrepo",
 			Mirrors:  nil,
 			Secure:   false,
@@ -63,7 +62,7 @@ func testTokenPassThru(t *testing.T, ts *httptest.Server) {
 	imagePullConfig := &ImagePullConfig{
 		Config: Config{
 			MetaHeaders: http.Header{},
-			AuthConfig: &types.AuthConfig{
+			AuthConfig: &registry.AuthConfig{
 				RegistryToken: secretRegistryToken,
 			},
 		},

+ 2 - 1
integration/plugin/common/plugin_test.go

@@ -17,6 +17,7 @@ import (
 	"github.com/containerd/containerd/images"
 	"github.com/containerd/containerd/remotes/docker"
 	"github.com/docker/docker/api/types"
+	registrytypes "github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/pkg/jsonmessage"
 	"github.com/docker/docker/testutil/daemon"
 	"github.com/docker/docker/testutil/fixtures/plugin"
@@ -125,7 +126,7 @@ func TestPluginInstall(t *testing.T) {
 
 		name := "test-" + strings.ToLower(t.Name())
 		repo := path.Join(registry.DefaultURL, name+":latest")
-		auth := &types.AuthConfig{ServerAddress: registry.DefaultURL, Username: "testuser", Password: "testpassword"}
+		auth := &registrytypes.AuthConfig{ServerAddress: registry.DefaultURL, Username: "testuser", Password: "testpassword"}
 		assert.NilError(t, plugin.CreateInRegistry(ctx, repo, auth))
 
 		authEncoded, err := json.Marshal(auth)

+ 4 - 4
integration/system/login_test.go

@@ -5,9 +5,9 @@ import (
 	"fmt"
 	"testing"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/integration/internal/requirement"
-	"github.com/docker/docker/registry"
+	registrypkg "github.com/docker/docker/registry"
 	"gotest.tools/v3/assert"
 	is "gotest.tools/v3/assert/cmp"
 	"gotest.tools/v3/skip"
@@ -20,12 +20,12 @@ func TestLoginFailsWithBadCredentials(t *testing.T) {
 	defer setupTest(t)()
 	client := testEnv.APIClient()
 
-	config := types.AuthConfig{
+	config := registry.AuthConfig{
 		Username: "no-user",
 		Password: "no-password",
 	}
 	_, err := client.RegistryLogin(context.Background(), config)
 	assert.Assert(t, err != nil)
 	assert.Check(t, is.ErrorContains(err, "unauthorized: incorrect username or password"))
-	assert.Check(t, is.ErrorContains(err, fmt.Sprintf("https://%s/v2/", registry.DefaultRegistryHost)))
+	assert.Check(t, is.ErrorContains(err, fmt.Sprintf("https://%s/v2/", registrypkg.DefaultRegistryHost)))
 }

+ 8 - 7
plugin/backend_linux.go

@@ -23,6 +23,7 @@ import (
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/pkg/authorization"
@@ -121,12 +122,12 @@ func computePrivileges(c types.PluginConfig) types.PluginPrivileges {
 			Value:       []string{"true"},
 		})
 	}
-	for _, mount := range c.Mounts {
-		if mount.Source != nil {
+	for _, mnt := range c.Mounts {
+		if mnt.Source != nil {
 			privileges = append(privileges, types.PluginPrivilege{
 				Name:        "mount",
 				Description: "host path to mount",
-				Value:       []string{*mount.Source},
+				Value:       []string{*mnt.Source},
 			})
 		}
 	}
@@ -158,7 +159,7 @@ func computePrivileges(c types.PluginConfig) types.PluginPrivileges {
 }
 
 // Privileges pulls a plugin config and computes the privileges required to install it.
-func (pm *Manager) Privileges(ctx context.Context, ref reference.Named, metaHeader http.Header, authConfig *types.AuthConfig) (types.PluginPrivileges, error) {
+func (pm *Manager) Privileges(ctx context.Context, ref reference.Named, metaHeader http.Header, authConfig *registry.AuthConfig) (types.PluginPrivileges, error) {
 	var (
 		config     types.PluginConfig
 		configSeen bool
@@ -206,7 +207,7 @@ func (pm *Manager) Privileges(ctx context.Context, ref reference.Named, metaHead
 // Upgrade upgrades a plugin
 //
 // TODO: replace reference package usage with simpler url.Parse semantics
-func (pm *Manager) Upgrade(ctx context.Context, ref reference.Named, name string, metaHeader http.Header, authConfig *types.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer) (err error) {
+func (pm *Manager) Upgrade(ctx context.Context, ref reference.Named, name string, metaHeader http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer) (err error) {
 	p, err := pm.config.Store.GetV2Plugin(name)
 	if err != nil {
 		return err
@@ -254,7 +255,7 @@ func (pm *Manager) Upgrade(ctx context.Context, ref reference.Named, name string
 // Pull pulls a plugin, check if the correct privileges are provided and install the plugin.
 //
 // TODO: replace reference package usage with simpler url.Parse semantics
-func (pm *Manager) Pull(ctx context.Context, ref reference.Named, name string, metaHeader http.Header, authConfig *types.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer, opts ...CreateOpt) (err error) {
+func (pm *Manager) Pull(ctx context.Context, ref reference.Named, name string, metaHeader http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer, opts ...CreateOpt) (err error) {
 	pm.muGC.RLock()
 	defer pm.muGC.RUnlock()
 
@@ -350,7 +351,7 @@ next:
 }
 
 // Push pushes a plugin to the registry.
-func (pm *Manager) Push(ctx context.Context, name string, metaHeader http.Header, authConfig *types.AuthConfig, outStream io.Writer) error {
+func (pm *Manager) Push(ctx context.Context, name string, metaHeader http.Header, authConfig *registry.AuthConfig, outStream io.Writer) error {
 	p, err := pm.config.Store.GetV2Plugin(name)
 	if err != nil {
 		return err

+ 5 - 4
plugin/backend_unsupported.go

@@ -12,6 +12,7 @@ import (
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/api/types/registry"
 )
 
 var errNotSupported = errors.New("plugins are not supported on this platform")
@@ -32,17 +33,17 @@ func (pm *Manager) Inspect(refOrID string) (tp *types.Plugin, err error) {
 }
 
 // Privileges pulls a plugin config and computes the privileges required to install it.
-func (pm *Manager) Privileges(ctx context.Context, ref reference.Named, metaHeader http.Header, authConfig *types.AuthConfig) (types.PluginPrivileges, error) {
+func (pm *Manager) Privileges(ctx context.Context, ref reference.Named, metaHeader http.Header, authConfig *registry.AuthConfig) (types.PluginPrivileges, error) {
 	return nil, errNotSupported
 }
 
 // Pull pulls a plugin, check if the correct privileges are provided and install the plugin.
-func (pm *Manager) Pull(ctx context.Context, ref reference.Named, name string, metaHeader http.Header, authConfig *types.AuthConfig, privileges types.PluginPrivileges, out io.Writer, opts ...CreateOpt) error {
+func (pm *Manager) Pull(ctx context.Context, ref reference.Named, name string, metaHeader http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, out io.Writer, opts ...CreateOpt) error {
 	return errNotSupported
 }
 
 // Upgrade pulls a plugin, check if the correct privileges are provided and install the plugin.
-func (pm *Manager) Upgrade(ctx context.Context, ref reference.Named, name string, metaHeader http.Header, authConfig *types.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer) error {
+func (pm *Manager) Upgrade(ctx context.Context, ref reference.Named, name string, metaHeader http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer) error {
 	return errNotSupported
 }
 
@@ -52,7 +53,7 @@ func (pm *Manager) List(pluginFilters filters.Args) ([]types.Plugin, error) {
 }
 
 // Push pushes a plugin to the store.
-func (pm *Manager) Push(ctx context.Context, name string, metaHeader http.Header, authConfig *types.AuthConfig, out io.Writer) error {
+func (pm *Manager) Push(ctx context.Context, name string, metaHeader http.Header, authConfig *registry.AuthConfig, out io.Writer) error {
 	return errNotSupported
 }
 

+ 2 - 2
plugin/fetch_linux.go

@@ -12,7 +12,7 @@ import (
 	"github.com/containerd/containerd/remotes"
 	"github.com/containerd/containerd/remotes/docker"
 	"github.com/docker/distribution/reference"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	progressutils "github.com/docker/docker/distribution/utils"
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/ioutils"
@@ -59,7 +59,7 @@ func setupProgressOutput(outStream io.Writer, cancel func()) (progress.Output, f
 
 // fetch the content related to the passed in reference into the blob store and appends the provided images.Handlers
 // There is no need to use remotes.FetchHandler since it already gets set
-func (pm *Manager) fetch(ctx context.Context, ref reference.Named, auth *types.AuthConfig, out progress.Output, metaHeader http.Header, handlers ...images.Handler) (err error) {
+func (pm *Manager) fetch(ctx context.Context, ref reference.Named, auth *registry.AuthConfig, out progress.Output, metaHeader http.Header, handlers ...images.Handler) (err error) {
 	// We need to make sure we have a domain on the reference
 	withDomain, err := reference.ParseNormalizedNamed(ref.String())
 	if err != nil {

+ 3 - 3
plugin/registry.go

@@ -10,7 +10,7 @@ import (
 	"github.com/containerd/containerd/remotes"
 	"github.com/containerd/containerd/remotes/docker"
 	"github.com/docker/distribution/reference"
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/dockerversion"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
@@ -27,7 +27,7 @@ func scope(ref reference.Named, push bool) string {
 	return scope
 }
 
-func (pm *Manager) newResolver(ctx context.Context, tracker docker.StatusTracker, auth *types.AuthConfig, headers http.Header, httpFallback bool) (remotes.Resolver, error) {
+func (pm *Manager) newResolver(ctx context.Context, tracker docker.StatusTracker, auth *registry.AuthConfig, headers http.Header, httpFallback bool) (remotes.Resolver, error) {
 	if headers == nil {
 		headers = http.Header{}
 	}
@@ -55,7 +55,7 @@ func registryHTTPClient(config *tls.Config) *http.Client {
 	}
 }
 
-func (pm *Manager) registryHostsFn(auth *types.AuthConfig, httpFallback bool) docker.RegistryHosts {
+func (pm *Manager) registryHostsFn(auth *registry.AuthConfig, httpFallback bool) docker.RegistryHosts {
 	return func(hostname string) ([]docker.RegistryHost, error) {
 		eps, err := pm.config.RegistryService.LookupPullEndpoints(hostname)
 		if err != nil {

+ 6 - 7
registry/auth.go

@@ -9,7 +9,6 @@ import (
 	"github.com/docker/distribution/registry/client/auth"
 	"github.com/docker/distribution/registry/client/auth/challenge"
 	"github.com/docker/distribution/registry/client/transport"
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/registry"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
@@ -19,7 +18,7 @@ import (
 const AuthClientID = "docker"
 
 type loginCredentialStore struct {
-	authConfig *types.AuthConfig
+	authConfig *registry.AuthConfig
 }
 
 func (lcs loginCredentialStore) Basic(*url.URL) (string, string) {
@@ -35,12 +34,12 @@ func (lcs loginCredentialStore) SetRefreshToken(u *url.URL, service, token strin
 }
 
 type staticCredentialStore struct {
-	auth *types.AuthConfig
+	auth *registry.AuthConfig
 }
 
 // NewStaticCredentialStore returns a credential store
 // which always returns the same credential values.
-func NewStaticCredentialStore(auth *types.AuthConfig) auth.CredentialStore {
+func NewStaticCredentialStore(auth *registry.AuthConfig) auth.CredentialStore {
 	return staticCredentialStore{
 		auth: auth,
 	}
@@ -66,7 +65,7 @@ func (scs staticCredentialStore) SetRefreshToken(*url.URL, string, string) {
 // loginV2 tries to login to the v2 registry server. The given registry
 // endpoint will be pinged to get authorization challenges. These challenges
 // will be used to authenticate against the registry to validate credentials.
-func loginV2(authConfig *types.AuthConfig, endpoint APIEndpoint, userAgent string) (string, string, error) {
+func loginV2(authConfig *registry.AuthConfig, endpoint APIEndpoint, userAgent string) (string, string, error) {
 	var (
 		endpointStr          = strings.TrimRight(endpoint.URL.String(), "/") + "/v2/"
 		modifiers            = Headers(userAgent, nil)
@@ -138,7 +137,7 @@ func ConvertToHostname(url string) string {
 }
 
 // ResolveAuthConfig matches an auth configuration to a server address or a URL
-func ResolveAuthConfig(authConfigs map[string]types.AuthConfig, index *registry.IndexInfo) types.AuthConfig {
+func ResolveAuthConfig(authConfigs map[string]registry.AuthConfig, index *registry.IndexInfo) registry.AuthConfig {
 	configKey := GetAuthConfigKey(index)
 	// First try the happy case
 	if c, found := authConfigs[configKey]; found || index.Official {
@@ -154,7 +153,7 @@ func ResolveAuthConfig(authConfigs map[string]types.AuthConfig, index *registry.
 	}
 
 	// When all else fails, return an empty auth config
-	return types.AuthConfig{}
+	return registry.AuthConfig{}
 }
 
 // PingResponseError is used when the response from a ping

+ 7 - 8
registry/auth_test.go

@@ -3,16 +3,15 @@ package registry // import "github.com/docker/docker/registry"
 import (
 	"testing"
 
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/registry"
 	"gotest.tools/v3/assert"
 )
 
-func buildAuthConfigs() map[string]types.AuthConfig {
-	authConfigs := map[string]types.AuthConfig{}
+func buildAuthConfigs() map[string]registry.AuthConfig {
+	authConfigs := map[string]registry.AuthConfig{}
 
 	for _, reg := range []string{"testIndex", IndexServer} {
-		authConfigs[reg] = types.AuthConfig{
+		authConfigs[reg] = registry.AuthConfig{
 			Username: "docker-user",
 			Password: "docker-pass",
 		}
@@ -42,21 +41,21 @@ func TestResolveAuthConfigIndexServer(t *testing.T) {
 func TestResolveAuthConfigFullURL(t *testing.T) {
 	authConfigs := buildAuthConfigs()
 
-	registryAuth := types.AuthConfig{
+	registryAuth := registry.AuthConfig{
 		Username: "foo-user",
 		Password: "foo-pass",
 	}
-	localAuth := types.AuthConfig{
+	localAuth := registry.AuthConfig{
 		Username: "bar-user",
 		Password: "bar-pass",
 	}
-	officialAuth := types.AuthConfig{
+	officialAuth := registry.AuthConfig{
 		Username: "baz-user",
 		Password: "baz-pass",
 	}
 	authConfigs[IndexServer] = officialAuth
 
-	expectedAuths := map[string]types.AuthConfig{
+	expectedAuths := map[string]registry.AuthConfig{
 		"registry.example.com": registryAuth,
 		"localhost:8000":       localAuth,
 		"example.com":          localAuth,

+ 1 - 2
registry/registry_test.go

@@ -9,7 +9,6 @@ import (
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/registry/client/transport"
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/registry"
 	"gotest.tools/v3/assert"
 	is "gotest.tools/v3/assert/cmp"
@@ -17,7 +16,7 @@ import (
 )
 
 func spawnTestRegistrySession(t *testing.T) *session {
-	authConfig := &types.AuthConfig{}
+	authConfig := &registry.AuthConfig{}
 	endpoint, err := newV1Endpoint(makeIndex("/v1/"), "", nil)
 	if err != nil {
 		t.Fatal(err)

+ 4 - 5
registry/service.go

@@ -10,7 +10,6 @@ import (
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/registry/client/auth"
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 	"github.com/sirupsen/logrus"
@@ -18,11 +17,11 @@ import (
 
 // Service is the interface defining what a registry service should implement.
 type Service interface {
-	Auth(ctx context.Context, authConfig *types.AuthConfig, userAgent string) (status, token string, err error)
+	Auth(ctx context.Context, authConfig *registry.AuthConfig, userAgent string) (status, token string, err error)
 	LookupPullEndpoints(hostname string) (endpoints []APIEndpoint, err error)
 	LookupPushEndpoints(hostname string) (endpoints []APIEndpoint, err error)
 	ResolveRepository(name reference.Named) (*RepositoryInfo, error)
-	Search(ctx context.Context, term string, limit int, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registry.SearchResults, error)
+	Search(ctx context.Context, term string, limit int, authConfig *registry.AuthConfig, userAgent string, headers map[string][]string) (*registry.SearchResults, error)
 	ServiceConfig() *registry.ServiceConfig
 	LoadAllowNondistributableArtifacts([]string) error
 	LoadMirrors([]string) error
@@ -78,7 +77,7 @@ func (s *defaultService) LoadInsecureRegistries(registries []string) error {
 // Auth contacts the public registry with the provided credentials,
 // and returns OK if authentication was successful.
 // It can be used to verify the validity of a client's credentials.
-func (s *defaultService) Auth(ctx context.Context, authConfig *types.AuthConfig, userAgent string) (status, token string, err error) {
+func (s *defaultService) Auth(ctx context.Context, authConfig *registry.AuthConfig, userAgent string) (status, token string, err error) {
 	// TODO Use ctx when searching for repositories
 	var registryHostName = IndexHostname
 
@@ -131,7 +130,7 @@ func splitReposSearchTerm(reposName string) (string, string) {
 
 // Search queries the public registry for images matching the specified
 // search terms, and returns the results.
-func (s *defaultService) Search(ctx context.Context, term string, limit int, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registry.SearchResults, error) {
+func (s *defaultService) Search(ctx context.Context, term string, limit int, authConfig *registry.AuthConfig, userAgent string, headers map[string][]string) (*registry.SearchResults, error) {
 	// TODO Use ctx when searching for repositories
 	if hasScheme(term) {
 		return nil, invalidParamf("invalid repository name: repository name (%s) should not have a scheme", term)

+ 3 - 4
registry/session.go

@@ -11,7 +11,6 @@ import (
 	"strings"
 	"sync"
 
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/pkg/ioutils"
@@ -30,7 +29,7 @@ type session struct {
 
 type authTransport struct {
 	http.RoundTripper
-	*types.AuthConfig
+	*registry.AuthConfig
 
 	alwaysSetBasicAuth bool
 	token              []string
@@ -52,7 +51,7 @@ type authTransport struct {
 // If the server sends a token without the client having requested it, it is ignored.
 //
 // This RoundTripper also has a CancelRequest method important for correct timeout handling.
-func newAuthTransport(base http.RoundTripper, authConfig *types.AuthConfig, alwaysSetBasicAuth bool) *authTransport {
+func newAuthTransport(base http.RoundTripper, authConfig *registry.AuthConfig, alwaysSetBasicAuth bool) *authTransport {
 	if base == nil {
 		base = http.DefaultTransport
 	}
@@ -147,7 +146,7 @@ func (tr *authTransport) CancelRequest(req *http.Request) {
 	}
 }
 
-func authorizeClient(client *http.Client, authConfig *types.AuthConfig, endpoint *v1Endpoint) error {
+func authorizeClient(client *http.Client, authConfig *registry.AuthConfig, endpoint *v1Endpoint) error {
 	var alwaysSetBasicAuth bool
 
 	// If we're working with a standalone private registry over HTTPS, send Basic Auth headers

+ 6 - 5
testutil/fixtures/plugin/plugin.go

@@ -10,9 +10,10 @@ import (
 	"time"
 
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/plugin"
-	"github.com/docker/docker/registry"
+	registrypkg "github.com/docker/docker/registry"
 	"github.com/pkg/errors"
 )
 
@@ -26,7 +27,7 @@ type CreateOpt func(*Config)
 type Config struct {
 	*types.PluginConfig
 	binPath        string
-	RegistryConfig registry.ServiceOptions
+	RegistryConfig registrypkg.ServiceOptions
 }
 
 // WithInsecureRegistry specifies that the given registry can skip host-key checking as well as fall back to plain http
@@ -77,7 +78,7 @@ func Create(ctx context.Context, c CreateClient, name string, opts ...CreateOpt)
 // This can be useful when testing plugins on swarm where you don't really want
 // the plugin to exist on any of the daemons (immediately) and there needs to be
 // some way to distribute the plugin.
-func CreateInRegistry(ctx context.Context, repo string, auth *types.AuthConfig, opts ...CreateOpt) error {
+func CreateInRegistry(ctx context.Context, repo string, auth *registry.AuthConfig, opts ...CreateOpt) error {
 	tmpDir, err := os.MkdirTemp("", "create-test-plugin-local")
 	if err != nil {
 		return err
@@ -105,7 +106,7 @@ func CreateInRegistry(ctx context.Context, repo string, auth *types.AuthConfig,
 		return nil, nil
 	}
 
-	regService, err := registry.NewService(cfg.RegistryConfig)
+	regService, err := registrypkg.NewService(cfg.RegistryConfig)
 	if err != nil {
 		return err
 	}
@@ -130,7 +131,7 @@ func CreateInRegistry(ctx context.Context, repo string, auth *types.AuthConfig,
 	}
 
 	if auth == nil {
-		auth = &types.AuthConfig{}
+		auth = &registry.AuthConfig{}
 	}
 	err = manager.Push(ctx, repo, nil, auth, io.Discard)
 	return errors.Wrap(err, "error pushing plugin")