2017-08-19 23:49:53 +00:00
|
|
|
package nomad
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
2022-07-15 13:20:50 +00:00
|
|
|
"time"
|
2017-08-19 23:49:53 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/nomad/acl"
|
2022-03-15 12:42:43 +00:00
|
|
|
"github.com/hashicorp/nomad/ci"
|
2022-07-15 13:20:50 +00:00
|
|
|
"github.com/hashicorp/nomad/helper/pointer"
|
2017-09-29 16:58:48 +00:00
|
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
2017-08-19 23:49:53 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
2017-10-23 19:50:37 +00:00
|
|
|
"github.com/hashicorp/nomad/testutil"
|
2022-07-15 13:20:50 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2017-08-19 23:49:53 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestResolveACLToken(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-10-23 19:50:37 +00:00
|
|
|
|
2022-07-15 13:20:50 +00:00
|
|
|
testServer, _, testServerCleanup := TestACLServer(t, nil)
|
|
|
|
defer testServerCleanup()
|
|
|
|
testutil.WaitForLeader(t, testServer.RPC)
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
testFn func(testServer *Server)
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "leader token",
|
|
|
|
testFn: func(testServer *Server) {
|
|
|
|
|
|
|
|
// Check the leader ACL token is correctly set.
|
|
|
|
leaderACL := testServer.getLeaderAcl()
|
|
|
|
require.NotEmpty(t, leaderACL)
|
|
|
|
|
|
|
|
// Resolve the token and ensure it's a management token.
|
|
|
|
aclResp, err := testServer.ResolveToken(leaderACL)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, aclResp)
|
|
|
|
require.True(t, aclResp.IsManagement())
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "anonymous token",
|
|
|
|
testFn: func(testServer *Server) {
|
|
|
|
|
|
|
|
// Call the function with an empty input secret ID which is
|
|
|
|
// classed as representing anonymous access in clusters with
|
|
|
|
// ACLs enabled.
|
|
|
|
aclResp, err := testServer.ResolveToken("")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, aclResp)
|
|
|
|
require.False(t, aclResp.IsManagement())
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "token not found",
|
|
|
|
testFn: func(testServer *Server) {
|
|
|
|
|
|
|
|
// Call the function with randomly generated secret ID which
|
|
|
|
// does not exist within state.
|
|
|
|
aclResp, err := testServer.ResolveToken(uuid.Generate())
|
|
|
|
require.Equal(t, structs.ErrTokenNotFound, err)
|
|
|
|
require.Nil(t, aclResp)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "token expired",
|
|
|
|
testFn: func(testServer *Server) {
|
|
|
|
|
|
|
|
// Create a mock token with an expiration time long in the
|
|
|
|
// past, and upsert.
|
|
|
|
token := mock.ACLToken()
|
|
|
|
token.ExpirationTime = pointer.Of(time.Date(
|
|
|
|
1970, time.January, 1, 0, 0, 0, 0, time.UTC))
|
|
|
|
|
|
|
|
err := testServer.State().UpsertACLTokens(
|
|
|
|
structs.MsgTypeTestSetup, 10, []*structs.ACLToken{token})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Perform the function call which should result in finding the
|
|
|
|
// token has expired.
|
|
|
|
aclResp, err := testServer.ResolveToken(uuid.Generate())
|
|
|
|
require.Equal(t, structs.ErrTokenNotFound, err)
|
|
|
|
require.Nil(t, aclResp)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "management token",
|
|
|
|
testFn: func(testServer *Server) {
|
|
|
|
|
|
|
|
// Generate a management token and upsert this.
|
|
|
|
managementToken := mock.ACLToken()
|
|
|
|
managementToken.Type = structs.ACLManagementToken
|
|
|
|
managementToken.Policies = nil
|
|
|
|
|
|
|
|
err := testServer.State().UpsertACLTokens(
|
|
|
|
structs.MsgTypeTestSetup, 10, []*structs.ACLToken{managementToken})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Resolve the token and check that we received a management
|
|
|
|
// ACL.
|
|
|
|
aclResp, err := testServer.ResolveToken(managementToken.SecretID)
|
|
|
|
require.Nil(t, err)
|
|
|
|
require.NotNil(t, aclResp)
|
|
|
|
require.True(t, aclResp.IsManagement())
|
|
|
|
require.Equal(t, acl.ManagementACL, aclResp)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "client token",
|
|
|
|
testFn: func(testServer *Server) {
|
|
|
|
|
|
|
|
// Generate a client token with associated policies and upsert
|
|
|
|
// these.
|
|
|
|
policy1 := mock.ACLPolicy()
|
|
|
|
policy2 := mock.ACLPolicy()
|
|
|
|
err := testServer.State().UpsertACLPolicies(
|
|
|
|
structs.MsgTypeTestSetup, 10, []*structs.ACLPolicy{policy1, policy2})
|
|
|
|
|
|
|
|
clientToken := mock.ACLToken()
|
|
|
|
clientToken.Policies = []string{policy1.Name, policy2.Name}
|
|
|
|
err = testServer.State().UpsertACLTokens(
|
|
|
|
structs.MsgTypeTestSetup, 20, []*structs.ACLToken{clientToken})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Resolve the token and check that we received a client
|
|
|
|
// ACL with appropriate permissions.
|
|
|
|
aclResp, err := testServer.ResolveToken(clientToken.SecretID)
|
|
|
|
require.Nil(t, err)
|
|
|
|
require.NotNil(t, aclResp)
|
|
|
|
require.False(t, aclResp.IsManagement())
|
|
|
|
|
|
|
|
allowed := aclResp.AllowNamespaceOperation("default", acl.NamespaceCapabilityListJobs)
|
|
|
|
require.True(t, allowed)
|
|
|
|
allowed = aclResp.AllowNamespaceOperation("other", acl.NamespaceCapabilityListJobs)
|
|
|
|
require.False(t, allowed)
|
|
|
|
|
|
|
|
// Resolve the same token again and ensure we get the same
|
|
|
|
// result.
|
|
|
|
aclResp2, err := testServer.ResolveToken(clientToken.SecretID)
|
|
|
|
require.Nil(t, err)
|
|
|
|
require.NotNil(t, aclResp2)
|
|
|
|
require.Equal(t, aclResp, aclResp2)
|
|
|
|
|
|
|
|
// Bust the cache by upserting the policy
|
|
|
|
err = testServer.State().UpsertACLPolicies(
|
|
|
|
structs.MsgTypeTestSetup, 30, []*structs.ACLPolicy{policy1})
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
|
|
|
// Resolve the same token again, should get different value
|
|
|
|
aclResp3, err := testServer.ResolveToken(clientToken.SecretID)
|
|
|
|
require.Nil(t, err)
|
|
|
|
require.NotNil(t, aclResp3)
|
|
|
|
require.NotEqual(t, aclResp2, aclResp3)
|
|
|
|
},
|
|
|
|
},
|
2017-08-19 23:49:53 +00:00
|
|
|
}
|
|
|
|
|
2022-07-15 13:20:50 +00:00
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
tc.testFn(testServer)
|
|
|
|
})
|
2017-10-23 19:50:37 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-22 16:17:33 +00:00
|
|
|
|
|
|
|
func TestResolveSecretToken(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2020-03-22 16:17:33 +00:00
|
|
|
|
2022-07-15 13:20:50 +00:00
|
|
|
testServer, _, testServerCleanup := TestACLServer(t, nil)
|
|
|
|
defer testServerCleanup()
|
|
|
|
testutil.WaitForLeader(t, testServer.RPC)
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
testFn func(testServer *Server)
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "valid token",
|
|
|
|
testFn: func(testServer *Server) {
|
|
|
|
|
|
|
|
// Generate and upsert a token.
|
|
|
|
token := mock.ACLToken()
|
|
|
|
err := testServer.State().UpsertACLTokens(
|
|
|
|
structs.MsgTypeTestSetup, 10, []*structs.ACLToken{token})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Attempt to look up the token and perform checks.
|
|
|
|
tokenResp, err := testServer.ResolveSecretToken(token.SecretID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, tokenResp)
|
|
|
|
require.Equal(t, token, tokenResp)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "anonymous token",
|
|
|
|
testFn: func(testServer *Server) {
|
|
|
|
|
|
|
|
// Call the function with an empty input secret ID which is
|
|
|
|
// classed as representing anonymous access in clusters with
|
|
|
|
// ACLs enabled.
|
|
|
|
tokenResp, err := testServer.ResolveSecretToken("")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, tokenResp)
|
|
|
|
require.Equal(t, structs.AnonymousACLToken, tokenResp)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "token not found",
|
|
|
|
testFn: func(testServer *Server) {
|
|
|
|
|
|
|
|
// Call the function with randomly generated secret ID which
|
|
|
|
// does not exist within state.
|
|
|
|
tokenResp, err := testServer.ResolveSecretToken(uuid.Generate())
|
|
|
|
require.Equal(t, structs.ErrTokenNotFound, err)
|
|
|
|
require.Nil(t, tokenResp)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "token expired",
|
|
|
|
testFn: func(testServer *Server) {
|
|
|
|
|
|
|
|
// Create a mock token with an expiration time long in the
|
|
|
|
// past, and upsert.
|
|
|
|
token := mock.ACLToken()
|
|
|
|
token.ExpirationTime = pointer.Of(time.Date(
|
|
|
|
1970, time.January, 1, 0, 0, 0, 0, time.UTC))
|
|
|
|
|
|
|
|
err := testServer.State().UpsertACLTokens(
|
|
|
|
structs.MsgTypeTestSetup, 10, []*structs.ACLToken{token})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Perform the function call which should result in finding the
|
|
|
|
// token has expired.
|
|
|
|
tokenResp, err := testServer.ResolveSecretToken(uuid.Generate())
|
|
|
|
require.Equal(t, structs.ErrTokenNotFound, err)
|
|
|
|
require.Nil(t, tokenResp)
|
|
|
|
},
|
|
|
|
},
|
2020-03-22 16:17:33 +00:00
|
|
|
}
|
|
|
|
|
2022-07-15 13:20:50 +00:00
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
tc.testFn(testServer)
|
|
|
|
})
|
|
|
|
}
|
2020-03-22 16:17:33 +00:00
|
|
|
}
|