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  }