Skip to content

Commit

Permalink
Add unit test for unauthenticated metrics access parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
michelvocks committed Oct 4, 2019
1 parent 8cc3cee commit 77db87e
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 25 deletions.
26 changes: 1 addition & 25 deletions http/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"github.com/hashicorp/errwrap"
cleanhttp "github.com/hashicorp/go-cleanhttp"
sockaddr "github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/vault/helper/metricsutil"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
Expand Down Expand Up @@ -150,7 +149,7 @@ func Handler(props *vault.HandlerProperties) http.Handler {

// Register metrics path without authentication if enabled
if props.UnauthenticatedMetricsAccess {
mux.Handle("/v1/sys/metrics", handleMetricsUnauth(core))
mux.Handle("/v1/sys/metrics", handleMetricsUnauthenticated(core))
}

additionalRoutes(mux, core)
Expand Down Expand Up @@ -521,29 +520,6 @@ func parseRequest(core *vault.Core, r *http.Request, w http.ResponseWriter, out
return nil, err
}

func handleMetricsUnauth(core *vault.Core) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
req := &logical.Request{Headers: r.Header}
format := r.Form.Get("format")
if format == "" {
format = metricsutil.FormatFromRequest(req)
}

// Define response
resp, err := core.MetricsHelper().ResponseForFormat(format)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}

// Manually unarchive the logical response and send back the information
w.WriteHeader(resp.Data[logical.HTTPStatusCode].(int))
w.Header().Set("Content-Type", resp.Data[logical.HTTPContentType].(string))
w.Write(resp.Data[logical.HTTPRawBody].([]byte))
})
}

// handleRequestForwarding determines whether to forward a request or not,
// falling back on the older behavior of redirecting the client
func handleRequestForwarding(core *vault.Core, handler http.Handler) http.Handler {
Expand Down
32 changes: 32 additions & 0 deletions http/sys_metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package http

import (
"net/http"

"github.com/hashicorp/vault/helper/metricsutil"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
)

func handleMetricsUnauthenticated(core *vault.Core) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
req := &logical.Request{Headers: r.Header}
format := r.Form.Get("format")
if format == "" {
format = metricsutil.FormatFromRequest(req)
}

// Define response
resp, err := core.MetricsHelper().ResponseForFormat(format)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}

// Manually extract the logical response and send back the information
w.WriteHeader(resp.Data[logical.HTTPStatusCode].(int))
w.Header().Set("Content-Type", resp.Data[logical.HTTPContentType].(string))
w.Write(resp.Data[logical.HTTPRawBody].([]byte))
})
}
50 changes: 50 additions & 0 deletions http/sys_metrics_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package http

import (
"testing"
"time"

"github.com/armon/go-metrics"
"github.com/hashicorp/vault/helper/metricsutil"
"github.com/hashicorp/vault/vault"
)

func TestSysMetricsUnauthenticated(t *testing.T) {
inm := metrics.NewInmemSink(10*time.Second, time.Minute)
metrics.DefaultInmemSignal(inm)
conf := &vault.CoreConfig{
BuiltinRegistry: vault.NewMockBuiltinRegistry(),
MetricsHelper: metricsutil.NewMetricsHelper(inm, false),
}
core, _, token := vault.TestCoreUnsealedWithConfig(t, conf)
ln, addr := TestServer(t, core)
TestServerAuth(t, addr, token)

// Default: Only authenticated access
resp := testHttpGet(t, "", addr+"/v1/sys/metrics")
testResponseStatus(t, resp, 400)
resp = testHttpGet(t, token, addr+"/v1/sys/metrics")
testResponseStatus(t, resp, 200)

// Close listener
ln.Close()

// Setup new custom listener with unauthenticated metrics access
ln, addr = TestListener(t)
props := &vault.HandlerProperties{
Core: core,
MaxRequestSize: DefaultMaxRequestSize,
UnauthenticatedMetricsAccess: true,
}
TestServerWithListenerAndProperties(t, ln, addr, core, props)
defer ln.Close()
TestServerAuth(t, addr, token)

// Test without token
resp = testHttpGet(t, "", addr+"/v1/sys/metrics")
testResponseStatus(t, resp, 200)

// Should also work with token
resp = testHttpGet(t, token, addr+"/v1/sys/metrics")
testResponseStatus(t, resp, 200)
}
1 change: 1 addition & 0 deletions vault/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ func TestCoreWithSealAndUI(t testing.T, opts *CoreConfig) *Core {
conf.Seal = opts.Seal
conf.LicensingConfig = opts.LicensingConfig
conf.DisableKeyEncodingChecks = opts.DisableKeyEncodingChecks
conf.MetricsHelper = opts.MetricsHelper

if opts.Logger != nil {
conf.Logger = opts.Logger
Expand Down

0 comments on commit 77db87e

Please sign in to comment.