142 lines
3.8 KiB
Go
142 lines
3.8 KiB
Go
// Copyright (c) OpenFaaS Project 2017. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
package commands
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/openfaas/faas-cli/config"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var (
|
|
username string
|
|
password string
|
|
passwordStdin bool
|
|
)
|
|
|
|
func init() {
|
|
loginCmd.Flags().StringVarP(&gateway, "gateway", "g", defaultGateway, "Gateway URL starting with http(s)://")
|
|
loginCmd.Flags().StringVarP(&username, "username", "u", "", "Gateway username")
|
|
loginCmd.Flags().StringVarP(&password, "password", "p", "", "Gateway password")
|
|
loginCmd.Flags().BoolVar(&passwordStdin, "password-stdin", false, "Reads the gateway password from stdin")
|
|
|
|
faasCmd.AddCommand(loginCmd)
|
|
}
|
|
|
|
var loginCmd = &cobra.Command{
|
|
Use: `login [--username USERNAME] [--password PASSWORD] [--gateway GATEWAY_URL]`,
|
|
Short: "Log in to OpenFaaS gateway",
|
|
Long: "Log in to OpenFaaS gateway.\nIf no gateway is specified, the default local one will be used.",
|
|
Example: ` faas-cli login -u user -p password --gateway http://127.0.0.1:8080
|
|
cat ~/faas_pass.txt | faas-cli login -u user --password-stdin --gateway https://openfaas.mydomain.com`,
|
|
RunE: runLogin,
|
|
}
|
|
|
|
func runLogin(cmd *cobra.Command, args []string) error {
|
|
|
|
if len(username) == 0 {
|
|
return fmt.Errorf("must provide --username or -u")
|
|
}
|
|
|
|
if len(password) > 0 {
|
|
fmt.Println("WARNING! Using --password is insecure, consider using: cat ~/faas_pass.txt | faas-cli login -u user --password-stdin")
|
|
if passwordStdin {
|
|
return fmt.Errorf("--password and --password-stdin are mutually exclusive")
|
|
}
|
|
|
|
if len(username) == 0 {
|
|
return fmt.Errorf("must provide --username with --password")
|
|
}
|
|
}
|
|
|
|
if passwordStdin {
|
|
if len(username) == 0 {
|
|
return fmt.Errorf("must provide --username with --password-stdin")
|
|
}
|
|
|
|
passwordStdin, err := ioutil.ReadAll(os.Stdin)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
password = strings.TrimSpace(string(passwordStdin))
|
|
}
|
|
|
|
password = strings.TrimSpace(password)
|
|
if len(password) == 0 {
|
|
return fmt.Errorf("must provide a non-empty password via --password or --password-stdin")
|
|
}
|
|
|
|
fmt.Println("Calling the OpenFaaS server to validate the credentials...")
|
|
|
|
gateway = getGatewayURL(gateway, "", "", os.Getenv("OPENFAAS_URL"))
|
|
|
|
if err := validateLogin(gateway, username, password); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := config.UpdateAuthConfig(gateway, username, password); err != nil {
|
|
return err
|
|
}
|
|
|
|
user, _, err := config.LookupAuthConfig(gateway)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("credentials saved for", user, gateway)
|
|
|
|
return nil
|
|
}
|
|
|
|
func validateLogin(gatewayURL string, user string, pass string) error {
|
|
tr := &http.Transport{
|
|
DisableKeepAlives: false,
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
}
|
|
client := &http.Client{
|
|
Transport: tr,
|
|
Timeout: time.Duration(5 * time.Second),
|
|
}
|
|
|
|
req, err := http.NewRequest("GET", gatewayURL+"/system/functions", nil)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid URL: %s", gatewayURL)
|
|
}
|
|
|
|
req.SetBasicAuth(user, pass)
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot connect to OpenFaaS on URL: %s", gatewayURL)
|
|
}
|
|
|
|
if res.Body != nil {
|
|
defer res.Body.Close()
|
|
}
|
|
|
|
if res.TLS == nil {
|
|
fmt.Println("WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.")
|
|
}
|
|
|
|
switch res.StatusCode {
|
|
case http.StatusOK:
|
|
return nil
|
|
case http.StatusUnauthorized:
|
|
return fmt.Errorf("unable to login, either username or password is incorrect")
|
|
default:
|
|
bytesOut, err := ioutil.ReadAll(res.Body)
|
|
if err == nil {
|
|
return fmt.Errorf("server returned unexpected status code: %d - %s", res.StatusCode, string(bytesOut))
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|