diff --git a/proxy_test.go b/proxy_test.go index a2aace0b..3fc18846 100644 --- a/proxy_test.go +++ b/proxy_test.go @@ -349,6 +349,42 @@ func TestReverseProxy_ServeHTTP1(t *testing.T) { return makeCustomRequest(p, req) }, }, + { + cfg: authCfg, + name: "headers auth ok", + expResponse: okResponse, + expStatusCode: http.StatusOK, + f: func(p *reverseProxy) *http.Response { + req := httptest.NewRequest("POST", fakeServer.URL, nil) + req.Header.Set("X-ClickHouse-User", "foo") + req.Header.Set("X-ClickHouse-Key", "bar") + return makeCustomRequest(p, req) + }, + }, + { + cfg: authCfg, + name: "header auth wrong name", + expResponse: "invalid username or password for user \"fooo\"", + expStatusCode: http.StatusUnauthorized, + f: func(p *reverseProxy) *http.Response { + req := httptest.NewRequest("POST", fakeServer.URL, nil) + req.Header.Set("X-ClickHouse-User", "fooo") + req.Header.Set("X-ClickHouse-Key", "bar") + return makeCustomRequest(p, req) + }, + }, + { + cfg: authCfg, + name: "header auth wrong name", + expResponse: "invalid username or password for user \"foo\"", + expStatusCode: http.StatusUnauthorized, + f: func(p *reverseProxy) *http.Response { + req := httptest.NewRequest("POST", fakeServer.URL, nil) + req.Header.Set("X-ClickHouse-User", "foo") + req.Header.Set("X-ClickHouse-Key", "baar") + return makeCustomRequest(p, req) + }, + }, } for _, tc := range testCases { diff --git a/scope.go b/scope.go index a236ac25..6f8b6940 100644 --- a/scope.go +++ b/scope.go @@ -355,6 +355,10 @@ func (s *scope) decorateRequest(req *http.Request) (*http.Request, url.Values) { // Rewrite possible previous Basic Auth and send request // as cluster user. req.SetBasicAuth(s.clusterUser.name, s.clusterUser.password) + // Delete possible X-ClickHouse headers, + // it is not allowed to use X-ClickHouse HTTP headers and other authentication methods simultaneously + req.Header.Del("X-ClickHouse-User") + req.Header.Del("X-ClickHouse-Key") // Send request to the chosen host from cluster. req.URL.Scheme = s.host.addr.Scheme diff --git a/utils.go b/utils.go index 53e73b16..a0d44c55 100644 --- a/utils.go +++ b/utils.go @@ -21,8 +21,15 @@ func respondWith(rw http.ResponseWriter, err error, status int) { } // getAuth retrieves auth credentials from request -// according to CH documentation @see "http://clickhouse.readthedocs.io/en/latest/reference_en.html#HTTP interface" +// according to CH documentation @see "https://clickhouse.yandex/docs/en/interfaces/http/" func getAuth(req *http.Request) (string, string) { + // check X-ClickHouse- headers + name := req.Header.Get("X-ClickHouse-User") + pass := req.Header.Get("X-ClickHouse-Key") + if name != "" { + return name, pass + } + // if header is empty - check basicAuth if name, pass, ok := req.BasicAuth(); ok { return name, pass }