pkg/cmd/cli/secrets/basicauth.go
6f7bcc6e
 package secrets
 
 import (
 	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
 
661aaef1
 	"github.com/spf13/cobra"
 
6f7bcc6e
 	"k8s.io/kubernetes/pkg/api"
3dd75654
 	client "k8s.io/kubernetes/pkg/client/unversioned"
6f7bcc6e
 	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
6366c25e
 	kterm "k8s.io/kubernetes/pkg/util/term"
6f7bcc6e
 
6267dded
 	"github.com/openshift/origin/pkg/cmd/templates"
6366c25e
 	"github.com/openshift/origin/pkg/cmd/util/term"
6f7bcc6e
 )
 
6267dded
 // CreateBasicAuthSecretRecommendedCommandName represents name of subcommand for `oc secrets` command
 const CreateBasicAuthSecretRecommendedCommandName = "new-basicauth"
6f7bcc6e
 
6267dded
 var (
 	createBasicAuthSecretLong = templates.LongDesc(`
     Create a new basic authentication secret
6f7bcc6e
 
6267dded
     Basic authentication secrets are used to authenticate against SCM servers.
6f7bcc6e
 
6267dded
     When creating applications, you may have a SCM server that requires basic authentication - username, password.
     In order for the nodes to clone source code on your behalf, they have to have the credentials. You can provide
     this information by creating a 'basicauth' secret and attaching it to your service account.`)
6f7bcc6e
 
6267dded
 	createBasicAuthSecretExample = templates.Examples(`
     # If your basic authentication method requires only username and password or token, add it by using:
     %[1]s SECRET --username=USERNAME --password=PASSWORD
6f7bcc6e
 
6267dded
     # If your basic authentication method requires also CA certificate, add it by using:
     %[1]s SECRET --username=USERNAME --password=PASSWORD --ca-cert=FILENAME
6f7bcc6e
 
6267dded
     # If you do already have a .gitconfig file needed for authentication, you can create a gitconfig secret by using:
     %[2]s SECRET path/to/.gitconfig`)
6f7bcc6e
 )
 
 // CreateBasicAuthSecretOptions holds the credential needed to authenticate against SCM servers.
 type CreateBasicAuthSecretOptions struct {
 	SecretName      string
 	Username        string
 	Password        string
 	CertificatePath string
 	GitConfigPath   string
 
 	PromptForPassword bool
 
 	Reader io.Reader
 	Out    io.Writer
 
 	SecretsInterface client.SecretsInterface
 }
 
 // NewCmdCreateBasicAuthSecret implements the OpenShift cli secrets new-basicauth subcommand
 func NewCmdCreateBasicAuthSecret(name, fullName string, f *kcmdutil.Factory, reader io.Reader, out io.Writer, newSecretFullName, ocEditFullName string) *cobra.Command {
 	o := &CreateBasicAuthSecretOptions{
 		Out:    out,
 		Reader: reader,
 	}
 
 	cmd := &cobra.Command{
44164be6
 		Use:     fmt.Sprintf("%s SECRET --username=USERNAME --password=PASSWORD [--ca-cert=FILENAME] [--gitconfig=FILENAME]", name),
6f7bcc6e
 		Short:   "Create a new secret for basic authentication",
 		Long:    createBasicAuthSecretLong,
 		Example: fmt.Sprintf(createBasicAuthSecretExample, fullName, newSecretFullName, ocEditFullName),
 		Run: func(c *cobra.Command, args []string) {
 			if err := o.Complete(f, args); err != nil {
 				kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
 			}
 
 			if err := o.Validate(); err != nil {
 				kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
 			}
 
 			if len(kcmdutil.GetFlagString(c, "output")) != 0 {
 				secret, err := o.NewBasicAuthSecret()
 				kcmdutil.CheckErr(err)
 
59e6f9d2
 				mapper, _ := f.Object(false)
 				kcmdutil.CheckErr(f.PrintObject(c, mapper, secret, out))
6f7bcc6e
 				return
 			}
 
 			if err := o.CreateBasicAuthSecret(); err != nil {
 				kcmdutil.CheckErr(err)
 			}
 		},
 	}
 
 	cmd.Flags().StringVar(&o.Username, "username", "", "Username for Git authentication")
 	cmd.Flags().StringVar(&o.Password, "password", "", "Password or token for Git authentication")
 	cmd.Flags().StringVar(&o.CertificatePath, "ca-cert", "", "Path to a certificate file")
 	cmd.MarkFlagFilename("ca-cert")
a166f955
 	cmd.Flags().StringVar(&o.GitConfigPath, "gitconfig", "", "Path to a .gitconfig file")
6f7bcc6e
 	cmd.MarkFlagFilename("gitconfig")
a166f955
 	cmd.Flags().BoolVarP(&o.PromptForPassword, "prompt", "", false, "Prompt for password or token")
6f7bcc6e
 
 	kcmdutil.AddPrinterFlags(cmd)
 
 	return cmd
 }
 
 // CreateBasicAuthSecret saves created Secret structure and prints the secret name to the output on success.
 func (o *CreateBasicAuthSecretOptions) CreateBasicAuthSecret() error {
 	secret, err := o.NewBasicAuthSecret()
 	if err != nil {
 		return err
 	}
 
 	if _, err := o.SecretsInterface.Create(secret); err != nil {
 		return err
 	}
 
 	fmt.Fprintf(o.GetOut(), "secret/%s\n", secret.Name)
 	return nil
 }
 
 // NewBasicAuthSecret builds up the Secret structure containing secret name, type and data structure
 // containing desired credentials.
 func (o *CreateBasicAuthSecretOptions) NewBasicAuthSecret() (*api.Secret, error) {
 	secret := &api.Secret{}
 	secret.Name = o.SecretName
 	secret.Type = api.SecretTypeOpaque
 	secret.Data = map[string][]byte{}
 
 	if len(o.Username) != 0 {
 		secret.Data[SourceUsername] = []byte(o.Username)
 	}
 
 	if len(o.Password) != 0 {
 		secret.Data[SourcePassword] = []byte(o.Password)
 	}
 
 	if len(o.CertificatePath) != 0 {
 		caContent, err := ioutil.ReadFile(o.CertificatePath)
 		if err != nil {
 			return nil, err
 		}
 		secret.Data[SourceCertificate] = caContent
 	}
 
 	if len(o.GitConfigPath) != 0 {
 		gitConfig, err := ioutil.ReadFile(o.GitConfigPath)
 		if err != nil {
 			return nil, err
 		}
 		secret.Data[SourceGitConfig] = gitConfig
 	}
 
 	return secret, nil
 }
 
 // Complete fills CreateBasicAuthSecretOptions fields with data and checks for mutual exclusivity
 // between flags from different option groups.
 func (o *CreateBasicAuthSecretOptions) Complete(f *kcmdutil.Factory, args []string) error {
 	if len(args) != 1 {
 		return errors.New("must have exactly one argument: secret name")
 	}
 	o.SecretName = args[0]
 
44164be6
 	if o.PromptForPassword {
 		if len(o.Password) != 0 {
 			return errors.New("must provide either --prompt or --password flag")
 		}
6366c25e
 		if !kterm.IsTerminal(o.Reader) {
44164be6
 			return errors.New("provided reader is not a terminal")
 		}
 
6366c25e
 		o.Password = term.PromptForPasswordString(o.Reader, o.Out, "Password: ")
44164be6
 		if len(o.Password) == 0 {
 			return errors.New("password must be provided")
 		}
 	}
 
6f7bcc6e
 	if f != nil {
 		client, err := f.Client()
 		if err != nil {
 			return err
 		}
 		namespace, _, err := f.DefaultNamespace()
 		if err != nil {
 			return err
 		}
 		o.SecretsInterface = client.Secrets(namespace)
 	}
 
 	return nil
 }
 
 // Validate check if all necessary fields from CreateBasicAuthSecretOptions are present.
 func (o CreateBasicAuthSecretOptions) Validate() error {
 	if len(o.SecretName) == 0 {
 		return errors.New("basic authentication secret name must be present")
 	}
 
44164be6
 	if len(o.Username) == 0 && len(o.Password) == 0 {
 		return errors.New("must provide basic authentication credentials")
6f7bcc6e
 	}
 
 	return nil
 }
 
 // GetOut check if the CreateBasicAuthSecretOptions Out Writer is set. Returns it if the Writer
 // is present, if not returns Writer on which all Write calls succeed without doing anything.
 func (o CreateBasicAuthSecretOptions) GetOut() io.Writer {
 	if o.Out == nil {
 		return ioutil.Discard
 	}
 
 	return o.Out
 }