Skip to content

Commit

Permalink
Merge pull request #2265 from influxdb/cli-auth-fix-2239
Browse files Browse the repository at this point in the history
Fix auth for CLI
  • Loading branch information
toddboom committed Apr 13, 2015
2 parents db15e22 + 96a3038 commit 6731ba4
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 75 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- [#2257](https://github.com/influxdb/influxdb/pull/2257): Add "snapshotting" pseudo state & log entry cache.
- [#2261](https://github.com/influxdb/influxdb/pull/2261): Support int64 value types.
- [#2191](https://github.com/influxdb/influxdb/pull/2191): Case-insensitive check for "fill"
- [#2265](https://github.com/influxdb/influxdb/pull/2265): Fix auth for CLI.

## v0.9.0-rc23 [2015-04-11]

Expand Down
29 changes: 23 additions & 6 deletions client/influxdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,17 @@ func NewClient(c Config) (*Client, error) {
return &client, nil
}

// SetAuth will update the username and passwords
func (c *Client) SetAuth(u, p string) {
c.username = u
c.password = p
}

// Query sends a command to the server and returns the Response
func (c *Client) Query(q Query) (*Response, error) {
u := c.url

u.Path = "query"
if c.username != "" {
u.User = url.UserPassword(c.username, c.password)
}
values := u.Query()
values.Set("q", q.Command)
values.Set("db", q.Database)
Expand All @@ -72,6 +75,10 @@ func (c *Client) Query(q Query) (*Response, error) {
return nil, err
}
req.Header.Set("User-Agent", c.userAgent)
if c.username != "" {
req.SetBasicAuth(c.username, c.password)
}

resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
Expand All @@ -81,9 +88,19 @@ func (c *Client) Query(q Query) (*Response, error) {
var response Response
dec := json.NewDecoder(resp.Body)
dec.UseNumber()
err = dec.Decode(&response)
if err != nil {
return nil, err
decErr := dec.Decode(&response)

// ignore this error if we got an invalid status code
if decErr != nil && decErr.Error() == "EOF" && resp.StatusCode != http.StatusOK {
decErr = nil
}
// If we got a valid decode error, send that back
if decErr != nil {
return nil, decErr
}
// If we don't have an error in our json response, and didn't get statusOK, then send back an error
if resp.StatusCode != http.StatusOK && response.Error() == nil {
return &response, fmt.Errorf("received status code %d from server", resp.StatusCode)
}
return &response, nil
}
Expand Down
58 changes: 36 additions & 22 deletions cmd/influx/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func main() {
}

if c.Execute != "" {
if err := c.executeQuery(c.Execute); err != nil {
if err := c.ExecuteQuery(c.Execute); err != nil {
os.Exit(1)
} else {
os.Exit(0)
Expand Down Expand Up @@ -140,13 +140,13 @@ func (c *CommandLine) ParseCommand(cmd string) bool {
// signal the program to exit
return false
case strings.HasPrefix(lcmd, "gopher"):
gopher()
c.gopher()
case strings.HasPrefix(lcmd, "connect"):
c.connect(cmd)
case strings.HasPrefix(lcmd, "auth"):
c.SetAuth()
c.SetAuth(cmd)
case strings.HasPrefix(lcmd, "help"):
help()
c.help()
case strings.HasPrefix(lcmd, "format"):
c.SetFormat(cmd)
case strings.HasPrefix(lcmd, "settings"):
Expand All @@ -163,7 +163,7 @@ func (c *CommandLine) ParseCommand(cmd string) bool {
case lcmd == "":
break
default:
c.executeQuery(cmd)
c.ExecuteQuery(cmd)
}
return true
}
Expand Down Expand Up @@ -205,9 +205,6 @@ func (c *CommandLine) connect(cmd string) {
} else {
u.Host = c.Host
}
if c.Username != "" {
u.User = url.UserPassword(c.Username, c.Password)
}
cl, err := client.NewClient(
client.Config{
URL: u,
Expand All @@ -230,19 +227,36 @@ func (c *CommandLine) connect(cmd string) {
}
}

func (c *CommandLine) SetAuth() {
u, e := c.Line.Prompt("username: ")
if e != nil {
fmt.Printf("Unable to process input: %s", e)
return
func (c *CommandLine) SetAuth(cmd string) {
// If they pass in the entire command, we should parse it
// auth <username> <password>
args := strings.Fields(cmd)
if len(args) == 3 {
args = args[1:]
} else {
args = []string{}
}
c.Username = strings.TrimSpace(u)
p, e := c.Line.PasswordPrompt("password: ")
if e != nil {
fmt.Printf("Unable to process input: %s", e)
return

if len(args) == 2 {
c.Username = args[0]
c.Password = args[1]
} else {
u, e := c.Line.Prompt("username: ")
if e != nil {
fmt.Printf("Unable to process input: %s", e)
return
}
c.Username = strings.TrimSpace(u)
p, e := c.Line.PasswordPrompt("password: ")
if e != nil {
fmt.Printf("Unable to process input: %s", e)
return
}
c.Password = p
}
c.Password = p

// Update the client as well
c.Client.SetAuth(c.Username, c.Password)
}

func (c *CommandLine) use(cmd string) {
Expand Down Expand Up @@ -286,7 +300,7 @@ func (c *CommandLine) dump() error {
return nil
}

func (c *CommandLine) executeQuery(query string) error {
func (c *CommandLine) ExecuteQuery(query string) error {
response, err := c.Client.Query(client.Query{Command: query, Database: c.Database})
if err != nil {
fmt.Printf("ERR: %s\n", err)
Expand Down Expand Up @@ -473,7 +487,7 @@ func (c *CommandLine) Settings() {
w.Flush()
}

func help() {
func (c *CommandLine) help() {
fmt.Println(`Usage:
connect <host:port> connect to another node
auth prompt for username and password
Expand All @@ -494,7 +508,7 @@ func help() {
`)
}

func gopher() {
func (c *CommandLine) gopher() {
fmt.Println(`
.-::-::://:-::- .:/++/'
'://:-''/oo+//++o+/.://o- ./+:
Expand Down
161 changes: 161 additions & 0 deletions cmd/influx/main_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package main_test

import (
"fmt"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"testing"

"github.com/influxdb/influxdb/client"
main "github.com/influxdb/influxdb/cmd/influx"
influxd "github.com/influxdb/influxdb/cmd/influxd"
)

func TestParseCommand_CommandsExist(t *testing.T) {
Expand Down Expand Up @@ -75,3 +82,157 @@ func TestParseCommand_Use(t *testing.T) {
}
}
}

func TestQuery_NoAuth(t *testing.T) {
if testing.Short() {
t.Skip("skipping TestQuery_NoAuth")
}

// Create root path to server.
// Defer it to clean up for successful tests
path := tempfile()
defer os.Remove(path)

config, _ := influxd.NewTestConfig()

// Start server.
node, err := newNode(config, path)
if err != nil {
t.Fatal(err)
}

c := main.CommandLine{
Format: "column",
}

u := url.URL{
Scheme: "http",
Host: fmt.Sprintf("%s:%d", "localhost", 8086),
}
cl, err := client.NewClient(
client.Config{
URL: u,
})

if err != nil {
t.Fatal(err)
}

c.Client = cl

ok := c.ParseCommand("CREATE USER admin WITH PASSWORD 'password'")
if !ok {
t.Fatal("Failed to create user")
}
node.Close()
}

func TestQuery_Auth(t *testing.T) {
if testing.Short() {
t.Skip("skipping TestQuery_Auth")
}

// Create root path to server.
// Defer it to clean up for successful tests
path := tempfile()
defer os.Remove(path)

// Create the cli
c := main.CommandLine{Format: "column"}
cl, err := client.NewClient(
client.Config{
URL: url.URL{
Scheme: "http",
Host: fmt.Sprintf("%s:%d", "localhost", 8086),
}})
if err != nil {
t.Fatal(err)
}

c.Client = cl

// spin up a server
config, _ := influxd.NewTestConfig()
config.Authentication.Enabled = true
node, err := newNode(config, path)
if err != nil {
t.Fatal(err)
}

// Check to make sure we can't do anything
err = c.ExecuteQuery("CREATE USER admin WITH PASSWORD 'password'")
if err == nil {
t.Fatal("Should have failed to create user")
}

// spin down server
node.Close()

// disable auth and spin back up
config.Authentication.Enabled = false
node, err = newNode(config, path)
if err != nil {
t.Fatal(err)
}

// create the user
err = c.ExecuteQuery("CREATE USER admin WITH PASSWORD 'password'")
if err != nil {
t.Fatalf("Should have created user: %s\n", err)
}
// Make cluster admin
err = c.ExecuteQuery("GRANT ALL PRIVILEGES TO admin")
if err != nil {
t.Fatalf("Should have made cluster admin: %s\n", err)
}

// spin down again
node.Close()

// enable auth, spin back up
config.Authentication.Enabled = true
node, err = newNode(config, path)
if err != nil {
t.Fatal(err)
}

// Check to make sure we still can't do anything
err = c.ExecuteQuery("CREATE USER admin WITH PASSWORD 'password'")
if err == nil {
t.Fatal("Should have failed to create user")
}

c.SetAuth("auth admin password")

// Check to make sure we can't do anything
err = c.ExecuteQuery("CREATE DATABASE foo")
if err != nil {
t.Fatalf("Failed to create database: %s\n", err)
}
node.Close()
}

// tempfile returns a temporary path.
func tempfile() string {
f, _ := ioutil.TempFile("", "influxdb-")
path := f.Name()
f.Close()
os.Remove(path)
return path
}

func newNode(config *influxd.Config, path string) (*influxd.Node, error) {
config.Broker.Dir = filepath.Join(path, "broker")
config.Data.Dir = filepath.Join(path, "data")

// Start server.
cmd := influxd.NewRunCommand()

node := cmd.Open(config, "")
if node.Broker == nil {
return nil, fmt.Errorf("cannot run broker")
} else if node.DataNode == nil {
return nil, fmt.Errorf("cannot run server")
}
return node, nil
}
18 changes: 15 additions & 3 deletions cmd/influxd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,27 @@ func execConfig(args []string) {
}

var (
configPath = fs.String("config", "", "")
hostname = fs.String("hostname", "", "")
configPath string
hostname string
)
fs.StringVar(&configPath, "config", "", "")
fs.StringVar(&hostname, "hostname", "", "")
fs.Parse(args)

config, err := parseConfig(*configPath, *hostname)
var config *Config
var err error
if configPath == "" {
config, err = NewTestConfig()
} else {
config, err = ParseConfigFile(configPath)
}
if err != nil {
log.Fatalf("parse config: %s", err)
}
// Override config properties.
if hostname != "" {
config.Hostname = hostname
}

config.Write(os.Stdout)
}
Expand Down
Loading

0 comments on commit 6731ba4

Please sign in to comment.