auth.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright 2015 go-dockerclient authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package docker
  5. import (
  6. "bytes"
  7. "encoding/base64"
  8. "encoding/json"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "io/ioutil"
  13. "os"
  14. "path"
  15. "strings"
  16. )
  17. // ErrCannotParseDockercfg is the error returned by NewAuthConfigurations when the dockercfg cannot be parsed.
  18. var ErrCannotParseDockercfg = errors.New("Failed to read authentication from dockercfg")
  19. // AuthConfiguration represents authentication options to use in the PushImage
  20. // method. It represents the authentication in the Docker index server.
  21. type AuthConfiguration struct {
  22. Username string `json:"username,omitempty"`
  23. Password string `json:"password,omitempty"`
  24. Email string `json:"email,omitempty"`
  25. ServerAddress string `json:"serveraddress,omitempty"`
  26. }
  27. // AuthConfigurations represents authentication options to use for the
  28. // PushImage method accommodating the new X-Registry-Config header
  29. type AuthConfigurations struct {
  30. Configs map[string]AuthConfiguration `json:"configs"`
  31. }
  32. // AuthConfigurations119 is used to serialize a set of AuthConfigurations
  33. // for Docker API >= 1.19.
  34. type AuthConfigurations119 map[string]AuthConfiguration
  35. // dockerConfig represents a registry authentation configuration from the
  36. // .dockercfg file.
  37. type dockerConfig struct {
  38. Auth string `json:"auth"`
  39. Email string `json:"email"`
  40. }
  41. // NewAuthConfigurationsFromDockerCfg returns AuthConfigurations from the
  42. // ~/.dockercfg file.
  43. func NewAuthConfigurationsFromDockerCfg() (*AuthConfigurations, error) {
  44. var r io.Reader
  45. var err error
  46. p := path.Join(os.Getenv("HOME"), ".docker", "config.json")
  47. r, err = os.Open(p)
  48. if err != nil {
  49. p := path.Join(os.Getenv("HOME"), ".dockercfg")
  50. r, err = os.Open(p)
  51. if err != nil {
  52. return nil, err
  53. }
  54. }
  55. return NewAuthConfigurations(r)
  56. }
  57. // NewAuthConfigurations returns AuthConfigurations from a JSON encoded string in the
  58. // same format as the .dockercfg file.
  59. func NewAuthConfigurations(r io.Reader) (*AuthConfigurations, error) {
  60. var auth *AuthConfigurations
  61. confs, err := parseDockerConfig(r)
  62. if err != nil {
  63. return nil, err
  64. }
  65. auth, err = authConfigs(confs)
  66. if err != nil {
  67. return nil, err
  68. }
  69. return auth, nil
  70. }
  71. func parseDockerConfig(r io.Reader) (map[string]dockerConfig, error) {
  72. buf := new(bytes.Buffer)
  73. buf.ReadFrom(r)
  74. byteData := buf.Bytes()
  75. confsWrapper := struct {
  76. Auths map[string]dockerConfig `json:"auths"`
  77. }{}
  78. if err := json.Unmarshal(byteData, &confsWrapper); err == nil {
  79. if len(confsWrapper.Auths) > 0 {
  80. return confsWrapper.Auths, nil
  81. }
  82. }
  83. var confs map[string]dockerConfig
  84. if err := json.Unmarshal(byteData, &confs); err != nil {
  85. return nil, err
  86. }
  87. return confs, nil
  88. }
  89. // authConfigs converts a dockerConfigs map to a AuthConfigurations object.
  90. func authConfigs(confs map[string]dockerConfig) (*AuthConfigurations, error) {
  91. c := &AuthConfigurations{
  92. Configs: make(map[string]AuthConfiguration),
  93. }
  94. for reg, conf := range confs {
  95. data, err := base64.StdEncoding.DecodeString(conf.Auth)
  96. if err != nil {
  97. return nil, err
  98. }
  99. userpass := strings.SplitN(string(data), ":", 2)
  100. if len(userpass) != 2 {
  101. return nil, ErrCannotParseDockercfg
  102. }
  103. c.Configs[reg] = AuthConfiguration{
  104. Email: conf.Email,
  105. Username: userpass[0],
  106. Password: userpass[1],
  107. ServerAddress: reg,
  108. }
  109. }
  110. return c, nil
  111. }
  112. // AuthStatus returns the authentication status for Docker API versions >= 1.23.
  113. type AuthStatus struct {
  114. Status string `json:"Status,omitempty" yaml:"Status,omitempty"`
  115. IdentityToken string `json:"IdentityToken,omitempty" yaml:"IdentityToken,omitempty"`
  116. }
  117. // AuthCheck validates the given credentials. It returns nil if successful.
  118. //
  119. // For Docker API versions >= 1.23, the AuthStatus struct will be populated, otherwise it will be empty.`
  120. //
  121. // See https://goo.gl/6nsZkH for more details.
  122. func (c *Client) AuthCheck(conf *AuthConfiguration) (AuthStatus, error) {
  123. var authStatus AuthStatus
  124. if conf == nil {
  125. return authStatus, fmt.Errorf("conf is nil")
  126. }
  127. resp, err := c.do("POST", "/auth", doOptions{data: conf})
  128. if err != nil {
  129. return authStatus, err
  130. }
  131. defer resp.Body.Close()
  132. data, err := ioutil.ReadAll(resp.Body)
  133. if err != nil {
  134. return authStatus, err
  135. }
  136. if len(data) == 0 {
  137. return authStatus, nil
  138. }
  139. if err := json.Unmarshal(data, &authStatus); err != nil {
  140. return authStatus, err
  141. }
  142. return authStatus, nil
  143. }