Skip to content

Commit

Permalink
Merge pull request #728 from influxdata/feature/go-insecure-tls
Browse files Browse the repository at this point in the history
Add insecureSkipVerify option to source to accept all influxdb certs
  • Loading branch information
goller authored Jan 5, 2017
2 parents d63ecdf + 18b7dd1 commit c852618
Show file tree
Hide file tree
Showing 11 changed files with 237 additions and 112 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
1. [#718](https://github.com/influxdata/chronograf/issues/718): Fix bug that stopped apps from displaying

### Upcoming Features
1. [#660](https://github.com/influxdata/chronograf/issues/660): Add option to accept any certificate from InfluxDB.

## v1.1.0-beta4 [2016-12-30]

Expand Down
18 changes: 10 additions & 8 deletions bolt/internal/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,15 @@ func UnmarshalExploration(data []byte, e *chronograf.Exploration) error {
// MarshalSource encodes a source to binary protobuf format.
func MarshalSource(s chronograf.Source) ([]byte, error) {
return proto.Marshal(&Source{
ID: int64(s.ID),
Name: s.Name,
Type: s.Type,
Username: s.Username,
Password: s.Password,
URL: s.URL,
Default: s.Default,
Telegraf: s.Telegraf,
ID: int64(s.ID),
Name: s.Name,
Type: s.Type,
Username: s.Username,
Password: s.Password,
URL: s.URL,
InsecureSkipVerify: s.InsecureSkipVerify,
Default: s.Default,
Telegraf: s.Telegraf,
})
}

Expand All @@ -68,6 +69,7 @@ func UnmarshalSource(data []byte, s *chronograf.Source) error {
s.Username = pb.Username
s.Password = pb.Password
s.URL = pb.URL
s.InsecureSkipVerify = pb.InsecureSkipVerify
s.Default = pb.Default
s.Telegraf = pb.Telegraf
return nil
Expand Down
180 changes: 92 additions & 88 deletions bolt/internal/internal.pb.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions bolt/internal/internal.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ message Source {
string URL = 6; // URL are the connections to the source
bool Default = 7; // Flags an exploration as the default.
string Telegraf = 8; // Telegraf is the db telegraf is written to. By default it is "telegraf"
bool InsecureSkipVerify = 9; // InsecureSkipVerify accepts any certificate from the influx server
}

message Dashboard {
Expand Down
10 changes: 10 additions & 0 deletions bolt/internal/internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ func TestMarshalSource(t *testing.T) {
} else if !reflect.DeepEqual(v, vv) {
t.Fatalf("source protobuf copy error: got %#v, expected %#v", vv, v)
}

// Test if the new insecureskipverify works
v.InsecureSkipVerify = true
if buf, err := internal.MarshalSource(v); err != nil {
t.Fatal(err)
} else if err := internal.UnmarshalSource(buf, &vv); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(v, vv) {
t.Fatalf("source protobuf copy error: got %#v, expected %#v", vv, v)
}
}

func TestMarshalServer(t *testing.T) {
Expand Down
22 changes: 17 additions & 5 deletions bolt/sources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ func TestSourceStore(t *testing.T) {
URL: "toyota-hilux.lyon-estates.local",
Default: true,
},
chronograf.Source{
Name: "HipToBeSquare",
Type: "influx",
Username: "calvinklein",
Password: "chuck b3rry",
URL: "https://toyota-hilux.lyon-estates.local",
InsecureSkipVerify: true,
Default: false,
},
}

ctx := context.Background()
Expand Down Expand Up @@ -94,7 +103,7 @@ func TestSourceStore(t *testing.T) {
Default: true,
})

srcs[2] = mustAddSource(t, s, srcs[2])
srcs[3] = mustAddSource(t, s, srcs[3])
if srcs, err := s.All(ctx); err != nil {
t.Fatal(err)
} else {
Expand All @@ -121,22 +130,25 @@ func TestSourceStore(t *testing.T) {
}

// Delete the other source we created
if err := s.Delete(ctx, srcs[2]); err != nil {
if err := s.Delete(ctx, srcs[3]); err != nil {
t.Fatal(err)
}

if bsrcs, err := s.All(ctx); err != nil {
t.Fatal(err)
} else if len(bsrcs) != 1 {
t.Fatalf("After delete All returned incorrect number of srcs; got %d, expected %d", len(bsrcs), 1)
} else if len(bsrcs) != 2 {
t.Fatalf("After delete All returned incorrect number of srcs; got %d, expected %d", len(bsrcs), 2)
} else if !reflect.DeepEqual(bsrcs[0], srcs[1]) {
t.Fatalf("After delete All returned incorrect source; got %v, expected %v", bsrcs[0], srcs[1])
}

// Delete the final source
// Delete the final sources
if err := s.Delete(ctx, srcs[1]); err != nil {
t.Fatal(err)
}
if err := s.Delete(ctx, srcs[2]); err != nil {
t.Fatal(err)
}

// Try to add one source as a non-default and ensure that it becomes a
// default
Expand Down
17 changes: 9 additions & 8 deletions chronograf.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,15 @@ type Response interface {

// Source is connection information to a time-series data store.
type Source struct {
ID int `json:"id,omitempty,string"` // ID is the unique ID of the source
Name string `json:"name"` // Name is the user-defined name for the source
Type string `json:"type,omitempty"` // Type specifies which kinds of source (enterprise vs oss)
Username string `json:"username,omitempty"` // Username is the username to connect to the source
Password string `json:"password,omitempty"` // Password is in CLEARTEXT
URL string `json:"url"` // URL are the connections to the source
Default bool `json:"default"` // Default specifies the default source for the application
Telegraf string `json:"telegraf"` // Telegraf is the db telegraf is written to. By default it is "telegraf"
ID int `json:"id,omitempty,string"` // ID is the unique ID of the source
Name string `json:"name"` // Name is the user-defined name for the source
Type string `json:"type,omitempty"` // Type specifies which kinds of source (enterprise vs oss)
Username string `json:"username,omitempty"` // Username is the username to connect to the source
Password string `json:"password,omitempty"` // Password is in CLEARTEXT
URL string `json:"url"` // URL are the connections to the source
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"` // InsecureSkipVerify as true means any certificate presented by the source is accepted.
Default bool `json:"default"` // Default specifies the default source for the application
Telegraf string `json:"telegraf"` // Telegraf is the db telegraf is written to. By default it is "telegraf"
}

// SourcesStore stores connection information for a `TimeSeries`
Expand Down
19 changes: 16 additions & 3 deletions influx/influx.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package influx

import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
"net/http"
Expand All @@ -12,7 +13,8 @@ import (

// Client is a device for retrieving time series data from an InfluxDB instance
type Client struct {
URL *url.URL
URL *url.URL
InsecureSkipVerify bool

Logger chronograf.Logger
}
Expand Down Expand Up @@ -64,8 +66,15 @@ func (c *Client) query(u *url.URL, q chronograf.Query) (chronograf.Response, err
params.Set("rp", q.RP)
params.Set("epoch", "ms")
req.URL.RawQuery = params.Encode()
httpClient := &http.Client{}
resp, err := httpClient.Do(req)

hc := &http.Client{}
if c.InsecureSkipVerify {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
hc.Transport = tr
}
resp, err := hc.Do(req)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -145,6 +154,10 @@ func (c *Client) Connect(ctx context.Context, src *chronograf.Source) error {
return err
}
u.User = url.UserPassword(src.Username, src.Password)
// Only allow acceptance of all certs if the scheme is https AND the user opted into to the setting.
if u.Scheme == "https" && src.InsecureSkipVerify {
c.InsecureSkipVerify = src.InsecureSkipVerify
}
c.URL = u
return nil
}
76 changes: 76 additions & 0 deletions influx/influx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,82 @@ func Test_Influx_MakesRequestsToQueryEndpoint(t *testing.T) {
}
}

func Test_Influx_HTTPS_Failure(t *testing.T) {
called := false
ts := httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
called = true
}))
defer ts.Close()

ctx := context.Background()
var series chronograf.TimeSeries
series, err := influx.NewClient(ts.URL, log.New(log.DebugLevel))
if err != nil {
t.Fatal("Unexpected error initializing client: err:", err)
}

src := chronograf.Source{
URL: ts.URL,
}
if err := series.Connect(ctx, &src); err != nil {
t.Fatal("Unexpected error connecting to client: err:", err)
}

query := chronograf.Query{
Command: "show databases",
}
_, err = series.Query(ctx, query)
if err == nil {
t.Error("Expected error but was successful")
}

if called == true {
t.Error("Expected http request to fail, but, succeeded")
}

}

func Test_Influx_HTTPS_InsecureSkipVerify(t *testing.T) {
t.Parallel()
called := false
ts := httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusOK)
rw.Write([]byte(`{}`))
called = true
if path := r.URL.Path; path != "/query" {
t.Error("Expected the path to contain `/query` but was", path)
}
}))
defer ts.Close()

ctx := context.Background()
var series chronograf.TimeSeries
series, err := influx.NewClient(ts.URL, log.New(log.DebugLevel))
if err != nil {
t.Fatal("Unexpected error initializing client: err:", err)
}

src := chronograf.Source{
URL: ts.URL,
InsecureSkipVerify: true,
}
if err := series.Connect(ctx, &src); err != nil {
t.Fatal("Unexpected error connecting to client: err:", err)
}

query := chronograf.Query{
Command: "show databases",
}
_, err = series.Query(ctx, query)
if err != nil {
t.Fatal("Expected no error but was", err)
}

if called == false {
t.Error("Expected http request to Influx but there was none")
}
}

func Test_Influx_CancelsInFlightRequests(t *testing.T) {
t.Parallel()

Expand Down
1 change: 1 addition & 0 deletions server/sources.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ func (h *Service) UpdateSource(w http.ResponseWriter, r *http.Request) {
}

src.Default = req.Default
src.InsecureSkipVerify = req.InsecureSkipVerify
if req.Name != "" {
src.Name = req.Name
}
Expand Down
4 changes: 4 additions & 0 deletions server/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -2092,6 +2092,10 @@
"format": "url",
"description": "URL for the time series data source backend (e.g. http://localhost:8086)"
},
"insecureSkipVerify": {
"type": "boolean",
"description": "True means any certificate presented by the source is accepted. Typically used for self-signed certs. Probably should only be used for testing."
},
"default": {
"type": "boolean",
"description": "Indicates whether this source is the default source"
Expand Down

0 comments on commit c852618

Please sign in to comment.