1package nomad
2
3import (
4	"testing"
5
6	lru "github.com/hashicorp/golang-lru"
7	"github.com/hashicorp/nomad/acl"
8	"github.com/hashicorp/nomad/helper/uuid"
9	"github.com/hashicorp/nomad/nomad/mock"
10	"github.com/hashicorp/nomad/nomad/state"
11	"github.com/hashicorp/nomad/nomad/structs"
12	"github.com/hashicorp/nomad/testutil"
13	"github.com/stretchr/testify/assert"
14)
15
16func TestResolveACLToken(t *testing.T) {
17	t.Parallel()
18
19	// Create mock state store and cache
20	state := state.TestStateStore(t)
21	cache, err := lru.New2Q(16)
22	assert.Nil(t, err)
23
24	// Create a policy / token
25	policy := mock.ACLPolicy()
26	policy2 := mock.ACLPolicy()
27	token := mock.ACLToken()
28	token.Policies = []string{policy.Name, policy2.Name}
29	token2 := mock.ACLToken()
30	token2.Type = structs.ACLManagementToken
31	token2.Policies = nil
32	err = state.UpsertACLPolicies(100, []*structs.ACLPolicy{policy, policy2})
33	assert.Nil(t, err)
34	err = state.UpsertACLTokens(110, []*structs.ACLToken{token, token2})
35	assert.Nil(t, err)
36
37	snap, err := state.Snapshot()
38	assert.Nil(t, err)
39
40	// Attempt resolution of blank token. Should return anonymous policy
41	aclObj, err := resolveTokenFromSnapshotCache(snap, cache, "")
42	assert.Nil(t, err)
43	assert.NotNil(t, aclObj)
44
45	// Attempt resolution of unknown token. Should fail.
46	randID := uuid.Generate()
47	aclObj, err = resolveTokenFromSnapshotCache(snap, cache, randID)
48	assert.Equal(t, structs.ErrTokenNotFound, err)
49	assert.Nil(t, aclObj)
50
51	// Attempt resolution of management token. Should get singleton.
52	aclObj, err = resolveTokenFromSnapshotCache(snap, cache, token2.SecretID)
53	assert.Nil(t, err)
54	assert.NotNil(t, aclObj)
55	assert.Equal(t, true, aclObj.IsManagement())
56	if aclObj != acl.ManagementACL {
57		t.Fatalf("expected singleton")
58	}
59
60	// Attempt resolution of client token
61	aclObj, err = resolveTokenFromSnapshotCache(snap, cache, token.SecretID)
62	assert.Nil(t, err)
63	assert.NotNil(t, aclObj)
64
65	// Check that the ACL object is sane
66	assert.Equal(t, false, aclObj.IsManagement())
67	allowed := aclObj.AllowNamespaceOperation("default", acl.NamespaceCapabilityListJobs)
68	assert.Equal(t, true, allowed)
69	allowed = aclObj.AllowNamespaceOperation("other", acl.NamespaceCapabilityListJobs)
70	assert.Equal(t, false, allowed)
71
72	// Resolve the same token again, should get cache value
73	aclObj2, err := resolveTokenFromSnapshotCache(snap, cache, token.SecretID)
74	assert.Nil(t, err)
75	assert.NotNil(t, aclObj2)
76	if aclObj != aclObj2 {
77		t.Fatalf("expected cached value")
78	}
79
80	// Bust the cache by upserting the policy
81	err = state.UpsertACLPolicies(120, []*structs.ACLPolicy{policy})
82	assert.Nil(t, err)
83	snap, err = state.Snapshot()
84	assert.Nil(t, err)
85
86	// Resolve the same token again, should get different value
87	aclObj3, err := resolveTokenFromSnapshotCache(snap, cache, token.SecretID)
88	assert.Nil(t, err)
89	assert.NotNil(t, aclObj3)
90	if aclObj == aclObj3 {
91		t.Fatalf("unexpected cached value")
92	}
93}
94
95func TestResolveACLToken_LeaderToken(t *testing.T) {
96	t.Parallel()
97	assert := assert.New(t)
98	s1, _, cleanupS1 := TestACLServer(t, nil)
99	defer cleanupS1()
100	testutil.WaitForLeader(t, s1.RPC)
101
102	leaderAcl := s1.getLeaderAcl()
103	assert.NotEmpty(leaderAcl)
104	token, err := s1.ResolveToken(leaderAcl)
105	assert.Nil(err)
106	if assert.NotNil(token) {
107		assert.True(token.IsManagement())
108	}
109}
110