Skip to content

Commit 3bae188

Browse files
committed
change dockercfg to json and support multiple auth remote
1 parent 9a15db2 commit 3bae188

3 files changed

Lines changed: 87 additions & 127 deletions

File tree

api.go

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -81,54 +81,15 @@ func getBoolParam(value string) (bool, error) {
8181
return ret, nil
8282
}
8383

84-
func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
85-
if version > 1.1 {
86-
w.WriteHeader(http.StatusNotFound)
87-
return nil
88-
}
89-
authConfig, err := auth.LoadConfig(srv.runtime.root)
90-
if err != nil {
91-
if err != auth.ErrConfigFileMissing {
92-
return err
93-
}
94-
authConfig = &auth.AuthConfig{}
95-
}
96-
b, err := json.Marshal(&auth.AuthConfig{Username: authConfig.Username, Email: authConfig.Email})
97-
if err != nil {
98-
return err
99-
}
100-
writeJSON(w, b)
101-
return nil
102-
}
103-
10484
func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
10585
authConfig := &auth.AuthConfig{}
10686
err := json.NewDecoder(r.Body).Decode(authConfig)
10787
if err != nil {
10888
return err
10989
}
110-
status := ""
111-
if version > 1.1 {
112-
status, err = auth.Login(authConfig, false)
113-
if err != nil {
114-
return err
115-
}
116-
} else {
117-
localAuthConfig, err := auth.LoadConfig(srv.runtime.root)
118-
if err != nil {
119-
if err != auth.ErrConfigFileMissing {
120-
return err
121-
}
122-
}
123-
if authConfig.Username == localAuthConfig.Username {
124-
authConfig.Password = localAuthConfig.Password
125-
}
126-
127-
newAuthConfig := auth.NewAuthConfig(authConfig.Username, authConfig.Password, authConfig.Email, srv.runtime.root)
128-
status, err = auth.Login(newAuthConfig, true)
129-
if err != nil {
130-
return err
131-
}
90+
status, err := auth.Login(authConfig)
91+
if err != nil {
92+
return err
13293
}
13394
if status != "" {
13495
b, err := json.Marshal(&APIAuth{Status: status})
@@ -429,16 +390,8 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht
429390

430391
func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
431392
authConfig := &auth.AuthConfig{}
432-
if version > 1.1 {
433-
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
434-
return err
435-
}
436-
} else {
437-
localAuthConfig, err := auth.LoadConfig(srv.runtime.root)
438-
if err != nil && err != auth.ErrConfigFileMissing {
439-
return err
440-
}
441-
authConfig = localAuthConfig
393+
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
394+
return err
442395
}
443396
if err := parseForm(r); err != nil {
444397
return err
@@ -854,7 +807,6 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
854807

855808
m := map[string]map[string]func(*Server, float64, http.ResponseWriter, *http.Request, map[string]string) error{
856809
"GET": {
857-
"/auth": getAuth,
858810
"/version": getVersion,
859811
"/info": getInfo,
860812
"/images/json": getImagesJSON,

auth/auth.go

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,15 @@ var (
2525
)
2626

2727
type AuthConfig struct {
28-
Username string `json:"username"`
29-
Password string `json:"password"`
28+
Username string `json:"username,omitempty"`
29+
Password string `json:"password,omitempty"`
30+
Auth string `json:"auth"`
3031
Email string `json:"email"`
31-
rootPath string
3232
}
3333

34-
func NewAuthConfig(username, password, email, rootPath string) *AuthConfig {
35-
return &AuthConfig{
36-
Username: username,
37-
Password: password,
38-
Email: email,
39-
rootPath: rootPath,
40-
}
34+
type ConfigFile struct {
35+
Configs map[string]AuthConfig `json:"configs,omitempty"`
36+
rootPath string
4137
}
4238

4339
func IndexServerAddress() string {
@@ -54,70 +50,91 @@ func encodeAuth(authConfig *AuthConfig) string {
5450
}
5551

5652
// decode the auth string
57-
func decodeAuth(authStr string) (*AuthConfig, error) {
53+
func decodeAuth(authStr string) (string, string, error) {
5854
decLen := base64.StdEncoding.DecodedLen(len(authStr))
5955
decoded := make([]byte, decLen)
6056
authByte := []byte(authStr)
6157
n, err := base64.StdEncoding.Decode(decoded, authByte)
6258
if err != nil {
63-
return nil, err
59+
return "", "", err
6460
}
6561
if n > decLen {
66-
return nil, fmt.Errorf("Something went wrong decoding auth config")
62+
return "", "", fmt.Errorf("Something went wrong decoding auth config")
6763
}
6864
arr := strings.Split(string(decoded), ":")
6965
if len(arr) != 2 {
70-
return nil, fmt.Errorf("Invalid auth configuration file")
66+
return "", "", fmt.Errorf("Invalid auth configuration file")
7167
}
7268
password := strings.Trim(arr[1], "\x00")
73-
return &AuthConfig{Username: arr[0], Password: password}, nil
69+
return arr[0], password, nil
7470
}
7571

7672
// load up the auth config information and return values
7773
// FIXME: use the internal golang config parser
78-
func LoadConfig(rootPath string) (*AuthConfig, error) {
74+
func LoadConfig(rootPath string) (*ConfigFile, error) {
75+
configFile := ConfigFile{Configs: make(map[string]AuthConfig), rootPath: rootPath}
7976
confFile := path.Join(rootPath, CONFIGFILE)
8077
if _, err := os.Stat(confFile); err != nil {
81-
return &AuthConfig{rootPath: rootPath}, ErrConfigFileMissing
78+
return &configFile, ErrConfigFileMissing
8279
}
8380
b, err := ioutil.ReadFile(confFile)
8481
if err != nil {
8582
return nil, err
8683
}
87-
arr := strings.Split(string(b), "\n")
88-
if len(arr) < 2 {
89-
return nil, fmt.Errorf("The Auth config file is empty")
90-
}
91-
origAuth := strings.Split(arr[0], " = ")
92-
origEmail := strings.Split(arr[1], " = ")
93-
authConfig, err := decodeAuth(origAuth[1])
94-
if err != nil {
95-
return nil, err
84+
85+
if err := json.Unmarshal(b, &configFile.Configs); err != nil {
86+
arr := strings.Split(string(b), "\n")
87+
if len(arr) < 2 {
88+
return nil, fmt.Errorf("The Auth config file is empty")
89+
}
90+
authConfig := AuthConfig{}
91+
origAuth := strings.Split(arr[0], " = ")
92+
authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
93+
if err != nil {
94+
return nil, err
95+
}
96+
origEmail := strings.Split(arr[1], " = ")
97+
authConfig.Email = origEmail[1]
98+
configFile.Configs[IndexServerAddress()] = authConfig
99+
} else {
100+
for k, authConfig := range configFile.Configs {
101+
authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth)
102+
if err != nil {
103+
return nil, err
104+
}
105+
configFile.Configs[k] = authConfig
106+
}
96107
}
97-
authConfig.Email = origEmail[1]
98-
authConfig.rootPath = rootPath
99-
return authConfig, nil
108+
return &configFile, nil
100109
}
101110

102111
// save the auth config
103-
func SaveConfig(authConfig *AuthConfig) error {
104-
confFile := path.Join(authConfig.rootPath, CONFIGFILE)
105-
if len(authConfig.Email) == 0 {
112+
func SaveConfig(configFile *ConfigFile) error {
113+
confFile := path.Join(configFile.rootPath, CONFIGFILE)
114+
if len(configFile.Configs) == 0 {
106115
os.Remove(confFile)
107116
return nil
108117
}
109-
lines := "auth = " + encodeAuth(authConfig) + "\n" + "email = " + authConfig.Email + "\n"
110-
b := []byte(lines)
111-
err := ioutil.WriteFile(confFile, b, 0600)
118+
for k, authConfig := range configFile.Configs {
119+
authConfig.Auth = encodeAuth(&authConfig)
120+
authConfig.Username = ""
121+
authConfig.Password = ""
122+
configFile.Configs[k] = authConfig
123+
}
124+
125+
b, err := json.Marshal(configFile.Configs)
126+
if err != nil {
127+
return err
128+
}
129+
err = ioutil.WriteFile(confFile, b, 0600)
112130
if err != nil {
113131
return err
114132
}
115133
return nil
116134
}
117135

118136
// try to register/login to the registry server
119-
func Login(authConfig *AuthConfig, store bool) (string, error) {
120-
storeConfig := false
137+
func Login(authConfig *AuthConfig) (string, error) {
121138
client := &http.Client{}
122139
reqStatusCode := 0
123140
var status string
@@ -143,7 +160,6 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
143160
if reqStatusCode == 201 {
144161
status = "Account created. Please use the confirmation link we sent" +
145162
" to your e-mail to activate it."
146-
storeConfig = true
147163
} else if reqStatusCode == 403 {
148164
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
149165
"Please check your e-mail for a confirmation link.")
@@ -162,14 +178,7 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
162178
}
163179
if resp.StatusCode == 200 {
164180
status = "Login Succeeded"
165-
storeConfig = true
166181
} else if resp.StatusCode == 401 {
167-
if store {
168-
authConfig.Email = ""
169-
if err := SaveConfig(authConfig); err != nil {
170-
return "", err
171-
}
172-
}
173182
return "", fmt.Errorf("Wrong login/password, please try again")
174183
} else {
175184
return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body,
@@ -181,10 +190,5 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
181190
} else {
182191
return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody)
183192
}
184-
if storeConfig && store {
185-
if err := SaveConfig(authConfig); err != nil {
186-
return "", err
187-
}
188-
}
189193
return status, nil
190194
}

commands.go

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -313,16 +313,21 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
313313
email string
314314
)
315315

316+
authconfig, ok := cli.configFile.Configs[auth.IndexServerAddress()]
317+
if !ok {
318+
authconfig = auth.AuthConfig{}
319+
}
320+
316321
if *flUsername == "" {
317-
fmt.Fprintf(cli.out, "Username (%s): ", cli.authConfig.Username)
322+
fmt.Fprintf(cli.out, "Username (%s): ", authconfig.Username)
318323
username = readAndEchoString(cli.in, cli.out)
319324
if username == "" {
320-
username = cli.authConfig.Username
325+
username = authconfig.Username
321326
}
322327
} else {
323328
username = *flUsername
324329
}
325-
if username != cli.authConfig.Username {
330+
if username != authconfig.Username {
326331
if *flPassword == "" {
327332
fmt.Fprintf(cli.out, "Password: ")
328333
password = readString(cli.in, cli.out)
@@ -334,31 +339,30 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
334339
}
335340

336341
if *flEmail == "" {
337-
fmt.Fprintf(cli.out, "Email (%s): ", cli.authConfig.Email)
342+
fmt.Fprintf(cli.out, "Email (%s): ", authconfig.Email)
338343
email = readAndEchoString(cli.in, cli.out)
339344
if email == "" {
340-
email = cli.authConfig.Email
345+
email = authconfig.Email
341346
}
342347
} else {
343348
email = *flEmail
344349
}
345350
} else {
346-
password = cli.authConfig.Password
347-
email = cli.authConfig.Email
351+
password = authconfig.Password
352+
email = authconfig.Email
348353
}
349354
if oldState != nil {
350355
term.RestoreTerminal(cli.terminalFd, oldState)
351356
}
352-
cli.authConfig.Username = username
353-
cli.authConfig.Password = password
354-
cli.authConfig.Email = email
357+
authconfig.Username = username
358+
authconfig.Password = password
359+
authconfig.Email = email
360+
cli.configFile.Configs[auth.IndexServerAddress()] = authconfig
355361

356-
body, statusCode, err := cli.call("POST", "/auth", cli.authConfig)
362+
body, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[auth.IndexServerAddress()])
357363
if statusCode == 401 {
358-
cli.authConfig.Username = ""
359-
cli.authConfig.Password = ""
360-
cli.authConfig.Email = ""
361-
auth.SaveConfig(cli.authConfig)
364+
delete(cli.configFile.Configs, auth.IndexServerAddress())
365+
auth.SaveConfig(cli.configFile)
362366
return err
363367
}
364368
if err != nil {
@@ -368,10 +372,10 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
368372
var out2 APIAuth
369373
err = json.Unmarshal(body, &out2)
370374
if err != nil {
371-
auth.LoadConfig(os.Getenv("HOME"))
375+
cli.configFile, _ = auth.LoadConfig(os.Getenv("HOME"))
372376
return err
373377
}
374-
auth.SaveConfig(cli.authConfig)
378+
auth.SaveConfig(cli.configFile)
375379
if out2.Status != "" {
376380
fmt.Fprintf(cli.out, "%s\n", out2.Status)
377381
}
@@ -802,10 +806,10 @@ func (cli *DockerCli) CmdPush(args ...string) error {
802806
// Custom repositories can have different rules, and we must also
803807
// allow pushing by image ID.
804808
if len(strings.SplitN(name, "/", 2)) == 1 {
805-
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.authConfig.Username, name)
809+
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.configFile.Configs[auth.IndexServerAddress()].Username, name)
806810
}
807811

808-
buf, err := json.Marshal(cli.authConfig)
812+
buf, err := json.Marshal(cli.configFile.Configs[auth.IndexServerAddress()])
809813
if err != nil {
810814
return err
811815
}
@@ -1410,11 +1414,11 @@ func (cli *DockerCli) CmdRun(args ...string) error {
14101414

14111415
func (cli *DockerCli) checkIfLogged(action string) error {
14121416
// If condition AND the login failed
1413-
if cli.authConfig.Username == "" {
1417+
if cli.configFile.Configs[auth.IndexServerAddress()].Username == "" {
14141418
if err := cli.CmdLogin(""); err != nil {
14151419
return err
14161420
}
1417-
if cli.authConfig.Username == "" {
1421+
if cli.configFile.Configs[auth.IndexServerAddress()].Username == "" {
14181422
return fmt.Errorf("Please login prior to %s. ('docker login')", action)
14191423
}
14201424
}
@@ -1670,11 +1674,11 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *Doc
16701674
err = out
16711675
}
16721676

1673-
authConfig, _ := auth.LoadConfig(os.Getenv("HOME"))
1677+
configFile, _ := auth.LoadConfig(os.Getenv("HOME"))
16741678
return &DockerCli{
16751679
proto: proto,
16761680
addr: addr,
1677-
authConfig: authConfig,
1681+
configFile: configFile,
16781682
in: in,
16791683
out: out,
16801684
err: err,
@@ -1686,7 +1690,7 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *Doc
16861690
type DockerCli struct {
16871691
proto string
16881692
addr string
1689-
authConfig *auth.AuthConfig
1693+
configFile *auth.ConfigFile
16901694
in io.ReadCloser
16911695
out io.Writer
16921696
err io.Writer

0 commit comments

Comments
 (0)