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