From a6052d13e387de2134e894db20f09018f09bdf23 Mon Sep 17 00:00:00 2001 From: Maxime Caruchet Date: Fri, 10 Aug 2018 10:29:58 +0200 Subject: [PATCH] feat: add basic auth support for tatcli (#74) --- client.go | 15 +++++++++++++++ tatcli/internal/config.go | 3 +++ tatcli/internal/engine.go | 31 +++++++++++++++++++++++++++++++ tatcli/main.go | 2 ++ tatcli/ui/cmd.go | 6 ++++++ 5 files changed, 57 insertions(+) diff --git a/client.go b/client.go index 3fd9561..e4931e0 100644 --- a/client.go +++ b/client.go @@ -18,6 +18,8 @@ import ( type Client struct { username string password string + basicAuthUsername string + basicAuthPassword string url string referer string requestTimeout time.Duration @@ -29,6 +31,8 @@ type Client struct { type Options struct { Username string Password string + BasicAuthUsername string + BasicAuthPassword string URL string Referer string RequestTimeout time.Duration @@ -79,6 +83,12 @@ func NewClient(opts Options) (*Client, error) { c.maxTries = opts.MaxTries } + // Set basic auth credentials only if the username AND the password options have been provided + if opts.BasicAuthUsername != "" && opts.BasicAuthPassword != "" { + c.basicAuthUsername = opts.BasicAuthUsername + c.basicAuthPassword = opts.BasicAuthPassword + } + return c, nil } @@ -87,6 +97,11 @@ func (c *Client) initHeaders(req *http.Request) error { return ErrClientNotInitiliazed } + // If the client is configured with basic auth credentials, add them to the request + if c.basicAuthUsername != "" && c.basicAuthPassword != "" { + req.SetBasicAuth(c.basicAuthUsername, c.basicAuthPassword) + } + req.Header.Set(TatHeaderUsername, c.username) req.Header.Set(TatHeaderPassword, c.password) req.Header.Set(TatHeaderXTatRefererLower, c.referer) diff --git a/tatcli/internal/config.go b/tatcli/internal/config.go index 9972ff6..5f30037 100644 --- a/tatcli/internal/config.go +++ b/tatcli/internal/config.go @@ -26,6 +26,9 @@ var ( // ShowStackTrace prints stacktrace on tatcli panic ShowStackTrace bool + // BasicAuth enables basic auth support + BasicAuth bool + // URL of tat engine URL string diff --git a/tatcli/internal/engine.go b/tatcli/internal/engine.go index f95f55f..813bc2e 100644 --- a/tatcli/internal/engine.go +++ b/tatcli/internal/engine.go @@ -9,6 +9,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/ovh/tat" "github.com/spf13/viper" + "golang.org/x/crypto/ssh/terminal" ) var instance *tat.Client @@ -20,10 +21,38 @@ func Client() *tat.Client { return instance } + // Init basic auth credentials + var basicAuthUsername, basicAuthPassword string + if viper.GetBool("basic-auth") { + // Only try to get basic auth credentials when --basic-auth flag is set + + // First, try to get basic auth credentials from the configuration file + basicAuthUsername = viper.GetString("basicAuthUsername") + basicAuthPassword = viper.GetString("basicAuthPassword") + + // If the username is not defined, ask the user to provide it + if basicAuthUsername == "" { + fmt.Println("No basic auth username found") + fmt.Print("Please enter your username: ") + fmt.Scan(&basicAuthUsername) + } + + // If the password is not defined, ask the user to provide it + if basicAuthPassword == "" { + fmt.Printf("No basic auth password found for username %v\n", basicAuthUsername) + fmt.Printf("Please enter the password for username %v: ", basicAuthUsername) + pwd, errReadPassword := terminal.ReadPassword(0) + Check(errReadPassword) + basicAuthPassword = string(pwd) + } + } + tc, err := tat.NewClient(tat.Options{ URL: viper.GetString("url"), Username: viper.GetString("username"), Password: viper.GetString("password"), + BasicAuthUsername: basicAuthUsername, // Always send the basic auth credentials (if --basic-auth is not set, the value will be empty) + BasicAuthPassword: basicAuthPassword, // Always send the basic auth credentials (if --basic-auth is not set, the value will be empty) Referer: "tatcli.v." + tat.Version, SSLInsecureSkipVerify: viper.GetBool("sslInsecureSkipVerify"), }) @@ -38,6 +67,8 @@ func Client() *tat.Client { tat.IsDebug = true } + // Set the instance for future use and return it + instance = tc return tc } diff --git a/tatcli/main.go b/tatcli/main.go index ecff05c..8281b9b 100644 --- a/tatcli/main.go +++ b/tatcli/main.go @@ -35,6 +35,7 @@ func main() { rootCmd.PersistentFlags().BoolVarP(&internal.Pretty, "pretty", "t", false, "Pretty Print Json Output") rootCmd.PersistentFlags().BoolVarP(&internal.ShowStackTrace, "showStackTrace", "", false, "Show Stack Trace if tatcli panic") rootCmd.PersistentFlags().BoolVarP(&internal.SSLInsecureSkipVerify, "sslInsecureSkipVerify", "k", false, "Skip certificate check with SSL connection") + rootCmd.PersistentFlags().BoolVarP(&internal.BasicAuth, "basic-auth", "", false, "Enable basic auth support") rootCmd.PersistentFlags().StringVarP(&internal.URL, "url", "", "", "URL Tat Engine, facultative if you have a "+home+"/.tatcli/config.json file") rootCmd.PersistentFlags().StringVarP(&internal.TatwebuiURL, "tatwebui-url", "", "", "URL of Tat WebUI, facultative") rootCmd.PersistentFlags().StringVarP(&internal.Username, "username", "u", "", "username, facultative if you have a "+home+"/.tatcli/config.json file") @@ -45,6 +46,7 @@ func main() { viper.BindPFlag("tatwebui-url", rootCmd.PersistentFlags().Lookup("tatwebui-url")) viper.BindPFlag("username", rootCmd.PersistentFlags().Lookup("username")) viper.BindPFlag("password", rootCmd.PersistentFlags().Lookup("password")) + viper.BindPFlag("basic-auth", rootCmd.PersistentFlags().Lookup("basic-auth")) viper.BindPFlag("sslInsecureSkipVerify", rootCmd.PersistentFlags().Lookup("sslInsecureSkipVerify")) if err := rootCmd.Execute(); err != nil { diff --git a/tatcli/ui/cmd.go b/tatcli/ui/cmd.go index 0e64251..cce2943 100644 --- a/tatcli/ui/cmd.go +++ b/tatcli/ui/cmd.go @@ -2,6 +2,7 @@ package ui import ( "github.com/gizak/termui" + "github.com/ovh/tat/tatcli/internal" "github.com/spf13/cobra" ) @@ -25,6 +26,11 @@ Example: func runUI(args []string) { ui := &tatui{} + + // This forces a client init before starting the UI + // This way, if the client needs to ask for credentials, it will be done now + internal.Client().Version() + ui.init(args) ui.draw(0)