github.com/criteo/command-launcher@v0.0.0-20230407142452-fb616f546e98/cmd/login.go (about) 1 package cmd 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "syscall" 8 9 "github.com/criteo/command-launcher/internal/command" 10 "github.com/criteo/command-launcher/internal/context" 11 "github.com/criteo/command-launcher/internal/helper" 12 "github.com/spf13/cobra" 13 "golang.org/x/crypto/ssh/terminal" 14 15 log "github.com/sirupsen/logrus" 16 ) 17 18 type LoginFlags struct { 19 username string 20 password string 21 } 22 23 var ( 24 loginFlags = LoginFlags{} 25 ) 26 27 func defaultUsername() string { 28 user, present := os.LookupEnv("USER") 29 if !present { 30 user, _ = os.LookupEnv("USERNAME") 31 } 32 33 return user 34 } 35 36 func AddLoginCmd(rootCmd *cobra.Command, appCtx context.LauncherContext, loginHook command.Command) { 37 loginCmd := &cobra.Command{ 38 Use: "login", 39 Short: "Login to use services", 40 Long: fmt.Sprintf(` 41 Login to use services. 42 43 You can specify your password from: 44 1. command option: --password (-p) 45 2. environment variable: %s 46 3. command line input 47 48 The credential will be stored in your system vault.`, appCtx.PasswordEnvVar()), 49 RunE: func(cmd *cobra.Command, args []string) error { 50 appCtx, _ := context.AppContext() 51 username := loginFlags.username 52 if username == "" { 53 username = os.Getenv(appCtx.UsernameEnvVar()) 54 if username == "" { 55 fmt.Printf("Please enter your user name: ") 56 nb, err := fmt.Scan(&username) 57 if err != nil { 58 return err 59 } 60 61 if nb != 1 { 62 return fmt.Errorf("invalid entries (expected only one argument)") 63 } 64 } 65 } 66 67 passwd := loginFlags.password 68 if passwd == "" { 69 passwd = os.Getenv(appCtx.PasswordEnvVar()) 70 if passwd == "" { 71 fmt.Printf("Please enter your password: ") 72 pass, err := terminal.ReadPassword(int(syscall.Stdin)) 73 if err != nil { 74 return err 75 } 76 passwd = string(pass) 77 } 78 } 79 80 fmt.Println() 81 82 // call system login hook if defined 83 if loginHook != nil { 84 log.Debug("calling login system hook") 85 _, hookOutput, err := loginHook.ExecuteWithOutput([]string{}, username, passwd) 86 if err != nil { 87 return err 88 } 89 credentials, err := parseLoginHookOutput(hookOutput) 90 if err != nil { 91 return err 92 } 93 for k, v := range credentials { 94 helper.SetSecret(k, v) 95 } 96 } else { 97 log.Debug("no login system hook registered, use default") 98 helper.SetUsername(username) 99 helper.SetPassword(passwd) 100 } 101 return nil 102 }, 103 } 104 loginCmd.Flags().StringVarP(&loginFlags.username, "user", "u", defaultUsername(), "User name") 105 loginCmd.Flags().StringVarP(&loginFlags.password, "password", "p", "", "User password") 106 107 rootCmd.AddCommand(loginCmd) 108 } 109 110 func parseLoginHookOutput(output string) (map[string]string, error) { 111 credentials := map[string]string{} 112 if err := json.Unmarshal([]byte(output), &credentials); err != nil { 113 return nil, err 114 } 115 return credentials, nil 116 }