123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- package credentials
- import (
- "github.com/docker/docker-credential-helpers/client"
- "github.com/docker/docker-credential-helpers/credentials"
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/cli/config/configfile"
- )
- const (
- remoteCredentialsPrefix = "docker-credential-"
- tokenUsername = "<token>"
- )
- // nativeStore implements a credentials store
- // using native keychain to keep credentials secure.
- // It piggybacks into a file store to keep users' emails.
- type nativeStore struct {
- programFunc client.ProgramFunc
- fileStore Store
- }
- // NewNativeStore creates a new native store that
- // uses a remote helper program to manage credentials.
- func NewNativeStore(file *configfile.ConfigFile, helperSuffix string) Store {
- name := remoteCredentialsPrefix + helperSuffix
- return &nativeStore{
- programFunc: client.NewShellProgramFunc(name),
- fileStore: NewFileStore(file),
- }
- }
- // Erase removes the given credentials from the native store.
- func (c *nativeStore) Erase(serverAddress string) error {
- if err := client.Erase(c.programFunc, serverAddress); err != nil {
- return err
- }
- // Fallback to plain text store to remove email
- return c.fileStore.Erase(serverAddress)
- }
- // Get retrieves credentials for a specific server from the native store.
- func (c *nativeStore) Get(serverAddress string) (types.AuthConfig, error) {
- // load user email if it exist or an empty auth config.
- auth, _ := c.fileStore.Get(serverAddress)
- creds, err := c.getCredentialsFromStore(serverAddress)
- if err != nil {
- return auth, err
- }
- auth.Username = creds.Username
- auth.IdentityToken = creds.IdentityToken
- auth.Password = creds.Password
- return auth, nil
- }
- // GetAll retrieves all the credentials from the native store.
- func (c *nativeStore) GetAll() (map[string]types.AuthConfig, error) {
- auths, err := c.listCredentialsInStore()
- if err != nil {
- return nil, err
- }
- // Emails are only stored in the file store.
- // This call can be safely eliminated when emails are removed.
- fileConfigs, _ := c.fileStore.GetAll()
- authConfigs := make(map[string]types.AuthConfig)
- for registry := range auths {
- creds, err := c.getCredentialsFromStore(registry)
- if err != nil {
- return nil, err
- }
- ac, _ := fileConfigs[registry] // might contain Email
- ac.Username = creds.Username
- ac.Password = creds.Password
- ac.IdentityToken = creds.IdentityToken
- authConfigs[registry] = ac
- }
- return authConfigs, nil
- }
- // Store saves the given credentials in the file store.
- func (c *nativeStore) Store(authConfig types.AuthConfig) error {
- if err := c.storeCredentialsInStore(authConfig); err != nil {
- return err
- }
- authConfig.Username = ""
- authConfig.Password = ""
- authConfig.IdentityToken = ""
- // Fallback to old credential in plain text to save only the email
- return c.fileStore.Store(authConfig)
- }
- // storeCredentialsInStore executes the command to store the credentials in the native store.
- func (c *nativeStore) storeCredentialsInStore(config types.AuthConfig) error {
- creds := &credentials.Credentials{
- ServerURL: config.ServerAddress,
- Username: config.Username,
- Secret: config.Password,
- }
- if config.IdentityToken != "" {
- creds.Username = tokenUsername
- creds.Secret = config.IdentityToken
- }
- return client.Store(c.programFunc, creds)
- }
- // getCredentialsFromStore executes the command to get the credentials from the native store.
- func (c *nativeStore) getCredentialsFromStore(serverAddress string) (types.AuthConfig, error) {
- var ret types.AuthConfig
- creds, err := client.Get(c.programFunc, serverAddress)
- if err != nil {
- if credentials.IsErrCredentialsNotFound(err) {
- // do not return an error if the credentials are not
- // in the keyckain. Let docker ask for new credentials.
- return ret, nil
- }
- return ret, err
- }
- if creds.Username == tokenUsername {
- ret.IdentityToken = creds.Secret
- } else {
- ret.Password = creds.Secret
- ret.Username = creds.Username
- }
- ret.ServerAddress = serverAddress
- return ret, nil
- }
- // listCredentialsInStore returns a listing of stored credentials as a map of
- // URL -> username.
- func (c *nativeStore) listCredentialsInStore() (map[string]string, error) {
- return client.List(c.programFunc)
- }
|