From b7bcb2a414c566a973211ec5f1f245494d390e28 Mon Sep 17 00:00:00 2001 From: David Adams Date: Mon, 19 Oct 2015 08:59:24 -0500 Subject: [PATCH] Add HTTP request header X-Consul-Token Add support for an X-Consul-Token HTTP request header to specify the token with which this request should be fulfilled. The header would have precedence over the responding Agent's default token, but would have lower precedence than a token specified in the query string. --- command/agent/http.go | 7 ++++- command/agent/http_test.go | 28 ++++++++++++++++++++ website/source/docs/agent/http.html.markdown | 5 ++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/command/agent/http.go b/command/agent/http.go index 22f1c118eb..02c20b3a43 100644 --- a/command/agent/http.go +++ b/command/agent/http.go @@ -463,13 +463,18 @@ func (s *HTTPServer) parseDC(req *http.Request, dc *string) { } } -// parseToken is used to parse the ?token query param +// parseToken is used to parse the ?token query param or the X-Consul-Token header func (s *HTTPServer) parseToken(req *http.Request, token *string) { if other := req.URL.Query().Get("token"); other != "" { *token = other return } + if other := req.Header.Get("X-Consul-Token"); other != "" { + *token = other + return + } + // Set the AtlasACLToken if SCADA if s.addr == scadaHTTPAddr && s.agent.config.AtlasACLToken != "" { *token = s.agent.config.AtlasACLToken diff --git a/command/agent/http_test.go b/command/agent/http_test.go index 9869b258dd..1f13f3a4bb 100644 --- a/command/agent/http_test.go +++ b/command/agent/http_test.go @@ -472,6 +472,22 @@ func TestACLResolution(t *testing.T) { t.Fatalf("err: %v", err) } + // Request with header token only + reqHeaderToken, err := http.NewRequest("GET", + "/v1/catalog/nodes", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + reqHeaderToken.Header.Add("X-Consul-Token", "bar") + + // Request with header and querystring tokens + reqBothTokens, err := http.NewRequest("GET", + "/v1/catalog/nodes?token=baz", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + reqBothTokens.Header.Add("X-Consul-Token", "zap") + httpTest(t, func(srv *HTTPServer) { // Check when no token is set srv.agent.config.ACLToken = "" @@ -513,6 +529,18 @@ func TestACLResolution(t *testing.T) { if token != "foo" { t.Fatalf("bad: %s", token) } + + // Header token has precedence over agent token + srv.parseToken(reqHeaderToken, &token) + if token != "bar" { + t.Fatalf("bad: %s", token) + } + + // Querystring token has precendence over header and agent tokens + srv.parseToken(reqBothTokens, &token) + if token != "baz" { + t.Fatalf("bad: %s", token) + } }) } diff --git a/website/source/docs/agent/http.html.markdown b/website/source/docs/agent/http.html.markdown index 9e1ae0b9be..d3fa365a2e 100644 --- a/website/source/docs/agent/http.html.markdown +++ b/website/source/docs/agent/http.html.markdown @@ -91,5 +91,6 @@ on the query string, formatted JSON will be returned. Several endpoints in Consul use or require ACL tokens to operate. An agent can be configured to use a default token in requests using the `acl_token` configuration option. However, the token can also be specified per-request -by using the `token` query parameter. This will take precedent over the -default token. +by using the `X-Consul-Token` request header or the `token` querystring +parameter. The request header takes precedence over the default token, and +the querystring parameter takes precedence over everything.