github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/internal/commands/credentials.go (about)

     1  package commands
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"io/ioutil"
     7  	"os"
     8  	"strings"
     9  
    10  	"github.com/deislabs/cnab-go/bundle"
    11  	"github.com/deislabs/cnab-go/credentials"
    12  	"github.com/docker/app/internal"
    13  	appstore "github.com/docker/app/internal/store"
    14  	"github.com/docker/cli/cli/command"
    15  	contextstore "github.com/docker/cli/cli/context/store"
    16  	"github.com/docker/distribution/reference"
    17  	"github.com/docker/docker/api/types"
    18  	"github.com/docker/docker/registry"
    19  	"github.com/pkg/errors"
    20  )
    21  
    22  type credentialSetOpt func(b *bundle.Bundle, creds credentials.Set) error
    23  
    24  func addNamedCredentialSets(credStore appstore.CredentialStore, namedCredentialsets []string) credentialSetOpt {
    25  	return func(_ *bundle.Bundle, creds credentials.Set) error {
    26  		for _, file := range namedCredentialsets {
    27  			var (
    28  				c   *credentials.CredentialSet
    29  				err error
    30  			)
    31  			// Check the credentialset locally first, then try in the credential store
    32  			if _, e := os.Stat(file); e == nil {
    33  				c, err = credentials.Load(file)
    34  			} else {
    35  				c, err = credStore.Read(file)
    36  				if os.IsNotExist(err) {
    37  					err = e
    38  				}
    39  			}
    40  			if err != nil {
    41  				return err
    42  			}
    43  			values, err := c.Resolve()
    44  			if err != nil {
    45  				return err
    46  			}
    47  			if err := creds.Merge(values); err != nil {
    48  				return err
    49  			}
    50  		}
    51  		return nil
    52  	}
    53  }
    54  
    55  func parseCommandlineCredential(c string) (string, string, error) {
    56  	split := strings.SplitN(c, "=", 2)
    57  	if len(split) != 2 || split[0] == "" {
    58  		return "", "", errors.Errorf("failed to parse %q as a credential name=value", c)
    59  	}
    60  	name := split[0]
    61  	value := split[1]
    62  	return name, value, nil
    63  }
    64  
    65  func addCredentials(strcreds []string) credentialSetOpt {
    66  	return func(_ *bundle.Bundle, creds credentials.Set) error {
    67  		for _, c := range strcreds {
    68  			name, value, err := parseCommandlineCredential(c)
    69  			if err != nil {
    70  				return err
    71  			}
    72  			if err := creds.Merge(credentials.Set{
    73  				name: value,
    74  			}); err != nil {
    75  				return err
    76  			}
    77  		}
    78  		return nil
    79  	}
    80  }
    81  
    82  func addDockerCredentials(contextName string, store contextstore.Store) credentialSetOpt {
    83  	// docker desktop contexts require some rewriting for being used within a container
    84  	store = internal.DockerDesktopAwareStore{Store: store}
    85  	return func(_ *bundle.Bundle, creds credentials.Set) error {
    86  		if contextName != "" {
    87  			data, err := ioutil.ReadAll(contextstore.Export(contextName, store))
    88  			if err != nil {
    89  				return err
    90  			}
    91  			creds[internal.CredentialDockerContextName] = string(data)
    92  		}
    93  		return nil
    94  	}
    95  }
    96  
    97  func addRegistryCredentials(shouldPopulate bool, dockerCli command.Cli) credentialSetOpt {
    98  	return func(b *bundle.Bundle, creds credentials.Set) error {
    99  		if _, ok := b.Credentials[internal.CredentialRegistryName]; !ok {
   100  			return nil
   101  		}
   102  
   103  		registryCreds := map[string]types.AuthConfig{}
   104  		if shouldPopulate {
   105  			for _, img := range b.Images {
   106  				named, err := reference.ParseNormalizedNamed(img.Image)
   107  				if err != nil {
   108  					return err
   109  				}
   110  				info, err := registry.ParseRepositoryInfo(named)
   111  				if err != nil {
   112  					return err
   113  				}
   114  				key := registry.GetAuthConfigKey(info.Index)
   115  				if _, ok := registryCreds[key]; !ok {
   116  					registryCreds[key] = command.ResolveAuthConfig(context.Background(), dockerCli, info.Index)
   117  				}
   118  			}
   119  		}
   120  		registryCredsJSON, err := json.Marshal(registryCreds)
   121  		if err != nil {
   122  			return err
   123  		}
   124  		creds[internal.CredentialRegistryName] = string(registryCredsJSON)
   125  		return nil
   126  	}
   127  }
   128  
   129  func prepareCredentialSet(b *bundle.Bundle, opts ...credentialSetOpt) (map[string]string, error) {
   130  	creds := map[string]string{}
   131  	for _, op := range opts {
   132  		if err := op(b, creds); err != nil {
   133  			return nil, err
   134  		}
   135  	}
   136  	return creds, nil
   137  }