github.com/jen20/docker@v1.13.1/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, helperSuffix string) Store { 26 name := remoteCredentialsPrefix + helperSuffix 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, err := c.listCredentialsInStore() 62 if err != nil { 63 return nil, err 64 } 65 66 // Emails are only stored in the file store. 67 // This call can be safely eliminated when emails are removed. 68 fileConfigs, _ := c.fileStore.GetAll() 69 70 authConfigs := make(map[string]types.AuthConfig) 71 for registry := range auths { 72 creds, err := c.getCredentialsFromStore(registry) 73 if err != nil { 74 return nil, err 75 } 76 ac, _ := fileConfigs[registry] // might contain Email 77 ac.Username = creds.Username 78 ac.Password = creds.Password 79 ac.IdentityToken = creds.IdentityToken 80 authConfigs[registry] = ac 81 } 82 83 return authConfigs, nil 84 } 85 86 // Store saves the given credentials in the file store. 87 func (c *nativeStore) Store(authConfig types.AuthConfig) error { 88 if err := c.storeCredentialsInStore(authConfig); err != nil { 89 return err 90 } 91 authConfig.Username = "" 92 authConfig.Password = "" 93 authConfig.IdentityToken = "" 94 95 // Fallback to old credential in plain text to save only the email 96 return c.fileStore.Store(authConfig) 97 } 98 99 // storeCredentialsInStore executes the command to store the credentials in the native store. 100 func (c *nativeStore) storeCredentialsInStore(config types.AuthConfig) error { 101 creds := &credentials.Credentials{ 102 ServerURL: config.ServerAddress, 103 Username: config.Username, 104 Secret: config.Password, 105 } 106 107 if config.IdentityToken != "" { 108 creds.Username = tokenUsername 109 creds.Secret = config.IdentityToken 110 } 111 112 return client.Store(c.programFunc, creds) 113 } 114 115 // getCredentialsFromStore executes the command to get the credentials from the native store. 116 func (c *nativeStore) getCredentialsFromStore(serverAddress string) (types.AuthConfig, error) { 117 var ret types.AuthConfig 118 119 creds, err := client.Get(c.programFunc, serverAddress) 120 if err != nil { 121 if credentials.IsErrCredentialsNotFound(err) { 122 // do not return an error if the credentials are not 123 // in the keyckain. Let docker ask for new credentials. 124 return ret, nil 125 } 126 return ret, err 127 } 128 129 if creds.Username == tokenUsername { 130 ret.IdentityToken = creds.Secret 131 } else { 132 ret.Password = creds.Secret 133 ret.Username = creds.Username 134 } 135 136 ret.ServerAddress = serverAddress 137 return ret, nil 138 } 139 140 // listCredentialsInStore returns a listing of stored credentials as a map of 141 // URL -> username. 142 func (c *nativeStore) listCredentialsInStore() (map[string]string, error) { 143 return client.List(c.programFunc) 144 }