package registry import ( "context" "crypto/tls" "errors" "fmt" "net/url" "strings" "github.com/containerd/errdefs" "github.com/containerd/log" "github.com/moby/moby/api/types/registry" ) // Service is a registry service. It tracks configuration data such as a list // of mirrors. type Service struct { config *serviceConfig } // NewService returns a new instance of [Service] ready to be installed into // an engine. func NewService(options ServiceOptions) (*Service, error) { config, err := newServiceConfig(options.InsecureRegistries) if err != nil { return nil, err } return &Service{config: config}, nil } // 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 *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, userAgent string) (token string, _ error) { registryHostName := IndexHostname if authConfig.ServerAddress != "" { serverAddress := authConfig.ServerAddress if !strings.HasPrefix(serverAddress, "https://") && !strings.HasPrefix(serverAddress, "http://") { serverAddress = "https://" + serverAddress } u, err := url.Parse(serverAddress) if err != nil { return "", invalidParam(fmt.Errorf("unable to parse server address: %w", err)) } registryHostName = u.Host } // Lookup endpoints for authentication. endpoints, err := s.Endpoints(ctx, registryHostName) if err != nil { if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { return "", err } return "", invalidParam(err) } var lastErr error for _, endpoint := range endpoints { authToken, err := loginV2(ctx, authConfig, endpoint, userAgent) if err != nil { if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) || errdefs.IsUnauthorized(err) { // Failed to authenticate; don't continue with (non-TLS) endpoints. return "", err } // Try next endpoint log.G(ctx).WithFields(log.Fields{ "error": err, "endpoint": endpoint, }).Infof("Error logging in to endpoint, trying next endpoint") lastErr = err continue } return authToken, nil } return "", lastErr } // APIEndpoint represents a remote API endpoint type APIEndpoint struct { URL *url.URL TLSConfig *tls.Config }