Skip to content

Commit

Permalink
Merge pull request #10 from vshn/token-parameter
Browse files Browse the repository at this point in the history
Allow passing the bearer token via query parameter
  • Loading branch information
Simon Rüegg authored Mar 5, 2020
2 parents 3028722 + c600aff commit 778411b
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 93 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ Please document all notable changes to this project in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [v0.4.0]

### Added

- Allow passing the bearer token via URL query parameter (`/webhook?token=<token>`) in addition to the `Authorization` header. Header takes precedence.

## [v0.3.0]

### Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Optional
* `--alertmanager_port`/`SIGNALILO_ALERTMANAGER_PORT`:
Port on which Signalilo listens to incoming webhooks (default 8888).
* `--alertmanager_bearer_token`/`SIGNALILO_ALERTMANAGER_BEARER_TOKEN`:
Incoming webhook authentication.
Incoming webhook authentication. Can be either set via `Authorization` header or in the `token` URL query parameter.
* `--alertmanager_tls_cert`/`SIGNALILO_ALERTMANAGER_TLS_CERT`:
Path of certificate file for TLS-enabled webhook endpoint. Should contain the
full chain.
Expand Down
77 changes: 8 additions & 69 deletions go.sum

Large diffs are not rendered by default.

21 changes: 13 additions & 8 deletions webhook/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,21 @@ func asJSON(w http.ResponseWriter, status int, message string) {

func checkBearerToken(r *http.Request, c config.Configuration) error {
tokenHeader := r.Header.Get("Authorization")
if tokenHeader == "" {
return fmt.Errorf("Request does not have Authorization header")
}
headerElems := strings.Split(tokenHeader, " ")
if len(headerElems) != 2 || (len(headerElems) > 0 && headerElems[0] != "Bearer") {
return fmt.Errorf("Malformed Authorization header")
tokenQuery := r.URL.Query().Get("token")
var token string
if tokenHeader != "" {
headerElems := strings.Split(tokenHeader, " ")
if len(headerElems) != 2 || (len(headerElems) > 0 && headerElems[0] != "Bearer") {
return fmt.Errorf("Malformed authorization header")
}
token = headerElems[1]
} else if tokenQuery != "" {
token = tokenQuery
} else {
return fmt.Errorf("Request dos not contain an authorization token")
}
token := headerElems[1]
if token != c.GetConfig().AlertManagerConfig.BearerToken {
return fmt.Errorf("Invalid Bearer token")
return fmt.Errorf("Invalid bearer token")
}
return nil
}
Expand Down
33 changes: 27 additions & 6 deletions webhook/hook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
"net/http"
"testing"

tassert "github.com/stretchr/testify/assert"
"git.vshn.net/appuio/signalilo/config"
"github.com/stretchr/testify/assert"
)

func isJSON(s string) bool {
Expand All @@ -27,12 +28,32 @@ func mockEchoHandler(w http.ResponseWriter, r *http.Request) {
}

func TestAsJSON(t *testing.T) {
assert := tassert.New(t)

handler := http.HandlerFunc(mockEchoHandler)

// verify response properties
assert.HTTPSuccess(handler, "GET", "http://example.com/webhook", nil)
response := tassert.HTTPBody(handler, "GET", "http://example.com/webhook", nil)
assert.JSONEq(response, `{ "Status": 200, "Message": "ok" }`)
assert.HTTPSuccess(t, handler, "GET", "http://example.com/webhook", nil)
response := assert.HTTPBody(handler, "GET", "http://example.com/webhook", nil)
assert.JSONEq(t, response, `{ "Status": 200, "Message": "ok" }`)
}

func TestBearerTokenHeader(t *testing.T) {
conf := config.NewMockConfiguration(1)
req, _ := http.NewRequest(http.MethodPost, "https://example.com/webhook", nil)
req.Header.Add("Authorization", "Bearer "+conf.GetConfig().AlertManagerConfig.BearerToken)
err := checkBearerToken(req, conf)
assert.NoError(t, err)
}

func TestBearerTokenQueryParam(t *testing.T) {
conf := config.NewMockConfiguration(1)
req, _ := http.NewRequest(http.MethodPost, "https://example.com/webhook?token="+conf.GetConfig().AlertManagerConfig.BearerToken, nil)
err := checkBearerToken(req, conf)
assert.NoError(t, err)
}

func TestBearerTokenMissing(t *testing.T) {
conf := config.NewMockConfiguration(1)
req, _ := http.NewRequest(http.MethodPost, "https://example.com/webhook", nil)
err := checkBearerToken(req, conf)
assert.Error(t, err)
}
10 changes: 3 additions & 7 deletions webhook/icinga_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

"git.vshn.net/appuio/signalilo/config"
"github.com/prometheus/alertmanager/template"
tassert "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/assert"
)

func TestValidateServiceName(t *testing.T) {
Expand All @@ -41,16 +41,12 @@ func TestValidateServiceName(t *testing.T) {
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab": false,
}

assert := tassert.New(t)

for name, expected := range serviceNames {
assert.Equal(validateServiceName(name), expected, "service name regex works")
assert.Equal(t, validateServiceName(name), expected, "service name regex works")
}
}

func TestComputeServiceName(t *testing.T) {
assert := tassert.New(t)

alerts := []template.Alert{
template.Alert{
Labels: map[string]string{
Expand All @@ -68,6 +64,6 @@ func TestComputeServiceName(t *testing.T) {
for _, alert := range alerts {
svcName, err := computeServiceName(template.Data{}, alert, c)
expected, _ := strconv.ParseBool(alert.Annotations["expected"])
assert.Equal(err == nil, expected, fmt.Sprintf("Alert: %+v -> %v; err = %v", alert, svcName, err))
assert.Equal(t, err == nil, expected, fmt.Sprintf("Alert: %+v -> %v; err = %v", alert, svcName, err))
}
}
4 changes: 2 additions & 2 deletions webhook/variable_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
)

var (
ErrorNotAMappingKey = errors.New("key does meet the mappable pattern")
ErrorNotAMappingKey = errors.New("key does meet the mappable pattern")
ErrorUnknownMappingType = errors.New("unknown type")
MappingKeyPattern = regexp.MustCompile("^icinga_([a-z]+)_(.*)$")
MappingKeyPattern = regexp.MustCompile("^icinga_([a-z]+)_(.*)$")
)

func mapIcingaVariables(vars icinga2.Vars, kv map[string]string, prefix string, log logr.Logger) icinga2.Vars {
Expand Down

0 comments on commit 778411b

Please sign in to comment.