native_store.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package credentials
  2. import (
  3. "github.com/docker/docker-credential-helpers/client"
  4. "github.com/docker/docker-credential-helpers/credentials"
  5. "github.com/docker/docker/cliconfig/configfile"
  6. "github.com/docker/engine-api/types"
  7. )
  8. const (
  9. remoteCredentialsPrefix = "docker-credential-"
  10. tokenUsername = "<token>"
  11. )
  12. // nativeStore implements a credentials store
  13. // using native keychain to keep credentials secure.
  14. // It piggybacks into a file store to keep users' emails.
  15. type nativeStore struct {
  16. programFunc client.ProgramFunc
  17. fileStore Store
  18. }
  19. // NewNativeStore creates a new native store that
  20. // uses a remote helper program to manage credentials.
  21. func NewNativeStore(file *configfile.ConfigFile) Store {
  22. name := remoteCredentialsPrefix + file.CredentialsStore
  23. return &nativeStore{
  24. programFunc: client.NewShellProgramFunc(name),
  25. fileStore: NewFileStore(file),
  26. }
  27. }
  28. // Erase removes the given credentials from the native store.
  29. func (c *nativeStore) Erase(serverAddress string) error {
  30. if err := client.Erase(c.programFunc, serverAddress); err != nil {
  31. return err
  32. }
  33. // Fallback to plain text store to remove email
  34. return c.fileStore.Erase(serverAddress)
  35. }
  36. // Get retrieves credentials for a specific server from the native store.
  37. func (c *nativeStore) Get(serverAddress string) (types.AuthConfig, error) {
  38. // load user email if it exist or an empty auth config.
  39. auth, _ := c.fileStore.Get(serverAddress)
  40. creds, err := c.getCredentialsFromStore(serverAddress)
  41. if err != nil {
  42. return auth, err
  43. }
  44. auth.Username = creds.Username
  45. auth.IdentityToken = creds.IdentityToken
  46. auth.Password = creds.Password
  47. return auth, nil
  48. }
  49. // GetAll retrieves all the credentials from the native store.
  50. func (c *nativeStore) GetAll() (map[string]types.AuthConfig, error) {
  51. auths, _ := c.fileStore.GetAll()
  52. for s, ac := range auths {
  53. creds, _ := c.getCredentialsFromStore(s)
  54. ac.Username = creds.Username
  55. ac.Password = creds.Password
  56. ac.IdentityToken = creds.IdentityToken
  57. auths[s] = ac
  58. }
  59. return auths, nil
  60. }
  61. // Store saves the given credentials in the file store.
  62. func (c *nativeStore) Store(authConfig types.AuthConfig) error {
  63. if err := c.storeCredentialsInStore(authConfig); err != nil {
  64. return err
  65. }
  66. authConfig.Username = ""
  67. authConfig.Password = ""
  68. authConfig.IdentityToken = ""
  69. // Fallback to old credential in plain text to save only the email
  70. return c.fileStore.Store(authConfig)
  71. }
  72. // storeCredentialsInStore executes the command to store the credentials in the native store.
  73. func (c *nativeStore) storeCredentialsInStore(config types.AuthConfig) error {
  74. creds := &credentials.Credentials{
  75. ServerURL: config.ServerAddress,
  76. Username: config.Username,
  77. Secret: config.Password,
  78. }
  79. if config.IdentityToken != "" {
  80. creds.Username = tokenUsername
  81. creds.Secret = config.IdentityToken
  82. }
  83. return client.Store(c.programFunc, creds)
  84. }
  85. // getCredentialsFromStore executes the command to get the credentials from the native store.
  86. func (c *nativeStore) getCredentialsFromStore(serverAddress string) (types.AuthConfig, error) {
  87. var ret types.AuthConfig
  88. creds, err := client.Get(c.programFunc, serverAddress)
  89. if err != nil {
  90. if credentials.IsErrCredentialsNotFound(err) {
  91. // do not return an error if the credentials are not
  92. // in the keyckain. Let docker ask for new credentials.
  93. return ret, nil
  94. }
  95. return ret, err
  96. }
  97. if creds.Username == tokenUsername {
  98. ret.IdentityToken = creds.Secret
  99. } else {
  100. ret.Password = creds.Secret
  101. ret.Username = creds.Username
  102. }
  103. ret.ServerAddress = serverAddress
  104. return ret, nil
  105. }