mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
When calling the client identity renew API, it is possible the target node ID is provided by either the URI or within the request body. This change fixes a bug where all calls using a node_id query parameter would be reject as it failed to decode the empty request body. Co-authored-by: Tim Gross <tgross@hashicorp.com>
238 lines
5.5 KiB
Go
238 lines
5.5 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package agent
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/nomad/ci"
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
"github.com/hashicorp/nomad/testutil"
|
|
"github.com/shoenig/test/must"
|
|
)
|
|
|
|
func TestHTTPServer_NodeIdentityGetRequest(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
t.Run("405 invalid method", func(t *testing.T) {
|
|
httpTest(t, cb, func(s *TestAgent) {
|
|
respW := httptest.NewRecorder()
|
|
|
|
badMethods := []string{
|
|
http.MethodConnect,
|
|
http.MethodDelete,
|
|
http.MethodHead,
|
|
http.MethodOptions,
|
|
http.MethodPatch,
|
|
http.MethodPost,
|
|
http.MethodPut,
|
|
http.MethodTrace,
|
|
}
|
|
|
|
for _, method := range badMethods {
|
|
req, err := http.NewRequest(method, "/v1/client/identity", nil)
|
|
must.NoError(t, err)
|
|
|
|
_, err = s.Server.NodeIdentityGetRequest(respW, req)
|
|
must.ErrorContains(t, err, "Invalid method")
|
|
|
|
codedErr, ok := err.(HTTPCodedError)
|
|
must.True(t, ok)
|
|
must.Eq(t, http.StatusMethodNotAllowed, codedErr.Code())
|
|
must.Eq(t, ErrInvalidMethod, codedErr.Error())
|
|
}
|
|
})
|
|
})
|
|
|
|
t.Run("400 query param with unknown node", func(t *testing.T) {
|
|
httpTest(t, nil, func(s *TestAgent) {
|
|
|
|
respW := httptest.NewRecorder()
|
|
|
|
req, err := http.NewRequest(
|
|
http.MethodGet,
|
|
"/v1/client/identity?node_id="+uuid.Generate(),
|
|
nil,
|
|
)
|
|
must.NoError(t, err)
|
|
|
|
_, err = s.Server.NodeIdentityGetRequest(respW, req)
|
|
must.ErrorContains(t, err, "Unknown node")
|
|
})
|
|
})
|
|
|
|
t.Run("200 ok query param", func(t *testing.T) {
|
|
|
|
// Enable the client, so we have something to renew.
|
|
configFn := func(c *Config) { c.Client.Enabled = true }
|
|
|
|
httpTest(t, configFn, func(s *TestAgent) {
|
|
|
|
respW := httptest.NewRecorder()
|
|
|
|
req, err := http.NewRequest(
|
|
http.MethodGet,
|
|
"/v1/client/identity?node_id="+s.client.NodeID(),
|
|
nil,
|
|
)
|
|
must.NoError(t, err)
|
|
|
|
obj, err := s.Server.NodeIdentityGetRequest(respW, req)
|
|
must.NoError(t, err)
|
|
must.Eq(t, http.StatusOK, respW.Code)
|
|
|
|
resp, ok := obj.(structs.NodeIdentityGetResp)
|
|
must.True(t, ok)
|
|
|
|
must.MapLen(t, 9, resp.Claims)
|
|
|
|
must.MapContainsKeys(t, resp.Claims, []string{
|
|
"aud",
|
|
"exp",
|
|
"jti",
|
|
"nbf",
|
|
"sub",
|
|
"iat",
|
|
"nomad_node_datacenter",
|
|
"nomad_node_id",
|
|
"nomad_node_pool",
|
|
})
|
|
|
|
must.MapContainsValues(t, resp.Claims, []any{
|
|
"nomadproject.io",
|
|
s.client.NodeID(),
|
|
s.client.Datacenter(),
|
|
s.client.Node().NodePool,
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestHTTPServer_NodeIdentityRenewRequest(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
t.Run("405 invalid method", func(t *testing.T) {
|
|
httpTest(t, nil, func(s *TestAgent) {
|
|
respW := httptest.NewRecorder()
|
|
|
|
badMethods := []string{
|
|
http.MethodConnect,
|
|
http.MethodDelete,
|
|
http.MethodGet,
|
|
http.MethodHead,
|
|
http.MethodOptions,
|
|
http.MethodPatch,
|
|
http.MethodTrace,
|
|
}
|
|
|
|
for _, method := range badMethods {
|
|
req, err := http.NewRequest(method, "/v1/client/identity/renew", nil)
|
|
must.NoError(t, err)
|
|
|
|
_, err = s.Server.NodeIdentityRenewRequest(respW, req)
|
|
must.ErrorContains(t, err, "Invalid method")
|
|
|
|
codedErr, ok := err.(HTTPCodedError)
|
|
must.True(t, ok)
|
|
must.Eq(t, http.StatusMethodNotAllowed, codedErr.Code())
|
|
must.Eq(t, ErrInvalidMethod, codedErr.Error())
|
|
}
|
|
})
|
|
})
|
|
|
|
t.Run("400 body with unknown node", func(t *testing.T) {
|
|
httpTest(t, nil, func(s *TestAgent) {
|
|
|
|
reqObj := structs.NodeIdentityRenewReq{
|
|
NodeID: uuid.Generate(),
|
|
QueryOptions: structs.QueryOptions{
|
|
Region: s.config().Region,
|
|
},
|
|
}
|
|
|
|
buf := encodeReq(reqObj)
|
|
|
|
respW := httptest.NewRecorder()
|
|
|
|
req, err := http.NewRequest(http.MethodPost, "/v1/client/identity/renew", buf)
|
|
must.NoError(t, err)
|
|
|
|
_, err = s.Server.NodeIdentityRenewRequest(respW, req)
|
|
must.ErrorContains(t, err, "Unknown node")
|
|
})
|
|
})
|
|
|
|
t.Run("400 query param with unknown node", func(t *testing.T) {
|
|
httpTest(t, nil, func(s *TestAgent) {
|
|
|
|
respW := httptest.NewRecorder()
|
|
|
|
req, err := http.NewRequest(
|
|
http.MethodPost,
|
|
"/v1/client/identity/renew?node_id="+uuid.Generate(),
|
|
nil,
|
|
)
|
|
must.NoError(t, err)
|
|
|
|
_, err = s.Server.NodeIdentityRenewRequest(respW, req)
|
|
must.ErrorContains(t, err, "Unknown node")
|
|
})
|
|
})
|
|
|
|
t.Run("200 ok body", func(t *testing.T) {
|
|
|
|
// Enable the client, so we have something to renew.
|
|
configFn := func(c *Config) { c.Client.Enabled = true }
|
|
|
|
httpTest(t, configFn, func(s *TestAgent) {
|
|
|
|
testutil.WaitForClient(t, s.RPC, s.client.NodeID(), s.config().Region)
|
|
|
|
reqObj := structs.NodeIdentityRenewReq{NodeID: s.client.NodeID()}
|
|
|
|
buf := encodeReq(reqObj)
|
|
|
|
respW := httptest.NewRecorder()
|
|
|
|
req, err := http.NewRequest(http.MethodPost, "/v1/client/identity/renew", buf)
|
|
must.NoError(t, err)
|
|
|
|
obj, err := s.Server.NodeIdentityRenewRequest(respW, req)
|
|
must.NoError(t, err)
|
|
|
|
_, ok := obj.(structs.NodeIdentityRenewResp)
|
|
must.True(t, ok)
|
|
})
|
|
})
|
|
|
|
t.Run("200 ok query param", func(t *testing.T) {
|
|
|
|
// Enable the client, so we have something to renew.
|
|
configFn := func(c *Config) { c.Client.Enabled = true }
|
|
|
|
httpTest(t, configFn, func(s *TestAgent) {
|
|
|
|
testutil.WaitForClient(t, s.RPC, s.client.NodeID(), s.config().Region)
|
|
|
|
respW := httptest.NewRecorder()
|
|
|
|
req, err := http.NewRequest(
|
|
http.MethodPost,
|
|
"/v1/client/identity/renew?node_id="+s.client.NodeID(),
|
|
nil,
|
|
)
|
|
must.NoError(t, err)
|
|
|
|
obj, err := s.Server.NodeIdentityRenewRequest(respW, req)
|
|
must.NoError(t, err)
|
|
|
|
_, ok := obj.(structs.NodeIdentityRenewResp)
|
|
must.True(t, ok)
|
|
})
|
|
})
|
|
}
|