From 127707c87c6094fafd0a9d7b418743d99b03fba8 Mon Sep 17 00:00:00 2001 From: Curtis Mattoon Date: Sun, 14 Apr 2019 19:35:49 -0400 Subject: [PATCH 1/2] Adds per-backend configuration for HTTP Basic Auth (Issue #28) --- relay/auth.go | 29 +++++++++++++++++++++++++++ relay/auth_test.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++ relay/config.go | 6 ++++++ relay/http.go | 12 +++++++---- sample.toml | 2 +- 5 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 relay/auth.go create mode 100644 relay/auth_test.go diff --git a/relay/auth.go b/relay/auth.go new file mode 100644 index 0000000..1b14202 --- /dev/null +++ b/relay/auth.go @@ -0,0 +1,29 @@ +package relay + +import ( + "encoding/base64" + "fmt" +) + +type HTTPAuth interface { + GetAuthorizationString(string) string +} + +type httpAuth struct { + user string + pass string +} + +func (a *httpAuth) GetAuthorizationString(passthru string) string { + if a.user != "" && a.pass != "" { + return fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", a.user, a.pass)))) + } + return passthru +} + +func NewHTTPAuth(cfg *HTTPOutputConfig) *httpAuth { + return &httpAuth{ + user: cfg.HTTPBasicAuthUser, + pass: cfg.HTTPBasicAuthPass, + } +} diff --git a/relay/auth_test.go b/relay/auth_test.go new file mode 100644 index 0000000..b37d599 --- /dev/null +++ b/relay/auth_test.go @@ -0,0 +1,50 @@ +package relay + +import ( + "testing" +) + +func newMockHTTPOutputConfig(user string, pass string) *HTTPOutputConfig { + return &HTTPOutputConfig{ + Name: "test-backend", + Location: "localhost:8086", + Timeout: "10s", + BufferSizeMB: 0, + MaxBatchKB: 512, + MaxDelayInterval: "10", + SkipTLSVerification: false, + HTTPBasicAuthUser: user, + HTTPBasicAuthPass: pass, + } +} + +func TestGetAuthorizationString(t *testing.T) { + for _, tbl := range []struct { + cfg *HTTPOutputConfig + auth string // Client auth header + exp string // expected result + + }{ + { + cfg: newMockHTTPOutputConfig("", ""), + auth: "", + exp: "", + }, + { + cfg: newMockHTTPOutputConfig("", ""), + auth: "client-header", + exp: "client-header", + }, + { + cfg: newMockHTTPOutputConfig("admin", "password"), + auth: "client-header-present-but-not-preferred", + exp: "Basic YWRtaW46cGFzc3dvcmQ=", // admin:password + }, + } { + test_auth := NewHTTPAuth(tbl.cfg) + res := test_auth.GetAuthorizationString(tbl.auth) + if tbl.exp != res { + t.Errorf("Expected %s, got %s", tbl.exp, res) + } + } +} diff --git a/relay/config.go b/relay/config.go index 18131d9..df8f42e 100644 --- a/relay/config.go +++ b/relay/config.go @@ -52,6 +52,12 @@ type HTTPOutputConfig struct { // Skip TLS verification in order to use self signed certificate. // WARNING: It's insecure. Use it only for developing and don't use in production. SkipTLSVerification bool `toml:"skip-tls-verification"` + + // Username for HTTP Basic Auth + HTTPBasicAuthUser string `toml:"http-user"` + + // Password for HTTP Basic Auth + HTTPBasicAuthPass string `toml:"http-pass"` } type UDPConfig struct { diff --git a/relay/http.go b/relay/http.go index 73d4f23..9b8e88e 100644 --- a/relay/http.go +++ b/relay/http.go @@ -114,9 +114,9 @@ func (h *HTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) { start := time.Now() if r.URL.Path == "/ping" && (r.Method == "GET" || r.Method == "HEAD") { - w.Header().Add("X-InfluxDB-Version", "relay") - w.WriteHeader(http.StatusNoContent) - return + w.Header().Add("X-InfluxDB-Version", "relay") + w.WriteHeader(http.StatusNoContent) + return } if r.URL.Path != "/write" { @@ -209,7 +209,7 @@ func (h *HTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) { b := b go func() { defer wg.Done() - resp, err := b.post(outBytes, query, authHeader) + resp, err := b.post(outBytes, query, b.auth.GetAuthorizationString(authHeader)) if err != nil { log.Printf("Problem posting to relay %q backend %q: %v", h.Name(), b.name, err) } else { @@ -350,6 +350,7 @@ func (b *simplePoster) post(buf []byte, query string, auth string) (*responseDat type httpBackend struct { poster name string + auth HTTPAuth } func newHTTPBackend(cfg *HTTPOutputConfig) (*httpBackend, error) { @@ -388,9 +389,12 @@ func newHTTPBackend(cfg *HTTPOutputConfig) (*httpBackend, error) { p = newRetryBuffer(cfg.BufferSizeMB*MB, batch, max, p) } + auth := NewHTTPAuth(cfg) + return &httpBackend{ poster: p, name: cfg.Name, + auth: auth, }, nil } diff --git a/sample.toml b/sample.toml index 5152857..b6a5516 100644 --- a/sample.toml +++ b/sample.toml @@ -5,7 +5,7 @@ name = "example-http" bind-addr = "127.0.0.1:9096" output = [ { name="local1", location = "http://127.0.0.1:8086/write" }, - { name="local2", location = "http://127.0.0.1:7086/write" }, + { name="local2", location = "http://127.0.0.1:7086/write", http-user="test", http-pass="secretpassword" }, ] [[udp]] From 0004635e993b316abbd1c74af52201f835ea3229 Mon Sep 17 00:00:00 2001 From: Curtis Mattoon Date: Sun, 14 Apr 2019 19:47:37 -0400 Subject: [PATCH 2/2] Add more test cases --- relay/auth_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/relay/auth_test.go b/relay/auth_test.go index b37d599..5375134 100644 --- a/relay/auth_test.go +++ b/relay/auth_test.go @@ -35,6 +35,16 @@ func TestGetAuthorizationString(t *testing.T) { auth: "client-header", exp: "client-header", }, + { + cfg: newMockHTTPOutputConfig("admin", ""), + auth: "client-header", + exp: "client-header", + }, + { + cfg: newMockHTTPOutputConfig("", "password"), + auth: "client-header", + exp: "client-header", + }, { cfg: newMockHTTPOutputConfig("admin", "password"), auth: "client-header-present-but-not-preferred",