adds query params support for vmauth urlPrefix (#1226)

* adds query params support for vmauth urlPrefix

* Update app/vmauth/example_config.yml

* Update app/vmauth/example_config.yml

Co-authored-by: Aliaksandr Valialkin <valyala@gmail.com>
This commit is contained in:
Nikolay 2021-04-20 10:51:03 +03:00 committed by Aliaksandr Valialkin
parent b0bd2c0d61
commit 7d249d787d
3 changed files with 44 additions and 4 deletions

View file

@ -11,6 +11,14 @@ users:
password: "***"
url_prefix: "http://localhost:8428"
# The user for querying local single-node VictoriaMetrics with extra_label team=dev.
# All the requests to http://vmauth:8427 with the given Basic Auth (username:password)
# will be routed to http://localhost:8428 with extra_label=team=dev query arg.
# For example, http://vmauth:8427/api/v1/query is routed to http://localhost:8428/api/v1/query?extra_label=team=dev
- username: "local-single-node"
password: "***"
url_prefix: "http://localhost:8428?extra_label=team=dev"
# The user for querying account 123 in VictoriaMetrics cluster
# See https://victoriametrics.github.io/Cluster-VictoriaMetrics.html#url-format
# All the requests to http://vmauth:8427 with the given Basic Auth (username:password)
@ -28,4 +36,3 @@ users:
- username: "cluster-insert-account-42"
password: "***"
url_prefix: "http://vminsert:8480/insert/42/prometheus"

View file

@ -7,6 +7,32 @@ import (
"strings"
)
func mergeURLs(uiURL string, requestURI *url.URL) (string, error) {
prefixURL, err := url.Parse(uiURL)
if err != nil {
return "", fmt.Errorf("BUG - cannot parse userInfo url: %q, err: %w", uiURL, err)
}
prefixURL.Path += requestURI.Path
requestParams := requestURI.Query()
// fast path
if len(requestParams) == 0 {
return prefixURL.String(), nil
}
// merge query parameters from requests.
userInfoParams := prefixURL.Query()
for k, v := range requestParams {
// skip clashed query params from original request
if exist := userInfoParams.Get(k); len(exist) > 0 {
continue
}
for i := range v {
userInfoParams.Add(k, v[i])
}
}
prefixURL.RawQuery = userInfoParams.Encode()
return prefixURL.String(), nil
}
func createTargetURL(ui *UserInfo, uOrig *url.URL) (string, error) {
u, err := url.Parse(uOrig.String())
if err != nil {
@ -20,12 +46,12 @@ func createTargetURL(ui *UserInfo, uOrig *url.URL) (string, error) {
for _, e := range ui.URLMap {
for _, sp := range e.SrcPaths {
if sp.match(u.Path) {
return e.URLPrefix + u.RequestURI(), nil
return mergeURLs(e.URLPrefix, u)
}
}
}
if len(ui.URLPrefix) > 0 {
return ui.URLPrefix + u.RequestURI(), nil
return mergeURLs(ui.URLPrefix, u)
}
return "", fmt.Errorf("missing route for %q", u)
}

View file

@ -38,7 +38,7 @@ func TestCreateTargetURLSuccess(t *testing.T) {
}, "/../../aaa", "https://sss:3894/x/y/aaa")
f(&UserInfo{
URLPrefix: "https://sss:3894/x/y",
}, "/./asd/../../aaa?a=d&s=s/../d", "https://sss:3894/x/y/aaa?a=d&s=s/../d")
}, "/./asd/../../aaa?a=d&s=s/../d", "https://sss:3894/x/y/aaa?a=d&s=s%2F..%2Fd")
// Complex routing with `url_map`
ui := &UserInfo{
@ -77,6 +77,13 @@ func TestCreateTargetURLSuccess(t *testing.T) {
f(ui, "/api/v1/label/foo/values", "http://vmselect/0/prometheus/api/v1/label/foo/values")
f(ui, "/api/v1/write", "http://vminsert/0/prometheus/api/v1/write")
f(ui, "/api/v1/foo/bar", "http://default-server/api/v1/foo/bar")
f(&UserInfo{
URLPrefix: "http://foo.bar?extra_label=team=dev",
}, "/api/v1/query", "http://foo.bar/api/v1/query?extra_label=team=dev")
f(&UserInfo{
URLPrefix: "http://foo.bar?extra_label=team=mobile",
}, "/api/v1/query?extra_label=team=dev", "http://foo.bar/api/v1/query?extra_label=team%3Dmobile")
}
func TestCreateTargetURLFailure(t *testing.T) {