mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
vmauth: add counter metrics for auth successes and failures (#5166)
New labels `reason="wrong basic auth creds"` and `reason="wrong auth key"` were added to metric `vm_http_request_errors_total` to help identify auth errors. https://github.com/victoriaMetrics/victoriaMetrics/issues/4590 Co-authored-by: Rao, B V Chalapathi <b_v_chalapathi.rao@nokia.com> Co-authored-by: Roman Khavronenko <roman@victoriametrics.com>
This commit is contained in:
parent
aaf9e3d526
commit
0638bbe69c
2 changed files with 97 additions and 2 deletions
|
@ -372,6 +372,7 @@ func CheckAuthFlag(w http.ResponseWriter, r *http.Request, flagValue string, fla
|
|||
return CheckBasicAuth(w, r)
|
||||
}
|
||||
if r.FormValue("authKey") != flagValue {
|
||||
authKeyRequestErrors.Inc()
|
||||
http.Error(w, fmt.Sprintf("The provided authKey doesn't match -%s", flagName), http.StatusUnauthorized)
|
||||
return false
|
||||
}
|
||||
|
@ -386,9 +387,13 @@ func CheckBasicAuth(w http.ResponseWriter, r *http.Request) bool {
|
|||
return true
|
||||
}
|
||||
username, password, ok := r.BasicAuth()
|
||||
if ok && username == *httpAuthUsername && password == *httpAuthPassword {
|
||||
return true
|
||||
if ok {
|
||||
if username == *httpAuthUsername && password == *httpAuthPassword {
|
||||
return true
|
||||
}
|
||||
authBasicRequestErrors.Inc()
|
||||
}
|
||||
|
||||
w.Header().Set("WWW-Authenticate", `Basic realm="VictoriaMetrics"`)
|
||||
http.Error(w, "", http.StatusUnauthorized)
|
||||
return false
|
||||
|
@ -442,6 +447,8 @@ var (
|
|||
pprofDefaultRequests = metrics.NewCounter(`vm_http_requests_total{path="/debug/pprof/default"}`)
|
||||
faviconRequests = metrics.NewCounter(`vm_http_requests_total{path="/favicon.ico"}`)
|
||||
|
||||
authBasicRequestErrors = metrics.NewCounter(`vm_http_request_errors_total{path="*", reason="wrong basic auth creds"}`)
|
||||
authKeyRequestErrors = metrics.NewCounter(`vm_http_request_errors_total{path="*", reason="wrong auth key"}`)
|
||||
unsupportedRequestErrors = metrics.NewCounter(`vm_http_request_errors_total{path="*", reason="unsupported"}`)
|
||||
|
||||
requestsTotal = metrics.NewCounter(`vm_http_requests_all_total`)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -36,6 +37,93 @@ func TestGetQuotedRemoteAddr(t *testing.T) {
|
|||
f("1.2\n\"3.4", "foo\nb\"ar", `"1.2\n\"3.4, X-Forwarded-For: foo\nb\"ar"`)
|
||||
}
|
||||
|
||||
func TestBasicAuthMetrics(t *testing.T) {
|
||||
origUsername := *httpAuthUsername
|
||||
origPasswd := *httpAuthPassword
|
||||
defer func() {
|
||||
*httpAuthPassword = origPasswd
|
||||
*httpAuthUsername = origUsername
|
||||
}()
|
||||
|
||||
f := func(user, pass string, expCode int) {
|
||||
t.Helper()
|
||||
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
|
||||
req.SetBasicAuth(user, pass)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
CheckBasicAuth(w, req)
|
||||
|
||||
res := w.Result()
|
||||
_ = res.Body.Close()
|
||||
if expCode != res.StatusCode {
|
||||
t.Fatalf("wanted status code: %d, got: %d\n", res.StatusCode, expCode)
|
||||
}
|
||||
}
|
||||
|
||||
*httpAuthUsername = "test"
|
||||
*httpAuthPassword = "pass"
|
||||
f("test", "pass", 200)
|
||||
f("test", "wrong", 401)
|
||||
f("wrong", "pass", 401)
|
||||
f("wrong", "wrong", 401)
|
||||
|
||||
*httpAuthUsername = ""
|
||||
*httpAuthPassword = ""
|
||||
f("test", "pass", 200)
|
||||
f("test", "wrong", 200)
|
||||
f("wrong", "pass", 200)
|
||||
f("wrong", "wrong", 200)
|
||||
}
|
||||
|
||||
func TestAuthKeyMetrics(t *testing.T) {
|
||||
origUsername := *httpAuthUsername
|
||||
origPasswd := *httpAuthPassword
|
||||
defer func() {
|
||||
*httpAuthPassword = origPasswd
|
||||
*httpAuthUsername = origUsername
|
||||
}()
|
||||
|
||||
tstWithAuthKey := func(key string, expCode int) {
|
||||
t.Helper()
|
||||
req := httptest.NewRequest(http.MethodPost, "/metrics", strings.NewReader("authKey="+key))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded;param=value")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
CheckAuthFlag(w, req, "rightKey", "metricsAuthkey")
|
||||
|
||||
res := w.Result()
|
||||
defer res.Body.Close()
|
||||
if expCode != res.StatusCode {
|
||||
t.Fatalf("Unexpected status code: %d, Expected code is: %d\n", res.StatusCode, expCode)
|
||||
}
|
||||
}
|
||||
|
||||
tstWithAuthKey("rightKey", 200)
|
||||
tstWithAuthKey("wrongKey", 401)
|
||||
|
||||
tstWithOutAuthKey := func(user, pass string, expCode int) {
|
||||
t.Helper()
|
||||
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
|
||||
req.SetBasicAuth(user, pass)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
CheckAuthFlag(w, req, "", "metricsAuthkey")
|
||||
|
||||
res := w.Result()
|
||||
_ = res.Body.Close()
|
||||
if expCode != res.StatusCode {
|
||||
t.Fatalf("wanted status code: %d, got: %d\n", res.StatusCode, expCode)
|
||||
}
|
||||
}
|
||||
|
||||
*httpAuthUsername = "test"
|
||||
*httpAuthPassword = "pass"
|
||||
tstWithOutAuthKey("test", "pass", 200)
|
||||
tstWithOutAuthKey("test", "wrong", 401)
|
||||
tstWithOutAuthKey("wrong", "pass", 401)
|
||||
tstWithOutAuthKey("wrong", "wrong", 401)
|
||||
}
|
||||
|
||||
func TestHandlerWrapper(t *testing.T) {
|
||||
*headerHSTS = "foo"
|
||||
*headerFrameOptions = "bar"
|
||||
|
|
Loading…
Reference in a new issue