feat: HTTP basic auth for webhooks (#9332)

Co-authored-by: Sebastian Spaink <3441183+sspaink@users.noreply.github.com>
This commit is contained in:
Alexander Krantz 2022-03-04 07:51:01 -08:00 committed by GitHub
parent 7e2f22c00c
commit f76729cfb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 159 additions and 8 deletions

View File

@ -0,0 +1,23 @@
package auth
import (
"crypto/subtle"
"net/http"
)
type BasicAuth struct {
Username string `toml:"username"`
Password string `toml:"password"`
}
func (b *BasicAuth) Verify(r *http.Request) bool {
if b.Username == "" && b.Password == "" {
return true
}
username, password, ok := r.BasicAuth()
usernameComparison := subtle.ConstantTimeCompare([]byte(username), []byte(b.Username)) == 1
passwordComparison := subtle.ConstantTimeCompare([]byte(password), []byte(b.Password)) == 1
return ok && usernameComparison && passwordComparison
}

View File

@ -0,0 +1,33 @@
package auth
import (
"github.com/stretchr/testify/require"
"net/http/httptest"
"testing"
)
func TestBasicAuth_VerifyWithCredentials(t *testing.T) {
auth := BasicAuth{"username", "password"}
r := httptest.NewRequest("GET", "/github", nil)
r.SetBasicAuth(auth.Username, auth.Password)
require.True(t, auth.Verify(r))
}
func TestBasicAuth_VerifyWithoutCredentials(t *testing.T) {
auth := BasicAuth{}
r := httptest.NewRequest("GET", "/github", nil)
require.True(t, auth.Verify(r))
}
func TestBasicAuth_VerifyWithInvalidCredentials(t *testing.T) {
auth := BasicAuth{"username", "password"}
r := httptest.NewRequest("GET", "/github", nil)
r.SetBasicAuth("wrong-username", "wrong-password")
require.False(t, auth.Verify(r))
}

View File

@ -23,21 +23,45 @@ sudo service telegraf start
[inputs.webhooks.filestack]
path = "/filestack"
## HTTP basic auth
#username = ""
#password = ""
[inputs.webhooks.github]
path = "/github"
# secret = ""
## HTTP basic auth
#username = ""
#password = ""
[inputs.webhooks.mandrill]
path = "/mandrill"
## HTTP basic auth
#username = ""
#password = ""
[inputs.webhooks.rollbar]
path = "/rollbar"
## HTTP basic auth
#username = ""
#password = ""
[inputs.webhooks.papertrail]
path = "/papertrail"
## HTTP basic auth
#username = ""
#password = ""
[inputs.webhooks.particle]
path = "/particle"
## HTTP basic auth
#username = ""
#password = ""
```
## Available webhooks

View File

@ -2,19 +2,21 @@ package filestack
import (
"encoding/json"
"io"
"io/ioutil"
"net/http"
"time"
"github.com/gorilla/mux"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/common/auth"
)
type FilestackWebhook struct {
Path string
acc telegraf.Accumulator
log telegraf.Logger
auth.BasicAuth
}
func (fs *FilestackWebhook) Register(router *mux.Router, acc telegraf.Accumulator, log telegraf.Logger) {
@ -27,7 +29,13 @@ func (fs *FilestackWebhook) Register(router *mux.Router, acc telegraf.Accumulato
func (fs *FilestackWebhook) eventHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
body, err := io.ReadAll(r.Body)
if !fs.Verify(r) {
w.WriteHeader(http.StatusUnauthorized)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return

View File

@ -11,6 +11,7 @@ import (
"github.com/gorilla/mux"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/common/auth"
)
type GithubWebhook struct {
@ -18,6 +19,7 @@ type GithubWebhook struct {
Secret string
acc telegraf.Accumulator
log telegraf.Logger
auth.BasicAuth
}
func (gh *GithubWebhook) Register(router *mux.Router, acc telegraf.Accumulator, log telegraf.Logger) {
@ -30,6 +32,12 @@ func (gh *GithubWebhook) Register(router *mux.Router, acc telegraf.Accumulator,
func (gh *GithubWebhook) eventHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
if !gh.Verify(r) {
w.WriteHeader(http.StatusUnauthorized)
return
}
eventType := r.Header.Get("X-Github-Event")
data, err := io.ReadAll(r.Body)
if err != nil {

View File

@ -2,20 +2,22 @@ package mandrill
import (
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/url"
"time"
"github.com/influxdata/telegraf"
"github.com/gorilla/mux"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/common/auth"
)
type MandrillWebhook struct {
Path string
acc telegraf.Accumulator
log telegraf.Logger
auth.BasicAuth
}
func (md *MandrillWebhook) Register(router *mux.Router, acc telegraf.Accumulator, log telegraf.Logger) {
@ -33,7 +35,13 @@ func (md *MandrillWebhook) returnOK(w http.ResponseWriter, _ *http.Request) {
func (md *MandrillWebhook) eventHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
body, err := io.ReadAll(r.Body)
if !md.Verify(r) {
w.WriteHeader(http.StatusUnauthorized)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return

View File

@ -9,12 +9,14 @@ import (
"github.com/gorilla/mux"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/common/auth"
)
type PapertrailWebhook struct {
Path string
acc telegraf.Accumulator
log telegraf.Logger
auth.BasicAuth
}
func (pt *PapertrailWebhook) Register(router *mux.Router, acc telegraf.Accumulator, log telegraf.Logger) {
@ -30,6 +32,11 @@ func (pt *PapertrailWebhook) eventHandler(w http.ResponseWriter, r *http.Request
return
}
if !pt.Verify(r) {
w.WriteHeader(http.StatusUnauthorized)
return
}
data := r.PostFormValue("payload")
if data == "" {
http.Error(w, "Bad Request", http.StatusBadRequest)

View File

@ -8,6 +8,7 @@ import (
"github.com/gorilla/mux"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/common/auth"
)
type event struct {
@ -40,6 +41,7 @@ type ParticleWebhook struct {
Path string
acc telegraf.Accumulator
log telegraf.Logger
auth.BasicAuth
}
func (rb *ParticleWebhook) Register(router *mux.Router, acc telegraf.Accumulator, log telegraf.Logger) {
@ -51,6 +53,12 @@ func (rb *ParticleWebhook) Register(router *mux.Router, acc telegraf.Accumulator
func (rb *ParticleWebhook) eventHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
if !rb.Verify(r) {
w.WriteHeader(http.StatusUnauthorized)
return
}
e := newEvent()
if err := json.NewDecoder(r.Body).Decode(e); err != nil {
rb.acc.AddError(err)

View File

@ -3,19 +3,21 @@ package rollbar
import (
"encoding/json"
"errors"
"io"
"io/ioutil"
"net/http"
"time"
"github.com/gorilla/mux"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/common/auth"
)
type RollbarWebhook struct {
Path string
acc telegraf.Accumulator
log telegraf.Logger
auth.BasicAuth
}
func (rb *RollbarWebhook) Register(router *mux.Router, acc telegraf.Accumulator, log telegraf.Logger) {
@ -27,7 +29,13 @@ func (rb *RollbarWebhook) Register(router *mux.Router, acc telegraf.Accumulator,
func (rb *RollbarWebhook) eventHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
if !rb.Verify(r) {
w.WriteHeader(http.StatusUnauthorized)
return
}
data, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return

View File

@ -53,21 +53,45 @@ func (wb *Webhooks) SampleConfig() string {
[inputs.webhooks.filestack]
path = "/filestack"
## HTTP basic auth
#username = ""
#password = ""
[inputs.webhooks.github]
path = "/github"
# secret = ""
## HTTP basic auth
#username = ""
#password = ""
[inputs.webhooks.mandrill]
path = "/mandrill"
## HTTP basic auth
#username = ""
#password = ""
[inputs.webhooks.rollbar]
path = "/rollbar"
## HTTP basic auth
#username = ""
#password = ""
[inputs.webhooks.papertrail]
path = "/papertrail"
## HTTP basic auth
#username = ""
#password = ""
[inputs.webhooks.particle]
path = "/particle"
## HTTP basic auth
#username = ""
#password = ""
`
}