Merge auth package within registry
Docker-DCO-1.1-Signed-off-by: Guillaume J. Charmes <guillaume@charmes.net> (github: creack)master
							parent
							
								
									af1a352485
								
							
						
					
					
						commit
						f6fefb0bc1
					
				|  | @ -0,0 +1,290 @@ | |||
| package registry | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/dotcloud/docker/utils" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| // Where we store the config file
 | ||||
| const CONFIGFILE = ".dockercfg" | ||||
| 
 | ||||
| // Only used for user auth + account creation
 | ||||
| const INDEXSERVER = "https://index.docker.io/v1/" | ||||
| 
 | ||||
| //const INDEXSERVER = "https://indexstaging-docker.dotcloud.com/v1/"
 | ||||
| 
 | ||||
| var ( | ||||
| 	ErrConfigFileMissing = errors.New("The Auth config file is missing") | ||||
| ) | ||||
| 
 | ||||
| type AuthConfig struct { | ||||
| 	Username      string `json:"username,omitempty"` | ||||
| 	Password      string `json:"password,omitempty"` | ||||
| 	Auth          string `json:"auth"` | ||||
| 	Email         string `json:"email"` | ||||
| 	ServerAddress string `json:"serveraddress,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type ConfigFile struct { | ||||
| 	Configs  map[string]AuthConfig `json:"configs,omitempty"` | ||||
| 	rootPath string | ||||
| } | ||||
| 
 | ||||
| func IndexServerAddress() string { | ||||
| 	return INDEXSERVER | ||||
| } | ||||
| 
 | ||||
| // create a base64 encoded auth string to store in config
 | ||||
| func encodeAuth(authConfig *AuthConfig) string { | ||||
| 	authStr := authConfig.Username + ":" + authConfig.Password | ||||
| 	msg := []byte(authStr) | ||||
| 	encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg))) | ||||
| 	base64.StdEncoding.Encode(encoded, msg) | ||||
| 	return string(encoded) | ||||
| } | ||||
| 
 | ||||
| // decode the auth string
 | ||||
| func decodeAuth(authStr string) (string, string, error) { | ||||
| 	decLen := base64.StdEncoding.DecodedLen(len(authStr)) | ||||
| 	decoded := make([]byte, decLen) | ||||
| 	authByte := []byte(authStr) | ||||
| 	n, err := base64.StdEncoding.Decode(decoded, authByte) | ||||
| 	if err != nil { | ||||
| 		return "", "", err | ||||
| 	} | ||||
| 	if n > decLen { | ||||
| 		return "", "", fmt.Errorf("Something went wrong decoding auth config") | ||||
| 	} | ||||
| 	arr := strings.SplitN(string(decoded), ":", 2) | ||||
| 	if len(arr) != 2 { | ||||
| 		return "", "", fmt.Errorf("Invalid auth configuration file") | ||||
| 	} | ||||
| 	password := strings.Trim(arr[1], "\x00") | ||||
| 	return arr[0], password, nil | ||||
| } | ||||
| 
 | ||||
| // load up the auth config information and return values
 | ||||
| // FIXME: use the internal golang config parser
 | ||||
| func LoadConfig(rootPath string) (*ConfigFile, error) { | ||||
| 	configFile := ConfigFile{Configs: make(map[string]AuthConfig), rootPath: rootPath} | ||||
| 	confFile := path.Join(rootPath, CONFIGFILE) | ||||
| 	if _, err := os.Stat(confFile); err != nil { | ||||
| 		return &configFile, nil //missing file is not an error
 | ||||
| 	} | ||||
| 	b, err := ioutil.ReadFile(confFile) | ||||
| 	if err != nil { | ||||
| 		return &configFile, err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := json.Unmarshal(b, &configFile.Configs); err != nil { | ||||
| 		arr := strings.Split(string(b), "\n") | ||||
| 		if len(arr) < 2 { | ||||
| 			return &configFile, fmt.Errorf("The Auth config file is empty") | ||||
| 		} | ||||
| 		authConfig := AuthConfig{} | ||||
| 		origAuth := strings.Split(arr[0], " = ") | ||||
| 		if len(origAuth) != 2 { | ||||
| 			return &configFile, fmt.Errorf("Invalid Auth config file") | ||||
| 		} | ||||
| 		authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1]) | ||||
| 		if err != nil { | ||||
| 			return &configFile, err | ||||
| 		} | ||||
| 		origEmail := strings.Split(arr[1], " = ") | ||||
| 		if len(origEmail) != 2 { | ||||
| 			return &configFile, fmt.Errorf("Invalid Auth config file") | ||||
| 		} | ||||
| 		authConfig.Email = origEmail[1] | ||||
| 		authConfig.ServerAddress = IndexServerAddress() | ||||
| 		configFile.Configs[IndexServerAddress()] = authConfig | ||||
| 	} else { | ||||
| 		for k, authConfig := range configFile.Configs { | ||||
| 			authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth) | ||||
| 			if err != nil { | ||||
| 				return &configFile, err | ||||
| 			} | ||||
| 			authConfig.Auth = "" | ||||
| 			configFile.Configs[k] = authConfig | ||||
| 			authConfig.ServerAddress = k | ||||
| 		} | ||||
| 	} | ||||
| 	return &configFile, nil | ||||
| } | ||||
| 
 | ||||
| // save the auth config
 | ||||
| func SaveConfig(configFile *ConfigFile) error { | ||||
| 	confFile := path.Join(configFile.rootPath, CONFIGFILE) | ||||
| 	if len(configFile.Configs) == 0 { | ||||
| 		os.Remove(confFile) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	configs := make(map[string]AuthConfig, len(configFile.Configs)) | ||||
| 	for k, authConfig := range configFile.Configs { | ||||
| 		authCopy := authConfig | ||||
| 
 | ||||
| 		authCopy.Auth = encodeAuth(&authCopy) | ||||
| 		authCopy.Username = "" | ||||
| 		authCopy.Password = "" | ||||
| 		authCopy.ServerAddress = "" | ||||
| 		configs[k] = authCopy | ||||
| 	} | ||||
| 
 | ||||
| 	b, err := json.Marshal(configs) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = ioutil.WriteFile(confFile, b, 0600) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // try to register/login to the registry server
 | ||||
| func Login(authConfig *AuthConfig, factory *utils.HTTPRequestFactory) (string, error) { | ||||
| 	var ( | ||||
| 		status        string | ||||
| 		reqBody       []byte | ||||
| 		err           error | ||||
| 		client        = &http.Client{} | ||||
| 		reqStatusCode = 0 | ||||
| 		serverAddress = authConfig.ServerAddress | ||||
| 	) | ||||
| 
 | ||||
| 	if serverAddress == "" { | ||||
| 		serverAddress = IndexServerAddress() | ||||
| 	} | ||||
| 
 | ||||
| 	loginAgainstOfficialIndex := serverAddress == IndexServerAddress() | ||||
| 
 | ||||
| 	// to avoid sending the server address to the server it should be removed before being marshalled
 | ||||
| 	authCopy := *authConfig | ||||
| 	authCopy.ServerAddress = "" | ||||
| 
 | ||||
| 	jsonBody, err := json.Marshal(authCopy) | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("Config Error: %s", err) | ||||
| 	} | ||||
| 
 | ||||
| 	// using `bytes.NewReader(jsonBody)` here causes the server to respond with a 411 status.
 | ||||
| 	b := strings.NewReader(string(jsonBody)) | ||||
| 	req1, err := http.Post(serverAddress+"users/", "application/json; charset=utf-8", b) | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("Server Error: %s", err) | ||||
| 	} | ||||
| 	reqStatusCode = req1.StatusCode | ||||
| 	defer req1.Body.Close() | ||||
| 	reqBody, err = ioutil.ReadAll(req1.Body) | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("Server Error: [%#v] %s", reqStatusCode, err) | ||||
| 	} | ||||
| 
 | ||||
| 	if reqStatusCode == 201 { | ||||
| 		if loginAgainstOfficialIndex { | ||||
| 			status = "Account created. Please use the confirmation link we sent" + | ||||
| 				" to your e-mail to activate it." | ||||
| 		} else { | ||||
| 			status = "Account created. Please see the documentation of the registry " + serverAddress + " for instructions how to activate it." | ||||
| 		} | ||||
| 	} else if reqStatusCode == 400 { | ||||
| 		if string(reqBody) == "\"Username or email already exists\"" { | ||||
| 			req, err := factory.NewRequest("GET", serverAddress+"users/", nil) | ||||
| 			req.SetBasicAuth(authConfig.Username, authConfig.Password) | ||||
| 			resp, err := client.Do(req) | ||||
| 			if err != nil { | ||||
| 				return "", err | ||||
| 			} | ||||
| 			defer resp.Body.Close() | ||||
| 			body, err := ioutil.ReadAll(resp.Body) | ||||
| 			if err != nil { | ||||
| 				return "", err | ||||
| 			} | ||||
| 			if resp.StatusCode == 200 { | ||||
| 				status = "Login Succeeded" | ||||
| 			} else if resp.StatusCode == 401 { | ||||
| 				return "", fmt.Errorf("Wrong login/password, please try again") | ||||
| 			} else if resp.StatusCode == 403 { | ||||
| 				if loginAgainstOfficialIndex { | ||||
| 					return "", fmt.Errorf("Login: Account is not Active. Please check your e-mail for a confirmation link.") | ||||
| 				} | ||||
| 				return "", fmt.Errorf("Login: Account is not Active. Please see the documentation of the registry %s for instructions how to activate it.", serverAddress) | ||||
| 			} else { | ||||
| 				return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body, resp.StatusCode, resp.Header) | ||||
| 			} | ||||
| 		} else { | ||||
| 			return "", fmt.Errorf("Registration: %s", reqBody) | ||||
| 		} | ||||
| 	} else if reqStatusCode == 401 { | ||||
| 		// This case would happen with private registries where /v1/users is
 | ||||
| 		// protected, so people can use `docker login` as an auth check.
 | ||||
| 		req, err := factory.NewRequest("GET", serverAddress+"users/", nil) | ||||
| 		req.SetBasicAuth(authConfig.Username, authConfig.Password) | ||||
| 		resp, err := client.Do(req) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		defer resp.Body.Close() | ||||
| 		body, err := ioutil.ReadAll(resp.Body) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		if resp.StatusCode == 200 { | ||||
| 			status = "Login Succeeded" | ||||
| 		} else if resp.StatusCode == 401 { | ||||
| 			return "", fmt.Errorf("Wrong login/password, please try again") | ||||
| 		} else { | ||||
| 			return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body, | ||||
| 				resp.StatusCode, resp.Header) | ||||
| 		} | ||||
| 	} else { | ||||
| 		return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody) | ||||
| 	} | ||||
| 	return status, nil | ||||
| } | ||||
| 
 | ||||
| // this method matches a auth configuration to a server address or a url
 | ||||
| func (config *ConfigFile) ResolveAuthConfig(hostname string) AuthConfig { | ||||
| 	if hostname == IndexServerAddress() || len(hostname) == 0 { | ||||
| 		// default to the index server
 | ||||
| 		return config.Configs[IndexServerAddress()] | ||||
| 	} | ||||
| 
 | ||||
| 	// First try the happy case
 | ||||
| 	if c, found := config.Configs[hostname]; found { | ||||
| 		return c | ||||
| 	} | ||||
| 
 | ||||
| 	convertToHostname := func(url string) string { | ||||
| 		stripped := url | ||||
| 		if strings.HasPrefix(url, "http://") { | ||||
| 			stripped = strings.Replace(url, "http://", "", 1) | ||||
| 		} else if strings.HasPrefix(url, "https://") { | ||||
| 			stripped = strings.Replace(url, "https://", "", 1) | ||||
| 		} | ||||
| 
 | ||||
| 		nameParts := strings.SplitN(stripped, "/", 2) | ||||
| 
 | ||||
| 		return nameParts[0] | ||||
| 	} | ||||
| 
 | ||||
| 	// Maybe they have a legacy config file, we will iterate the keys converting
 | ||||
| 	// them to the new format and testing
 | ||||
| 	normalizedHostename := convertToHostname(hostname) | ||||
| 	for registry, config := range config.Configs { | ||||
| 		if registryHostname := convertToHostname(registry); registryHostname == normalizedHostename { | ||||
| 			return config | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// When all else fails, return an empty auth config
 | ||||
| 	return AuthConfig{} | ||||
| } | ||||
|  | @ -0,0 +1,149 @@ | |||
| package registry | ||||
| 
 | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func TestEncodeAuth(t *testing.T) { | ||||
| 	newAuthConfig := &AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"} | ||||
| 	authStr := encodeAuth(newAuthConfig) | ||||
| 	decAuthConfig := &AuthConfig{} | ||||
| 	var err error | ||||
| 	decAuthConfig.Username, decAuthConfig.Password, err = decodeAuth(authStr) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if newAuthConfig.Username != decAuthConfig.Username { | ||||
| 		t.Fatal("Encode Username doesn't match decoded Username") | ||||
| 	} | ||||
| 	if newAuthConfig.Password != decAuthConfig.Password { | ||||
| 		t.Fatal("Encode Password doesn't match decoded Password") | ||||
| 	} | ||||
| 	if authStr != "a2VuOnRlc3Q=" { | ||||
| 		t.Fatal("AuthString encoding isn't correct.") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func setupTempConfigFile() (*ConfigFile, error) { | ||||
| 	root, err := ioutil.TempDir("", "docker-test-auth") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	configFile := &ConfigFile{ | ||||
| 		rootPath: root, | ||||
| 		Configs:  make(map[string]AuthConfig), | ||||
| 	} | ||||
| 
 | ||||
| 	for _, registry := range []string{"testIndex", IndexServerAddress()} { | ||||
| 		configFile.Configs[registry] = AuthConfig{ | ||||
| 			Username: "docker-user", | ||||
| 			Password: "docker-pass", | ||||
| 			Email:    "docker@docker.io", | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return configFile, nil | ||||
| } | ||||
| 
 | ||||
| func TestSameAuthDataPostSave(t *testing.T) { | ||||
| 	configFile, err := setupTempConfigFile() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer os.RemoveAll(configFile.rootPath) | ||||
| 
 | ||||
| 	err = SaveConfig(configFile) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	authConfig := configFile.Configs["testIndex"] | ||||
| 	if authConfig.Username != "docker-user" { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| 	if authConfig.Password != "docker-pass" { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| 	if authConfig.Email != "docker@docker.io" { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| 	if authConfig.Auth != "" { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestResolveAuthConfigIndexServer(t *testing.T) { | ||||
| 	configFile, err := setupTempConfigFile() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer os.RemoveAll(configFile.rootPath) | ||||
| 
 | ||||
| 	for _, registry := range []string{"", IndexServerAddress()} { | ||||
| 		resolved := configFile.ResolveAuthConfig(registry) | ||||
| 		if resolved != configFile.Configs[IndexServerAddress()] { | ||||
| 			t.Fail() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestResolveAuthConfigFullURL(t *testing.T) { | ||||
| 	configFile, err := setupTempConfigFile() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer os.RemoveAll(configFile.rootPath) | ||||
| 
 | ||||
| 	registryAuth := AuthConfig{ | ||||
| 		Username: "foo-user", | ||||
| 		Password: "foo-pass", | ||||
| 		Email:    "foo@example.com", | ||||
| 	} | ||||
| 	localAuth := AuthConfig{ | ||||
| 		Username: "bar-user", | ||||
| 		Password: "bar-pass", | ||||
| 		Email:    "bar@example.com", | ||||
| 	} | ||||
| 	configFile.Configs["https://registry.example.com/v1/"] = registryAuth | ||||
| 	configFile.Configs["http://localhost:8000/v1/"] = localAuth | ||||
| 	configFile.Configs["registry.com"] = registryAuth | ||||
| 
 | ||||
| 	validRegistries := map[string][]string{ | ||||
| 		"https://registry.example.com/v1/": { | ||||
| 			"https://registry.example.com/v1/", | ||||
| 			"http://registry.example.com/v1/", | ||||
| 			"registry.example.com", | ||||
| 			"registry.example.com/v1/", | ||||
| 		}, | ||||
| 		"http://localhost:8000/v1/": { | ||||
| 			"https://localhost:8000/v1/", | ||||
| 			"http://localhost:8000/v1/", | ||||
| 			"localhost:8000", | ||||
| 			"localhost:8000/v1/", | ||||
| 		}, | ||||
| 		"registry.com": { | ||||
| 			"https://registry.com/v1/", | ||||
| 			"http://registry.com/v1/", | ||||
| 			"registry.com", | ||||
| 			"registry.com/v1/", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for configKey, registries := range validRegistries { | ||||
| 		for _, registry := range registries { | ||||
| 			var ( | ||||
| 				configured AuthConfig | ||||
| 				ok         bool | ||||
| 			) | ||||
| 			resolved := configFile.ResolveAuthConfig(registry) | ||||
| 			if configured, ok = configFile.Configs[configKey]; !ok { | ||||
| 				t.Fail() | ||||
| 			} | ||||
| 			if resolved.Email != configured.Email { | ||||
| 				t.Errorf("%s -> %q != %q\n", registry, resolved.Email, configured.Email) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -6,7 +6,6 @@ import ( | |||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/dotcloud/docker/auth" | ||||
| 	"github.com/dotcloud/docker/utils" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
|  | @ -27,7 +26,7 @@ var ( | |||
| ) | ||||
| 
 | ||||
| func pingRegistryEndpoint(endpoint string) (bool, error) { | ||||
| 	if endpoint == auth.IndexServerAddress() { | ||||
| 	if endpoint == IndexServerAddress() { | ||||
| 		// Skip the check, we now this one is valid
 | ||||
| 		// (and we never want to fallback to http in case of error)
 | ||||
| 		return false, nil | ||||
|  | @ -103,7 +102,7 @@ func ResolveRepositoryName(reposName string) (string, string, error) { | |||
| 		nameParts[0] != "localhost" { | ||||
| 		// This is a Docker Index repos (ex: samalba/hipache or ubuntu)
 | ||||
| 		err := validateRepositoryName(reposName) | ||||
| 		return auth.IndexServerAddress(), reposName, err | ||||
| 		return IndexServerAddress(), reposName, err | ||||
| 	} | ||||
| 	if len(nameParts) < 2 { | ||||
| 		// There is a dot in repos name (and no registry address)
 | ||||
|  | @ -601,7 +600,7 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat | |||
| 
 | ||||
| func (r *Registry) SearchRepositories(term string) (*SearchResults, error) { | ||||
| 	utils.Debugf("Index server: %s", r.indexEndpoint) | ||||
| 	u := auth.IndexServerAddress() + "search?q=" + url.QueryEscape(term) | ||||
| 	u := IndexServerAddress() + "search?q=" + url.QueryEscape(term) | ||||
| 	req, err := r.reqFactory.NewRequest("GET", u, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|  | @ -627,12 +626,12 @@ func (r *Registry) SearchRepositories(term string) (*SearchResults, error) { | |||
| 	return result, err | ||||
| } | ||||
| 
 | ||||
| func (r *Registry) GetAuthConfig(withPasswd bool) *auth.AuthConfig { | ||||
| func (r *Registry) GetAuthConfig(withPasswd bool) *AuthConfig { | ||||
| 	password := "" | ||||
| 	if withPasswd { | ||||
| 		password = r.authConfig.Password | ||||
| 	} | ||||
| 	return &auth.AuthConfig{ | ||||
| 	return &AuthConfig{ | ||||
| 		Username: r.authConfig.Username, | ||||
| 		Password: password, | ||||
| 		Email:    r.authConfig.Email, | ||||
|  | @ -668,12 +667,12 @@ type ImgData struct { | |||
| 
 | ||||
| type Registry struct { | ||||
| 	client        *http.Client | ||||
| 	authConfig    *auth.AuthConfig | ||||
| 	authConfig    *AuthConfig | ||||
| 	reqFactory    *utils.HTTPRequestFactory | ||||
| 	indexEndpoint string | ||||
| } | ||||
| 
 | ||||
| func NewRegistry(authConfig *auth.AuthConfig, factory *utils.HTTPRequestFactory, indexEndpoint string) (r *Registry, err error) { | ||||
| func NewRegistry(authConfig *AuthConfig, factory *utils.HTTPRequestFactory, indexEndpoint string) (r *Registry, err error) { | ||||
| 	httpTransport := &http.Transport{ | ||||
| 		DisableKeepAlives: true, | ||||
| 		Proxy:             http.ProxyFromEnvironment, | ||||
|  | @ -693,13 +692,13 @@ func NewRegistry(authConfig *auth.AuthConfig, factory *utils.HTTPRequestFactory, | |||
| 
 | ||||
| 	// If we're working with a standalone private registry over HTTPS, send Basic Auth headers
 | ||||
| 	// alongside our requests.
 | ||||
| 	if indexEndpoint != auth.IndexServerAddress() && strings.HasPrefix(indexEndpoint, "https://") { | ||||
| 	if indexEndpoint != IndexServerAddress() && strings.HasPrefix(indexEndpoint, "https://") { | ||||
| 		standalone, err := pingRegistryEndpoint(indexEndpoint) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if standalone { | ||||
| 			utils.Debugf("Endpoint %s is eligible for private registry auth. Enabling decorator.", indexEndpoint) | ||||
| 			utils.Debugf("Endpoint %s is eligible for private registry registry. Enabling decorator.", indexEndpoint) | ||||
| 			dec := utils.NewHTTPAuthDecorator(authConfig.Username, authConfig.Password) | ||||
| 			factory.AddDecorator(dec) | ||||
| 		} | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| package registry | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/dotcloud/docker/auth" | ||||
| 	"github.com/dotcloud/docker/utils" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | @ -14,7 +13,7 @@ var ( | |||
| ) | ||||
| 
 | ||||
| func spawnTestRegistry(t *testing.T) *Registry { | ||||
| 	authConfig := &auth.AuthConfig{} | ||||
| 	authConfig := &AuthConfig{} | ||||
| 	r, err := NewRegistry(authConfig, utils.NewHTTPRequestFactory(), makeURL("/v1/")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
|  | @ -137,7 +136,7 @@ func TestResolveRepositoryName(t *testing.T) { | |||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	assertEqual(t, ep, auth.IndexServerAddress(), "Expected endpoint to be index server address") | ||||
| 	assertEqual(t, ep, IndexServerAddress(), "Expected endpoint to be index server address") | ||||
| 	assertEqual(t, repo, "fooo/bar", "Expected resolved repo to be foo/bar") | ||||
| 
 | ||||
| 	u := makeURL("")[7:] | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue