1package state
2
3import (
4	// "reflect"
5	"testing"
6	"time"
7
8	"github.com/hashicorp/consul/acl"
9	"github.com/hashicorp/consul/agent/structs"
10	// "github.com/hashicorp/go-memdb"
11	// "github.com/pascaldekloe/goe/verify"
12
13	"github.com/stretchr/testify/require"
14)
15
16func setupGlobalManagement(t *testing.T, s *Store) {
17	policy := structs.ACLPolicy{
18		ID:          structs.ACLPolicyGlobalManagementID,
19		Name:        "global-management",
20		Description: "Builtin Policy that grants unlimited access",
21		Rules:       structs.ACLPolicyGlobalManagement,
22		Syntax:      acl.SyntaxCurrent,
23	}
24	policy.SetHash(true)
25	require.NoError(t, s.ACLPolicySet(1, &policy))
26}
27
28func setupAnonymous(t *testing.T, s *Store) {
29	token := structs.ACLToken{
30		AccessorID:  structs.ACLTokenAnonymousID,
31		SecretID:    "anonymous",
32		Description: "Anonymous Token",
33	}
34	token.SetHash(true)
35	require.NoError(t, s.ACLTokenSet(1, &token, false))
36}
37
38func testACLStateStore(t *testing.T) *Store {
39	s := testStateStore(t)
40	setupGlobalManagement(t, s)
41	setupAnonymous(t, s)
42	return s
43}
44
45func setupExtraPolicies(t *testing.T, s *Store) {
46	policies := structs.ACLPolicies{
47		&structs.ACLPolicy{
48			ID:          "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
49			Name:        "node-read",
50			Description: "Allows reading all node information",
51			Rules:       `node_prefix "" { policy = "read" }`,
52			Syntax:      acl.SyntaxCurrent,
53		},
54	}
55
56	for _, policy := range policies {
57		policy.SetHash(true)
58	}
59
60	require.NoError(t, s.ACLPolicyBatchSet(2, policies))
61}
62
63func testACLTokensStateStore(t *testing.T) *Store {
64	s := testACLStateStore(t)
65	setupExtraPolicies(t, s)
66	return s
67}
68
69func TestStateStore_ACLBootstrap(t *testing.T) {
70	t.Parallel()
71	token1 := &structs.ACLToken{
72		AccessorID:  "30fca056-9fbb-4455-b94a-bf0e2bc575d6",
73		SecretID:    "cbe1c6fd-d865-4034-9d6d-64fef7fb46a9",
74		Description: "Bootstrap Token (Global Management)",
75		Policies: []structs.ACLTokenPolicyLink{
76			{
77				ID: structs.ACLPolicyGlobalManagementID,
78			},
79		},
80		CreateTime: time.Now(),
81		Local:      false,
82		// DEPRECATED (ACL-Legacy-Compat) - This is used so that the bootstrap token is still visible via the v1 acl APIs
83		Type: structs.ACLTokenTypeManagement,
84	}
85
86	token2 := &structs.ACLToken{
87		AccessorID:  "fd5c17fa-1503-4422-a424-dd44cdf35919",
88		SecretID:    "7fd776b1-ded1-4d15-931b-db4770fc2317",
89		Description: "Bootstrap Token (Global Management)",
90		Policies: []structs.ACLTokenPolicyLink{
91			{
92				ID: structs.ACLPolicyGlobalManagementID,
93			},
94		},
95		CreateTime: time.Now(),
96		Local:      false,
97		// DEPRECATED (ACL-Legacy-Compat) - This is used so that the bootstrap token is still visible via the v1 acl APIs
98		Type: structs.ACLTokenTypeManagement,
99	}
100
101	s := testStateStore(t)
102	setupGlobalManagement(t, s)
103
104	canBootstrap, index, err := s.CanBootstrapACLToken()
105	require.NoError(t, err)
106	require.True(t, canBootstrap)
107	require.Equal(t, uint64(0), index)
108
109	// Perform a regular bootstrap.
110	require.NoError(t, s.ACLBootstrap(3, 0, token1, false))
111
112	// Make sure we can't bootstrap again
113	canBootstrap, index, err = s.CanBootstrapACLToken()
114	require.NoError(t, err)
115	require.False(t, canBootstrap)
116	require.Equal(t, uint64(3), index)
117
118	// Make sure another attempt fails.
119	err = s.ACLBootstrap(4, 0, token2, false)
120	require.Error(t, err)
121	require.Equal(t, structs.ACLBootstrapNotAllowedErr, err)
122
123	// Check that the bootstrap state remains the same.
124	canBootstrap, index, err = s.CanBootstrapACLToken()
125	require.NoError(t, err)
126	require.False(t, canBootstrap)
127	require.Equal(t, uint64(3), index)
128
129	// Make sure the ACLs are in an expected state.
130	_, tokens, err := s.ACLTokenList(nil, true, true, "")
131	require.NoError(t, err)
132	require.Len(t, tokens, 1)
133	require.Equal(t, token1, tokens[0])
134
135	// bootstrap reset
136	err = s.ACLBootstrap(32, index-1, token2, false)
137	require.Error(t, err)
138	require.Equal(t, structs.ACLBootstrapInvalidResetIndexErr, err)
139
140	// bootstrap reset
141	err = s.ACLBootstrap(32, index, token2, false)
142	require.NoError(t, err)
143
144	_, tokens, err = s.ACLTokenList(nil, true, true, "")
145	require.NoError(t, err)
146	require.Len(t, tokens, 2)
147}
148
149func TestStateStore_ACLToken_SetGet_Legacy(t *testing.T) {
150	t.Parallel()
151	t.Run("Legacy - Existing With Policies", func(t *testing.T) {
152		t.Parallel()
153		s := testACLTokensStateStore(t)
154
155		token := &structs.ACLToken{
156			AccessorID: "c8d0378c-566a-4535-8fc9-c883a8cc9849",
157			SecretID:   "6d48ce91-2558-4098-bdab-8737e4e57d5f",
158			Policies: []structs.ACLTokenPolicyLink{
159				structs.ACLTokenPolicyLink{
160					ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
161				},
162			},
163		}
164
165		require.NoError(t, s.ACLTokenSet(2, token, false))
166
167		// legacy flag is set so it should disallow setting this token
168		err := s.ACLTokenSet(3, token, true)
169		require.Error(t, err)
170	})
171
172	t.Run("Legacy - Empty Type", func(t *testing.T) {
173		t.Parallel()
174		s := testACLTokensStateStore(t)
175		token := &structs.ACLToken{
176			AccessorID: "271cd056-0038-4fd3-90e5-f97f50fb3ac8",
177			SecretID:   "c0056225-5785-43b3-9b77-3954f06d6aee",
178		}
179
180		require.NoError(t, s.ACLTokenSet(2, token, false))
181
182		// legacy flag is set so it should disallow setting this token
183		err := s.ACLTokenSet(3, token, true)
184		require.Error(t, err)
185	})
186
187	t.Run("Legacy - New", func(t *testing.T) {
188		t.Parallel()
189		s := testACLTokensStateStore(t)
190		token := &structs.ACLToken{
191			SecretID: "2989e271-6169-4f34-8fec-4618d70008fb",
192			Type:     structs.ACLTokenTypeClient,
193			Rules:    `service "" { policy = "read" }`,
194		}
195
196		require.NoError(t, s.ACLTokenSet(2, token, true))
197
198		idx, rtoken, err := s.ACLTokenGetBySecret(nil, token.SecretID)
199		require.NoError(t, err)
200		require.Equal(t, uint64(2), idx)
201		require.NotNil(t, rtoken)
202		require.Equal(t, "", rtoken.AccessorID)
203		require.Equal(t, "2989e271-6169-4f34-8fec-4618d70008fb", rtoken.SecretID)
204		require.Equal(t, "", rtoken.Description)
205		require.Len(t, rtoken.Policies, 0)
206		require.Equal(t, structs.ACLTokenTypeClient, rtoken.Type)
207		require.Equal(t, uint64(2), rtoken.CreateIndex)
208		require.Equal(t, uint64(2), rtoken.ModifyIndex)
209	})
210
211	t.Run("Legacy - Update", func(t *testing.T) {
212		t.Parallel()
213		s := testACLTokensStateStore(t)
214		original := &structs.ACLToken{
215			SecretID: "2989e271-6169-4f34-8fec-4618d70008fb",
216			Type:     structs.ACLTokenTypeClient,
217			Rules:    `service "" { policy = "read" }`,
218		}
219
220		require.NoError(t, s.ACLTokenSet(2, original, true))
221
222		updatedRules := `service "" { policy = "read" } service "foo" { policy = "deny"}`
223		update := &structs.ACLToken{
224			SecretID: "2989e271-6169-4f34-8fec-4618d70008fb",
225			Type:     structs.ACLTokenTypeClient,
226			Rules:    updatedRules,
227		}
228
229		require.NoError(t, s.ACLTokenSet(3, update, true))
230
231		idx, rtoken, err := s.ACLTokenGetBySecret(nil, original.SecretID)
232		require.NoError(t, err)
233		require.Equal(t, uint64(3), idx)
234		require.NotNil(t, rtoken)
235		require.Equal(t, "", rtoken.AccessorID)
236		require.Equal(t, "2989e271-6169-4f34-8fec-4618d70008fb", rtoken.SecretID)
237		require.Equal(t, "", rtoken.Description)
238		require.Len(t, rtoken.Policies, 0)
239		require.Equal(t, structs.ACLTokenTypeClient, rtoken.Type)
240		require.Equal(t, updatedRules, rtoken.Rules)
241		require.Equal(t, uint64(2), rtoken.CreateIndex)
242		require.Equal(t, uint64(3), rtoken.ModifyIndex)
243	})
244}
245
246func TestStateStore_ACLToken_SetGet(t *testing.T) {
247	t.Parallel()
248	t.Run("Missing Secret", func(t *testing.T) {
249		t.Parallel()
250		s := testACLTokensStateStore(t)
251		token := &structs.ACLToken{
252			AccessorID: "39171632-6f34-4411-827f-9416403687f4",
253		}
254
255		err := s.ACLTokenSet(2, token, false)
256		require.Error(t, err)
257		require.Equal(t, ErrMissingACLTokenSecret, err)
258	})
259
260	t.Run("Missing Accessor", func(t *testing.T) {
261		t.Parallel()
262		s := testACLTokensStateStore(t)
263		token := &structs.ACLToken{
264			SecretID: "39171632-6f34-4411-827f-9416403687f4",
265		}
266
267		err := s.ACLTokenSet(2, token, false)
268		require.Error(t, err)
269		require.Equal(t, ErrMissingACLTokenAccessor, err)
270	})
271
272	t.Run("Missing Policy ID", func(t *testing.T) {
273		t.Parallel()
274		s := testACLTokensStateStore(t)
275		token := &structs.ACLToken{
276			AccessorID: "daf37c07-d04d-4fd5-9678-a8206a57d61a",
277			SecretID:   "39171632-6f34-4411-827f-9416403687f4",
278			Policies: []structs.ACLTokenPolicyLink{
279				structs.ACLTokenPolicyLink{
280					Name: "no-id",
281				},
282			},
283		}
284
285		err := s.ACLTokenSet(2, token, false)
286		require.Error(t, err)
287	})
288
289	t.Run("Unresolvable Policy ID", func(t *testing.T) {
290		t.Parallel()
291		s := testACLTokensStateStore(t)
292		token := &structs.ACLToken{
293			AccessorID: "daf37c07-d04d-4fd5-9678-a8206a57d61a",
294			SecretID:   "39171632-6f34-4411-827f-9416403687f4",
295			Policies: []structs.ACLTokenPolicyLink{
296				structs.ACLTokenPolicyLink{
297					ID: "4f20e379-b496-4b99-9599-19a197126490",
298				},
299			},
300		}
301
302		err := s.ACLTokenSet(2, token, false)
303		require.Error(t, err)
304	})
305
306	t.Run("New", func(t *testing.T) {
307		t.Parallel()
308		s := testACLTokensStateStore(t)
309		token := &structs.ACLToken{
310			AccessorID: "daf37c07-d04d-4fd5-9678-a8206a57d61a",
311			SecretID:   "39171632-6f34-4411-827f-9416403687f4",
312			Policies: []structs.ACLTokenPolicyLink{
313				structs.ACLTokenPolicyLink{
314					ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
315				},
316			},
317		}
318
319		require.NoError(t, s.ACLTokenSet(2, token, false))
320
321		idx, rtoken, err := s.ACLTokenGetByAccessor(nil, "daf37c07-d04d-4fd5-9678-a8206a57d61a")
322		require.NoError(t, err)
323		require.Equal(t, uint64(2), idx)
324		// pointer equality
325		require.True(t, rtoken == token)
326		require.Equal(t, uint64(2), rtoken.CreateIndex)
327		require.Equal(t, uint64(2), rtoken.ModifyIndex)
328		require.Len(t, rtoken.Policies, 1)
329		require.Equal(t, "node-read", rtoken.Policies[0].Name)
330	})
331
332	t.Run("Update", func(t *testing.T) {
333		t.Parallel()
334		s := testACLTokensStateStore(t)
335		token := &structs.ACLToken{
336			AccessorID: "daf37c07-d04d-4fd5-9678-a8206a57d61a",
337			SecretID:   "39171632-6f34-4411-827f-9416403687f4",
338			Policies: []structs.ACLTokenPolicyLink{
339				structs.ACLTokenPolicyLink{
340					ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
341				},
342			},
343		}
344
345		require.NoError(t, s.ACLTokenSet(2, token, false))
346
347		updated := &structs.ACLToken{
348			AccessorID: "daf37c07-d04d-4fd5-9678-a8206a57d61a",
349			SecretID:   "39171632-6f34-4411-827f-9416403687f4",
350			Policies: []structs.ACLTokenPolicyLink{
351				structs.ACLTokenPolicyLink{
352					ID: structs.ACLPolicyGlobalManagementID,
353				},
354			},
355		}
356
357		require.NoError(t, s.ACLTokenSet(3, updated, false))
358
359		idx, rtoken, err := s.ACLTokenGetByAccessor(nil, "daf37c07-d04d-4fd5-9678-a8206a57d61a")
360		require.NoError(t, err)
361		require.Equal(t, uint64(3), idx)
362		// pointer equality
363		require.True(t, rtoken == updated)
364		require.Equal(t, uint64(2), rtoken.CreateIndex)
365		require.Equal(t, uint64(3), rtoken.ModifyIndex)
366		require.Len(t, rtoken.Policies, 1)
367		require.Equal(t, structs.ACLPolicyGlobalManagementID, rtoken.Policies[0].ID)
368		require.Equal(t, "global-management", rtoken.Policies[0].Name)
369	})
370}
371
372func TestStateStore_ACLTokens_UpsertBatchRead(t *testing.T) {
373	t.Parallel()
374
375	t.Run("CAS - Deleted", func(t *testing.T) {
376		t.Parallel()
377		s := testACLTokensStateStore(t)
378
379		// CAS op + nonexistent token should not work. This prevents modifying
380		// deleted tokens
381
382		tokens := structs.ACLTokens{
383			&structs.ACLToken{
384				AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
385				SecretID:   "00ff4564-dd96-4d1b-8ad6-578a08279f79",
386				RaftIndex:  structs.RaftIndex{CreateIndex: 2, ModifyIndex: 3},
387			},
388		}
389
390		require.NoError(t, s.ACLTokenBatchSet(2, tokens, true))
391
392		_, token, err := s.ACLTokenGetByAccessor(nil, tokens[0].AccessorID)
393		require.NoError(t, err)
394		require.Nil(t, token)
395	})
396
397	t.Run("CAS - Updated", func(t *testing.T) {
398		t.Parallel()
399		s := testACLTokensStateStore(t)
400
401		// CAS op + nonexistent token should not work. This prevents modifying
402		// deleted tokens
403
404		tokens := structs.ACLTokens{
405			&structs.ACLToken{
406				AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
407				SecretID:   "00ff4564-dd96-4d1b-8ad6-578a08279f79",
408			},
409		}
410
411		require.NoError(t, s.ACLTokenBatchSet(5, tokens, true))
412
413		updated := structs.ACLTokens{
414			&structs.ACLToken{
415				AccessorID:  "a4f68bd6-3af5-4f56-b764-3c6f20247879",
416				SecretID:    "00ff4564-dd96-4d1b-8ad6-578a08279f79",
417				Description: "wont update",
418				RaftIndex:   structs.RaftIndex{CreateIndex: 1, ModifyIndex: 4},
419			},
420		}
421
422		require.NoError(t, s.ACLTokenBatchSet(6, updated, true))
423
424		_, token, err := s.ACLTokenGetByAccessor(nil, tokens[0].AccessorID)
425		require.NoError(t, err)
426		require.NotNil(t, token)
427		require.Equal(t, "", token.Description)
428	})
429
430	t.Run("CAS - Already Exists", func(t *testing.T) {
431		t.Parallel()
432		s := testACLTokensStateStore(t)
433
434		tokens := structs.ACLTokens{
435			&structs.ACLToken{
436				AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
437				SecretID:   "00ff4564-dd96-4d1b-8ad6-578a08279f79",
438			},
439		}
440
441		require.NoError(t, s.ACLTokenBatchSet(5, tokens, true))
442
443		updated := structs.ACLTokens{
444			&structs.ACLToken{
445				AccessorID:  "a4f68bd6-3af5-4f56-b764-3c6f20247879",
446				SecretID:    "00ff4564-dd96-4d1b-8ad6-578a08279f79",
447				Description: "wont update",
448			},
449		}
450
451		require.NoError(t, s.ACLTokenBatchSet(6, updated, true))
452
453		_, token, err := s.ACLTokenGetByAccessor(nil, tokens[0].AccessorID)
454		require.NoError(t, err)
455		require.NotNil(t, token)
456		require.Equal(t, "", token.Description)
457	})
458
459	t.Run("Normal", func(t *testing.T) {
460		t.Parallel()
461		s := testACLTokensStateStore(t)
462
463		tokens := structs.ACLTokens{
464			&structs.ACLToken{
465				AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
466				SecretID:   "00ff4564-dd96-4d1b-8ad6-578a08279f79",
467			},
468			&structs.ACLToken{
469				AccessorID: "a2719052-40b3-4a4b-baeb-f3df1831a217",
470				SecretID:   "ff826eaf-4b88-4881-aaef-52b1089e5d5d",
471			},
472		}
473
474		require.NoError(t, s.ACLTokenBatchSet(2, tokens, false))
475
476		idx, rtokens, err := s.ACLTokenBatchGet(nil, []string{
477			"a4f68bd6-3af5-4f56-b764-3c6f20247879",
478			"a2719052-40b3-4a4b-baeb-f3df1831a217"})
479
480		require.NoError(t, err)
481		require.Equal(t, uint64(2), idx)
482		require.Len(t, rtokens, 2)
483		require.ElementsMatch(t, tokens, rtokens)
484		require.Equal(t, uint64(2), rtokens[0].CreateIndex)
485		require.Equal(t, uint64(2), rtokens[0].ModifyIndex)
486		require.Equal(t, uint64(2), rtokens[1].CreateIndex)
487		require.Equal(t, uint64(2), rtokens[1].ModifyIndex)
488	})
489
490	t.Run("Update", func(t *testing.T) {
491		t.Parallel()
492		s := testACLTokensStateStore(t)
493
494		tokens := structs.ACLTokens{
495			&structs.ACLToken{
496				AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
497				SecretID:   "00ff4564-dd96-4d1b-8ad6-578a08279f79",
498			},
499			&structs.ACLToken{
500				AccessorID: "a2719052-40b3-4a4b-baeb-f3df1831a217",
501				SecretID:   "ff826eaf-4b88-4881-aaef-52b1089e5d5d",
502			},
503		}
504
505		require.NoError(t, s.ACLTokenBatchSet(2, tokens, false))
506
507		updates := structs.ACLTokens{
508			&structs.ACLToken{
509				AccessorID:  "a4f68bd6-3af5-4f56-b764-3c6f20247879",
510				SecretID:    "00ff4564-dd96-4d1b-8ad6-578a08279f79",
511				Description: "first token",
512				Policies: []structs.ACLTokenPolicyLink{
513					structs.ACLTokenPolicyLink{
514						ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
515					},
516				},
517			},
518			&structs.ACLToken{
519				AccessorID:  "a2719052-40b3-4a4b-baeb-f3df1831a217",
520				SecretID:    "ff826eaf-4b88-4881-aaef-52b1089e5d5d",
521				Description: "second token",
522				Policies: []structs.ACLTokenPolicyLink{
523					structs.ACLTokenPolicyLink{
524						ID: structs.ACLPolicyGlobalManagementID,
525					},
526				},
527			},
528		}
529
530		require.NoError(t, s.ACLTokenBatchSet(3, updates, false))
531
532		idx, rtokens, err := s.ACLTokenBatchGet(nil, []string{
533			"a4f68bd6-3af5-4f56-b764-3c6f20247879",
534			"a2719052-40b3-4a4b-baeb-f3df1831a217"})
535
536		require.NoError(t, err)
537		require.Equal(t, uint64(3), idx)
538		require.Len(t, rtokens, 2)
539		rtokens.Sort()
540		require.Equal(t, "a2719052-40b3-4a4b-baeb-f3df1831a217", rtokens[0].AccessorID)
541		require.Equal(t, "ff826eaf-4b88-4881-aaef-52b1089e5d5d", rtokens[0].SecretID)
542		require.Equal(t, "second token", rtokens[0].Description)
543		require.Len(t, rtokens[0].Policies, 1)
544		require.Equal(t, structs.ACLPolicyGlobalManagementID, rtokens[0].Policies[0].ID)
545		require.Equal(t, "global-management", rtokens[0].Policies[0].Name)
546		require.Equal(t, uint64(2), rtokens[0].CreateIndex)
547		require.Equal(t, uint64(3), rtokens[0].ModifyIndex)
548
549		require.Equal(t, "a4f68bd6-3af5-4f56-b764-3c6f20247879", rtokens[1].AccessorID)
550		require.Equal(t, "00ff4564-dd96-4d1b-8ad6-578a08279f79", rtokens[1].SecretID)
551		require.Equal(t, "first token", rtokens[1].Description)
552		require.Len(t, rtokens[1].Policies, 1)
553		require.Equal(t, "a0625e95-9b3e-42de-a8d6-ceef5b6f3286", rtokens[1].Policies[0].ID)
554		require.Equal(t, "node-read", rtokens[1].Policies[0].Name)
555		require.Equal(t, uint64(2), rtokens[1].CreateIndex)
556		require.Equal(t, uint64(3), rtokens[1].ModifyIndex)
557	})
558}
559
560func TestStateStore_ACLTokens_ListUpgradeable(t *testing.T) {
561	t.Parallel()
562	s := testACLTokensStateStore(t)
563
564	require.NoError(t, s.ACLTokenSet(2, &structs.ACLToken{
565		SecretID: "34ec8eb3-095d-417a-a937-b439af7a8e8b",
566		Type:     structs.ACLTokenTypeManagement,
567	}, true))
568
569	require.NoError(t, s.ACLTokenSet(3, &structs.ACLToken{
570		SecretID: "8de2dd39-134d-4cb1-950b-b7ab96ea20ba",
571		Type:     structs.ACLTokenTypeManagement,
572	}, true))
573
574	require.NoError(t, s.ACLTokenSet(4, &structs.ACLToken{
575		SecretID: "548bdb8e-c0d6-477b-bcc4-67fb836e9e61",
576		Type:     structs.ACLTokenTypeManagement,
577	}, true))
578
579	require.NoError(t, s.ACLTokenSet(5, &structs.ACLToken{
580		SecretID: "3ee33676-d9b8-4144-bf0b-92618cff438b",
581		Type:     structs.ACLTokenTypeManagement,
582	}, true))
583
584	require.NoError(t, s.ACLTokenSet(6, &structs.ACLToken{
585		SecretID: "fa9d658a-6e26-42ab-a5f0-1ea05c893dee",
586		Type:     structs.ACLTokenTypeManagement,
587	}, true))
588
589	tokens, _, err := s.ACLTokenListUpgradeable(3)
590	require.NoError(t, err)
591	require.Len(t, tokens, 3)
592
593	tokens, _, err = s.ACLTokenListUpgradeable(10)
594	require.NoError(t, err)
595	require.Len(t, tokens, 5)
596
597	updates := structs.ACLTokens{
598		&structs.ACLToken{
599			AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
600			SecretID:   "34ec8eb3-095d-417a-a937-b439af7a8e8b",
601			Policies: []structs.ACLTokenPolicyLink{
602				structs.ACLTokenPolicyLink{
603					ID: structs.ACLPolicyGlobalManagementID,
604				},
605			},
606		},
607		&structs.ACLToken{
608			AccessorID: "54866514-3cf2-4fec-8a8a-710583831834",
609			SecretID:   "8de2dd39-134d-4cb1-950b-b7ab96ea20ba",
610			Policies: []structs.ACLTokenPolicyLink{
611				structs.ACLTokenPolicyLink{
612					ID: structs.ACLPolicyGlobalManagementID,
613				},
614			},
615		},
616		&structs.ACLToken{
617			AccessorID: "47eea4da-bda1-48a6-901c-3e36d2d9262f",
618			SecretID:   "548bdb8e-c0d6-477b-bcc4-67fb836e9e61",
619			Policies: []structs.ACLTokenPolicyLink{
620				structs.ACLTokenPolicyLink{
621					ID: structs.ACLPolicyGlobalManagementID,
622				},
623			},
624		},
625		&structs.ACLToken{
626			AccessorID: "af1dffe5-8ac2-4282-9336-aeed9f7d951a",
627			SecretID:   "3ee33676-d9b8-4144-bf0b-92618cff438b",
628			Policies: []structs.ACLTokenPolicyLink{
629				structs.ACLTokenPolicyLink{
630					ID: structs.ACLPolicyGlobalManagementID,
631				},
632			},
633		},
634		&structs.ACLToken{
635			AccessorID: "511df589-3316-4784-b503-6e25ead4d4e1",
636			SecretID:   "fa9d658a-6e26-42ab-a5f0-1ea05c893dee",
637			Policies: []structs.ACLTokenPolicyLink{
638				structs.ACLTokenPolicyLink{
639					ID: structs.ACLPolicyGlobalManagementID,
640				},
641			},
642		},
643	}
644
645	require.NoError(t, s.ACLTokenBatchSet(7, updates, false))
646
647	tokens, _, err = s.ACLTokenListUpgradeable(10)
648	require.NoError(t, err)
649	require.Len(t, tokens, 0)
650}
651
652func TestStateStore_ACLToken_List(t *testing.T) {
653	t.Parallel()
654	s := testACLTokensStateStore(t)
655
656	tokens := structs.ACLTokens{
657		// the local token
658		&structs.ACLToken{
659			AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
660			SecretID:   "34ec8eb3-095d-417a-a937-b439af7a8e8b",
661			Policies: []structs.ACLTokenPolicyLink{
662				structs.ACLTokenPolicyLink{
663					ID: structs.ACLPolicyGlobalManagementID,
664				},
665			},
666			Local: true,
667		},
668		// the global token
669		&structs.ACLToken{
670			AccessorID: "54866514-3cf2-4fec-8a8a-710583831834",
671			SecretID:   "8de2dd39-134d-4cb1-950b-b7ab96ea20ba",
672			Policies: []structs.ACLTokenPolicyLink{
673				structs.ACLTokenPolicyLink{
674					ID: structs.ACLPolicyGlobalManagementID,
675				},
676			},
677		},
678		// the policy specific token
679		&structs.ACLToken{
680			AccessorID: "47eea4da-bda1-48a6-901c-3e36d2d9262f",
681			SecretID:   "548bdb8e-c0d6-477b-bcc4-67fb836e9e61",
682			Policies: []structs.ACLTokenPolicyLink{
683				structs.ACLTokenPolicyLink{
684					ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
685				},
686			},
687		},
688		// the policy specific token and local
689		&structs.ACLToken{
690			AccessorID: "4915fc9d-3726-4171-b588-6c271f45eecd",
691			SecretID:   "f6998577-fd9b-4e6c-b202-cc3820513d32",
692			Policies: []structs.ACLTokenPolicyLink{
693				structs.ACLTokenPolicyLink{
694					ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
695				},
696			},
697			Local: true,
698		},
699	}
700
701	require.NoError(t, s.ACLTokenBatchSet(2, tokens, false))
702
703	type testCase struct {
704		name      string
705		local     bool
706		global    bool
707		policy    string
708		accessors []string
709	}
710
711	cases := []testCase{
712		{
713			name:   "Global",
714			local:  false,
715			global: true,
716			policy: "",
717			accessors: []string{
718				structs.ACLTokenAnonymousID,
719				"47eea4da-bda1-48a6-901c-3e36d2d9262f",
720				"54866514-3cf2-4fec-8a8a-710583831834",
721			},
722		},
723		{
724			name:   "Local",
725			local:  true,
726			global: false,
727			policy: "",
728			accessors: []string{
729				"4915fc9d-3726-4171-b588-6c271f45eecd",
730				"f1093997-b6c7-496d-bfb8-6b1b1895641b",
731			},
732		},
733		{
734			name:   "Policy",
735			local:  true,
736			global: true,
737			policy: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
738			accessors: []string{
739				"47eea4da-bda1-48a6-901c-3e36d2d9262f",
740				"4915fc9d-3726-4171-b588-6c271f45eecd",
741			},
742		},
743		{
744			name:   "Policy - Local",
745			local:  true,
746			global: false,
747			policy: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
748			accessors: []string{
749				"4915fc9d-3726-4171-b588-6c271f45eecd",
750			},
751		},
752		{
753			name:   "Policy - Global",
754			local:  false,
755			global: true,
756			policy: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
757			accessors: []string{
758				"47eea4da-bda1-48a6-901c-3e36d2d9262f",
759				"4915fc9d-3726-4171-b588-6c271f45eecd",
760			},
761		},
762		{
763			name:   "All",
764			local:  true,
765			global: true,
766			policy: "",
767			accessors: []string{
768				structs.ACLTokenAnonymousID,
769				"47eea4da-bda1-48a6-901c-3e36d2d9262f",
770				"4915fc9d-3726-4171-b588-6c271f45eecd",
771				"54866514-3cf2-4fec-8a8a-710583831834",
772				"f1093997-b6c7-496d-bfb8-6b1b1895641b",
773			},
774		},
775	}
776
777	for _, tc := range cases {
778		t.Run(tc.name, func(t *testing.T) {
779			t.Parallel()
780			_, tokens, err := s.ACLTokenList(nil, tc.local, tc.global, tc.policy)
781			require.NoError(t, err)
782			require.Len(t, tokens, len(tc.accessors))
783			tokens.Sort()
784			for i, token := range tokens {
785				require.Equal(t, tc.accessors[i], token.AccessorID)
786			}
787		})
788	}
789}
790
791func TestStateStore_ACLToken_Delete(t *testing.T) {
792	t.Parallel()
793
794	t.Run("Accessor", func(t *testing.T) {
795		t.Parallel()
796		s := testACLTokensStateStore(t)
797
798		token := &structs.ACLToken{
799			AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
800			SecretID:   "34ec8eb3-095d-417a-a937-b439af7a8e8b",
801			Policies: []structs.ACLTokenPolicyLink{
802				structs.ACLTokenPolicyLink{
803					ID: structs.ACLPolicyGlobalManagementID,
804				},
805			},
806			Local: true,
807		}
808
809		require.NoError(t, s.ACLTokenSet(2, token, false))
810
811		_, rtoken, err := s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
812		require.NoError(t, err)
813		require.NotNil(t, rtoken)
814
815		require.NoError(t, s.ACLTokenDeleteByAccessor(3, "f1093997-b6c7-496d-bfb8-6b1b1895641b"))
816
817		_, rtoken, err = s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
818		require.NoError(t, err)
819		require.Nil(t, rtoken)
820	})
821
822	t.Run("Secret", func(t *testing.T) {
823		t.Parallel()
824		s := testACLTokensStateStore(t)
825
826		token := &structs.ACLToken{
827			AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
828			SecretID:   "34ec8eb3-095d-417a-a937-b439af7a8e8b",
829			Policies: []structs.ACLTokenPolicyLink{
830				structs.ACLTokenPolicyLink{
831					ID: structs.ACLPolicyGlobalManagementID,
832				},
833			},
834			Local: true,
835		}
836
837		require.NoError(t, s.ACLTokenSet(2, token, false))
838
839		_, rtoken, err := s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
840		require.NoError(t, err)
841		require.NotNil(t, rtoken)
842
843		require.NoError(t, s.ACLTokenDeleteBySecret(3, "34ec8eb3-095d-417a-a937-b439af7a8e8b"))
844
845		_, rtoken, err = s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
846		require.NoError(t, err)
847		require.Nil(t, rtoken)
848	})
849
850	t.Run("Multiple", func(t *testing.T) {
851		t.Parallel()
852		s := testACLTokensStateStore(t)
853
854		tokens := structs.ACLTokens{
855			&structs.ACLToken{
856				AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
857				SecretID:   "34ec8eb3-095d-417a-a937-b439af7a8e8b",
858				Policies: []structs.ACLTokenPolicyLink{
859					structs.ACLTokenPolicyLink{
860						ID: structs.ACLPolicyGlobalManagementID,
861					},
862				},
863				Local: true,
864			},
865			&structs.ACLToken{
866				AccessorID: "a0bfe8d4-b2f3-4b48-b387-f28afb820eab",
867				SecretID:   "be444e46-fb95-4ccc-80d5-c873f34e6fa6",
868				Policies: []structs.ACLTokenPolicyLink{
869					structs.ACLTokenPolicyLink{
870						ID: structs.ACLPolicyGlobalManagementID,
871					},
872				},
873				Local: true,
874			},
875		}
876
877		require.NoError(t, s.ACLTokenBatchSet(2, tokens, false))
878
879		_, rtoken, err := s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
880		require.NoError(t, err)
881		require.NotNil(t, rtoken)
882		_, rtoken, err = s.ACLTokenGetByAccessor(nil, "a0bfe8d4-b2f3-4b48-b387-f28afb820eab")
883		require.NoError(t, err)
884		require.NotNil(t, rtoken)
885
886		require.NoError(t, s.ACLTokenBatchDelete(2, []string{
887			"f1093997-b6c7-496d-bfb8-6b1b1895641b",
888			"a0bfe8d4-b2f3-4b48-b387-f28afb820eab"}))
889
890		_, rtoken, err = s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
891		require.NoError(t, err)
892		require.Nil(t, rtoken)
893		_, rtoken, err = s.ACLTokenGetByAccessor(nil, "a0bfe8d4-b2f3-4b48-b387-f28afb820eab")
894		require.NoError(t, err)
895		require.Nil(t, rtoken)
896	})
897
898	t.Run("Anonymous", func(t *testing.T) {
899		t.Parallel()
900		s := testACLTokensStateStore(t)
901
902		require.Error(t, s.ACLTokenDeleteByAccessor(3, structs.ACLTokenAnonymousID))
903		require.Error(t, s.ACLTokenDeleteBySecret(3, "anonymous"))
904	})
905
906	t.Run("Not Found", func(t *testing.T) {
907		t.Parallel()
908		s := testACLStateStore(t)
909
910		// deletion of non-existant policies is not an error
911		require.NoError(t, s.ACLTokenDeleteByAccessor(3, "ea58a09c-2100-4aef-816b-8ee0ade77dcd"))
912		require.NoError(t, s.ACLTokenDeleteBySecret(3, "376d0cae-dd50-4213-9668-2c7797a7fb2d"))
913	})
914}
915
916func TestStateStore_ACLPolicy_SetGet(t *testing.T) {
917	t.Parallel()
918
919	t.Run("Missing ID", func(t *testing.T) {
920		t.Parallel()
921		s := testACLStateStore(t)
922
923		policy := structs.ACLPolicy{
924			Name:        "test-policy",
925			Description: "test",
926			Rules:       `keyring = "write"`,
927		}
928
929		require.Error(t, s.ACLPolicySet(3, &policy))
930	})
931
932	t.Run("Missing Name", func(t *testing.T) {
933		t.Parallel()
934		s := testACLStateStore(t)
935
936		policy := structs.ACLPolicy{
937			ID:          "2c74a9b8-271c-4a21-b727-200db397c01c",
938			Description: "test",
939			Rules:       `keyring = "write"`,
940		}
941
942		require.Error(t, s.ACLPolicySet(3, &policy))
943	})
944
945	t.Run("Global Management", func(t *testing.T) {
946		t.Parallel()
947		s := testACLStateStore(t)
948
949		t.Run("Rules", func(t *testing.T) {
950			t.Parallel()
951
952			policy := structs.ACLPolicy{
953				ID:          structs.ACLPolicyGlobalManagementID,
954				Name:        "global-management",
955				Description: "Global Management",
956				Rules:       `acl = "write"`,
957			}
958
959			require.Error(t, s.ACLPolicySet(3, &policy))
960		})
961
962		t.Run("Datacenters", func(t *testing.T) {
963			t.Parallel()
964
965			policy := structs.ACLPolicy{
966				ID:          structs.ACLPolicyGlobalManagementID,
967				Name:        "global-management",
968				Description: "Global Management",
969				Rules:       structs.ACLPolicyGlobalManagement,
970				Datacenters: []string{"dc1"},
971			}
972
973			require.Error(t, s.ACLPolicySet(3, &policy))
974		})
975
976		t.Run("Change", func(t *testing.T) {
977			t.Parallel()
978
979			policy := structs.ACLPolicy{
980				ID:          structs.ACLPolicyGlobalManagementID,
981				Name:        "management",
982				Description: "Modified",
983				Rules:       structs.ACLPolicyGlobalManagement,
984			}
985
986			require.NoError(t, s.ACLPolicySet(3, &policy))
987
988			_, rpolicy, err := s.ACLPolicyGetByName(nil, "management")
989			require.NoError(t, err)
990			require.NotNil(t, rpolicy)
991			require.Equal(t, structs.ACLPolicyGlobalManagementID, rpolicy.ID)
992			require.Equal(t, "management", rpolicy.Name)
993			require.Equal(t, "Modified", rpolicy.Description)
994			require.Equal(t, uint64(1), rpolicy.CreateIndex)
995			require.Equal(t, uint64(3), rpolicy.ModifyIndex)
996		})
997	})
998
999	t.Run("New", func(t *testing.T) {
1000		t.Parallel()
1001		// this actually creates a new policy - we just need to verify it.
1002		s := testACLStateStore(t)
1003
1004		policy := structs.ACLPolicy{
1005			ID:          "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
1006			Name:        "node-read",
1007			Description: "Allows reading all node information",
1008			Rules:       `node_prefix "" { policy = "read" }`,
1009			Syntax:      acl.SyntaxCurrent,
1010			Datacenters: []string{"dc1"},
1011		}
1012
1013		require.NoError(t, s.ACLPolicySet(3, &policy))
1014
1015		idx, rpolicy, err := s.ACLPolicyGetByID(nil, "a0625e95-9b3e-42de-a8d6-ceef5b6f3286")
1016		require.Equal(t, uint64(3), idx)
1017		require.NoError(t, err)
1018		require.NotNil(t, rpolicy)
1019		require.Equal(t, "node-read", rpolicy.Name)
1020		require.Equal(t, "Allows reading all node information", rpolicy.Description)
1021		require.Equal(t, `node_prefix "" { policy = "read" }`, rpolicy.Rules)
1022		require.Equal(t, acl.SyntaxCurrent, rpolicy.Syntax)
1023		require.Len(t, rpolicy.Datacenters, 1)
1024		require.Equal(t, "dc1", rpolicy.Datacenters[0])
1025		require.Equal(t, uint64(3), rpolicy.CreateIndex)
1026		require.Equal(t, uint64(3), rpolicy.ModifyIndex)
1027
1028		// also verify the global management policy that testACLStateStore Set while we are at it.
1029		idx, rpolicy, err = s.ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID)
1030		require.Equal(t, uint64(3), idx)
1031		require.NoError(t, err)
1032		require.NotNil(t, rpolicy)
1033		require.Equal(t, "global-management", rpolicy.Name)
1034		require.Equal(t, "Builtin Policy that grants unlimited access", rpolicy.Description)
1035		require.Equal(t, structs.ACLPolicyGlobalManagement, rpolicy.Rules)
1036		require.Equal(t, acl.SyntaxCurrent, rpolicy.Syntax)
1037		require.Len(t, rpolicy.Datacenters, 0)
1038		require.Equal(t, uint64(1), rpolicy.CreateIndex)
1039		require.Equal(t, uint64(1), rpolicy.ModifyIndex)
1040	})
1041
1042	t.Run("Update", func(t *testing.T) {
1043		t.Parallel()
1044		// this creates the node read policy which we can update
1045		s := testACLTokensStateStore(t)
1046
1047		update := structs.ACLPolicy{
1048			ID:          "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
1049			Name:        "node-read-modified",
1050			Description: "Modified",
1051			Rules:       `node_prefix "" { policy = "read" } node "secret" { policy = "deny" }`,
1052			Syntax:      acl.SyntaxCurrent,
1053			Datacenters: []string{"dc1", "dc2"},
1054		}
1055
1056		require.NoError(t, s.ACLPolicySet(3, &update))
1057
1058		idx, rpolicy, err := s.ACLPolicyGetByID(nil, "a0625e95-9b3e-42de-a8d6-ceef5b6f3286")
1059		require.Equal(t, uint64(3), idx)
1060		require.NoError(t, err)
1061		require.NotNil(t, rpolicy)
1062		require.Equal(t, "node-read-modified", rpolicy.Name)
1063		require.Equal(t, "Modified", rpolicy.Description)
1064		require.Equal(t, `node_prefix "" { policy = "read" } node "secret" { policy = "deny" }`, rpolicy.Rules)
1065		require.Equal(t, acl.SyntaxCurrent, rpolicy.Syntax)
1066		require.ElementsMatch(t, []string{"dc1", "dc2"}, rpolicy.Datacenters)
1067		require.Equal(t, uint64(2), rpolicy.CreateIndex)
1068		require.Equal(t, uint64(3), rpolicy.ModifyIndex)
1069	})
1070}
1071
1072func TestStateStore_ACLPolicy_UpsertBatchRead(t *testing.T) {
1073	t.Parallel()
1074
1075	t.Run("Normal", func(t *testing.T) {
1076		t.Parallel()
1077		s := testACLStateStore(t)
1078
1079		policies := structs.ACLPolicies{
1080			&structs.ACLPolicy{
1081				ID:    "a4f68bd6-3af5-4f56-b764-3c6f20247879",
1082				Name:  "service-read",
1083				Rules: `service_prefix "" { policy = "read" }`,
1084			},
1085			&structs.ACLPolicy{
1086				ID:          "a2719052-40b3-4a4b-baeb-f3df1831a217",
1087				Name:        "acl-write-dc3",
1088				Description: "Can manage ACLs in dc3",
1089				Datacenters: []string{"dc3"},
1090				Rules:       `acl = "write"`,
1091			},
1092		}
1093
1094		require.NoError(t, s.ACLPolicyBatchSet(2, policies))
1095
1096		idx, rpolicies, err := s.ACLPolicyBatchGet(nil, []string{
1097			"a4f68bd6-3af5-4f56-b764-3c6f20247879",
1098			"a2719052-40b3-4a4b-baeb-f3df1831a217"})
1099
1100		require.NoError(t, err)
1101		require.Equal(t, uint64(2), idx)
1102		require.Len(t, rpolicies, 2)
1103		require.ElementsMatch(t, policies, rpolicies)
1104		require.Equal(t, uint64(2), rpolicies[0].CreateIndex)
1105		require.Equal(t, uint64(2), rpolicies[0].ModifyIndex)
1106		require.Equal(t, uint64(2), rpolicies[1].CreateIndex)
1107		require.Equal(t, uint64(2), rpolicies[1].ModifyIndex)
1108	})
1109
1110	t.Run("Update", func(t *testing.T) {
1111		t.Parallel()
1112		s := testACLStateStore(t)
1113
1114		policies := structs.ACLPolicies{
1115			&structs.ACLPolicy{
1116				ID:    "a4f68bd6-3af5-4f56-b764-3c6f20247879",
1117				Name:  "service-read",
1118				Rules: `service_prefix "" { policy = "read" }`,
1119			},
1120			&structs.ACLPolicy{
1121				ID:          "a2719052-40b3-4a4b-baeb-f3df1831a217",
1122				Name:        "acl-write-dc3",
1123				Description: "Can manage ACLs in dc3",
1124				Datacenters: []string{"dc3"},
1125				Rules:       `acl = "write"`,
1126			},
1127		}
1128
1129		require.NoError(t, s.ACLPolicyBatchSet(2, policies))
1130
1131		updates := structs.ACLPolicies{
1132			&structs.ACLPolicy{
1133				ID:          "a4f68bd6-3af5-4f56-b764-3c6f20247879",
1134				Name:        "service-write",
1135				Rules:       `service_prefix "" { policy = "write" }`,
1136				Datacenters: []string{"dc1"},
1137			},
1138			&structs.ACLPolicy{
1139				ID:          "a2719052-40b3-4a4b-baeb-f3df1831a217",
1140				Name:        "acl-write",
1141				Description: "Modified",
1142				Rules:       `acl = "write"`,
1143			},
1144		}
1145
1146		require.NoError(t, s.ACLPolicyBatchSet(3, updates))
1147
1148		idx, rpolicies, err := s.ACLPolicyBatchGet(nil, []string{
1149			"a4f68bd6-3af5-4f56-b764-3c6f20247879",
1150			"a2719052-40b3-4a4b-baeb-f3df1831a217"})
1151
1152		require.NoError(t, err)
1153		require.Equal(t, uint64(3), idx)
1154		require.Len(t, rpolicies, 2)
1155		rpolicies.Sort()
1156		require.Equal(t, "a2719052-40b3-4a4b-baeb-f3df1831a217", rpolicies[0].ID)
1157		require.Equal(t, "acl-write", rpolicies[0].Name)
1158		require.Equal(t, "Modified", rpolicies[0].Description)
1159		require.Equal(t, `acl = "write"`, rpolicies[0].Rules)
1160		require.Empty(t, rpolicies[0].Datacenters)
1161		require.Equal(t, uint64(2), rpolicies[0].CreateIndex)
1162		require.Equal(t, uint64(3), rpolicies[0].ModifyIndex)
1163
1164		require.Equal(t, "a4f68bd6-3af5-4f56-b764-3c6f20247879", rpolicies[1].ID)
1165		require.Equal(t, "service-write", rpolicies[1].Name)
1166		require.Equal(t, "", rpolicies[1].Description)
1167		require.Equal(t, `service_prefix "" { policy = "write" }`, rpolicies[1].Rules)
1168		require.ElementsMatch(t, []string{"dc1"}, rpolicies[1].Datacenters)
1169		require.Equal(t, uint64(2), rpolicies[1].CreateIndex)
1170		require.Equal(t, uint64(3), rpolicies[1].ModifyIndex)
1171	})
1172}
1173
1174func TestStateStore_ACLPolicy_List(t *testing.T) {
1175	t.Parallel()
1176	s := testACLStateStore(t)
1177
1178	policies := structs.ACLPolicies{
1179		&structs.ACLPolicy{
1180			ID:    "a4f68bd6-3af5-4f56-b764-3c6f20247879",
1181			Name:  "service-read",
1182			Rules: `service_prefix "" { policy = "read" }`,
1183		},
1184		&structs.ACLPolicy{
1185			ID:          "a2719052-40b3-4a4b-baeb-f3df1831a217",
1186			Name:        "acl-write-dc3",
1187			Description: "Can manage ACLs in dc3",
1188			Datacenters: []string{"dc3"},
1189			Rules:       `acl = "write"`,
1190		},
1191	}
1192
1193	require.NoError(t, s.ACLPolicyBatchSet(2, policies))
1194
1195	_, policies, err := s.ACLPolicyList(nil)
1196	require.NoError(t, err)
1197	require.Len(t, policies, 3)
1198	policies.Sort()
1199	require.Equal(t, structs.ACLPolicyGlobalManagementID, policies[0].ID)
1200	require.Equal(t, "global-management", policies[0].Name)
1201	require.Equal(t, "Builtin Policy that grants unlimited access", policies[0].Description)
1202	require.Empty(t, policies[0].Datacenters)
1203	require.NotEqual(t, []byte{}, policies[0].Hash)
1204	require.Equal(t, uint64(1), policies[0].CreateIndex)
1205	require.Equal(t, uint64(1), policies[0].ModifyIndex)
1206
1207	require.Equal(t, "a2719052-40b3-4a4b-baeb-f3df1831a217", policies[1].ID)
1208	require.Equal(t, "acl-write-dc3", policies[1].Name)
1209	require.Equal(t, "Can manage ACLs in dc3", policies[1].Description)
1210	require.ElementsMatch(t, []string{"dc3"}, policies[1].Datacenters)
1211	require.Nil(t, policies[1].Hash)
1212	require.Equal(t, uint64(2), policies[1].CreateIndex)
1213	require.Equal(t, uint64(2), policies[1].ModifyIndex)
1214
1215	require.Equal(t, "a4f68bd6-3af5-4f56-b764-3c6f20247879", policies[2].ID)
1216	require.Equal(t, "service-read", policies[2].Name)
1217	require.Equal(t, "", policies[2].Description)
1218	require.Empty(t, policies[2].Datacenters)
1219	require.Nil(t, policies[2].Hash)
1220	require.Equal(t, uint64(2), policies[2].CreateIndex)
1221	require.Equal(t, uint64(2), policies[2].ModifyIndex)
1222}
1223
1224func TestStateStore_ACLPolicy_Delete(t *testing.T) {
1225	t.Parallel()
1226
1227	t.Run("ID", func(t *testing.T) {
1228		t.Parallel()
1229		s := testACLStateStore(t)
1230
1231		policy := &structs.ACLPolicy{
1232			ID:    "f1093997-b6c7-496d-bfb8-6b1b1895641b",
1233			Name:  "test-policy",
1234			Rules: `acl = "read"`,
1235		}
1236
1237		require.NoError(t, s.ACLPolicySet(2, policy))
1238
1239		_, rpolicy, err := s.ACLPolicyGetByID(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
1240		require.NoError(t, err)
1241		require.NotNil(t, rpolicy)
1242
1243		require.NoError(t, s.ACLPolicyDeleteByID(3, "f1093997-b6c7-496d-bfb8-6b1b1895641b"))
1244		require.NoError(t, err)
1245
1246		_, rpolicy, err = s.ACLPolicyGetByID(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
1247		require.NoError(t, err)
1248		require.Nil(t, rpolicy)
1249	})
1250
1251	t.Run("Name", func(t *testing.T) {
1252		t.Parallel()
1253		s := testACLStateStore(t)
1254
1255		policy := &structs.ACLPolicy{
1256			ID:    "f1093997-b6c7-496d-bfb8-6b1b1895641b",
1257			Name:  "test-policy",
1258			Rules: `acl = "read"`,
1259		}
1260
1261		require.NoError(t, s.ACLPolicySet(2, policy))
1262
1263		_, rpolicy, err := s.ACLPolicyGetByName(nil, "test-policy")
1264		require.NoError(t, err)
1265		require.NotNil(t, rpolicy)
1266
1267		require.NoError(t, s.ACLPolicyDeleteByName(3, "test-policy"))
1268		require.NoError(t, err)
1269
1270		_, rpolicy, err = s.ACLPolicyGetByName(nil, "test-policy")
1271		require.NoError(t, err)
1272		require.Nil(t, rpolicy)
1273	})
1274
1275	t.Run("Multiple", func(t *testing.T) {
1276		t.Parallel()
1277		s := testACLStateStore(t)
1278
1279		policies := structs.ACLPolicies{
1280			&structs.ACLPolicy{
1281				ID:    "f1093997-b6c7-496d-bfb8-6b1b1895641b",
1282				Name:  "34ec8eb3-095d-417a-a937-b439af7a8e8b",
1283				Rules: `acl = "read"`,
1284			},
1285			&structs.ACLPolicy{
1286				ID:    "a0bfe8d4-b2f3-4b48-b387-f28afb820eab",
1287				Name:  "be444e46-fb95-4ccc-80d5-c873f34e6fa6",
1288				Rules: `acl = "write"`,
1289			},
1290		}
1291
1292		require.NoError(t, s.ACLPolicyBatchSet(2, policies))
1293
1294		_, rpolicy, err := s.ACLPolicyGetByID(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
1295		require.NoError(t, err)
1296		require.NotNil(t, rpolicy)
1297		_, rpolicy, err = s.ACLPolicyGetByID(nil, "a0bfe8d4-b2f3-4b48-b387-f28afb820eab")
1298		require.NoError(t, err)
1299		require.NotNil(t, rpolicy)
1300
1301		require.NoError(t, s.ACLPolicyBatchDelete(3, []string{
1302			"f1093997-b6c7-496d-bfb8-6b1b1895641b",
1303			"a0bfe8d4-b2f3-4b48-b387-f28afb820eab"}))
1304
1305		_, rpolicy, err = s.ACLPolicyGetByID(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
1306		require.NoError(t, err)
1307		require.Nil(t, rpolicy)
1308		_, rpolicy, err = s.ACLPolicyGetByID(nil, "a0bfe8d4-b2f3-4b48-b387-f28afb820eab")
1309		require.NoError(t, err)
1310		require.Nil(t, rpolicy)
1311	})
1312
1313	t.Run("Global-Management", func(t *testing.T) {
1314		t.Parallel()
1315		s := testACLStateStore(t)
1316
1317		require.Error(t, s.ACLPolicyDeleteByID(5, structs.ACLPolicyGlobalManagementID))
1318		require.Error(t, s.ACLPolicyDeleteByName(5, "global-management"))
1319	})
1320
1321	t.Run("Not Found", func(t *testing.T) {
1322		t.Parallel()
1323		s := testACLStateStore(t)
1324
1325		// deletion of non-existant policies is not an error
1326		require.NoError(t, s.ACLPolicyDeleteByName(3, "not-found"))
1327		require.NoError(t, s.ACLPolicyDeleteByID(3, "376d0cae-dd50-4213-9668-2c7797a7fb2d"))
1328	})
1329}
1330
1331func TestStateStore_ACLTokens_Snapshot_Restore(t *testing.T) {
1332	s := testStateStore(t)
1333
1334	tokens := structs.ACLTokens{
1335		&structs.ACLToken{
1336			AccessorID:  "68016c3d-835b-450c-a6f9-75db9ba740be",
1337			SecretID:    "838f72b5-5c15-4a9e-aa6d-31734c3a0286",
1338			Description: "token1",
1339			Policies: []structs.ACLTokenPolicyLink{
1340				structs.ACLTokenPolicyLink{
1341					ID:   "ca1fc52c-3676-4050-82ed-ca223e38b2c9",
1342					Name: "policy1",
1343				},
1344				structs.ACLTokenPolicyLink{
1345					ID:   "7b70fa0f-58cd-412d-93c3-a0f17bb19a3e",
1346					Name: "policy2",
1347				},
1348			},
1349			Hash:      []byte{1, 2, 3, 4},
1350			RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2},
1351		},
1352		&structs.ACLToken{
1353			AccessorID:  "b2125a1b-2a52-41d4-88f3-c58761998a46",
1354			SecretID:    "ba5d9239-a4ab-49b9-ae09-1f19eed92204",
1355			Description: "token2",
1356			Policies: []structs.ACLTokenPolicyLink{
1357				structs.ACLTokenPolicyLink{
1358					ID:   "ca1fc52c-3676-4050-82ed-ca223e38b2c9",
1359					Name: "policy1",
1360				},
1361				structs.ACLTokenPolicyLink{
1362					ID:   "7b70fa0f-58cd-412d-93c3-a0f17bb19a3e",
1363					Name: "policy2",
1364				},
1365			},
1366			Hash:      []byte{1, 2, 3, 4},
1367			RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2},
1368		},
1369	}
1370
1371	require.NoError(t, s.ACLTokenBatchSet(2, tokens, false))
1372
1373	// Snapshot the ACLs.
1374	snap := s.Snapshot()
1375	defer snap.Close()
1376
1377	// Alter the real state store.
1378	require.NoError(t, s.ACLTokenDeleteByAccessor(3, tokens[0].AccessorID))
1379
1380	// Verify the snapshot.
1381	require.Equal(t, uint64(2), snap.LastIndex())
1382
1383	iter, err := snap.ACLTokens()
1384	require.NoError(t, err)
1385
1386	var dump structs.ACLTokens
1387	for token := iter.Next(); token != nil; token = iter.Next() {
1388		dump = append(dump, token.(*structs.ACLToken))
1389	}
1390	require.ElementsMatch(t, dump, tokens)
1391
1392	// Restore the values into a new state store.
1393	func() {
1394		s := testStateStore(t)
1395		restore := s.Restore()
1396		for _, token := range dump {
1397			require.NoError(t, restore.ACLToken(token))
1398		}
1399		restore.Commit()
1400
1401		// Read the restored ACLs back out and verify that they match.
1402		idx, res, err := s.ACLTokenList(nil, true, true, "")
1403		require.NoError(t, err)
1404		require.Equal(t, uint64(2), idx)
1405		require.ElementsMatch(t, tokens, res)
1406		require.Equal(t, uint64(2), s.maxIndex("acl-tokens"))
1407	}()
1408}
1409
1410func TestStateStore_ACLPolicies_Snapshot_Restore(t *testing.T) {
1411	s := testStateStore(t)
1412
1413	policies := structs.ACLPolicies{
1414		&structs.ACLPolicy{
1415			ID:          "68016c3d-835b-450c-a6f9-75db9ba740be",
1416			Name:        "838f72b5-5c15-4a9e-aa6d-31734c3a0286",
1417			Description: "policy1",
1418			Rules:       `acl = "read"`,
1419			Hash:        []byte{1, 2, 3, 4},
1420			RaftIndex:   structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2},
1421		},
1422		&structs.ACLPolicy{
1423			ID:          "b2125a1b-2a52-41d4-88f3-c58761998a46",
1424			Name:        "ba5d9239-a4ab-49b9-ae09-1f19eed92204",
1425			Description: "policy2",
1426			Rules:       `operator = "read"`,
1427			Hash:        []byte{1, 2, 3, 4},
1428			RaftIndex:   structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2},
1429		},
1430	}
1431
1432	require.NoError(t, s.ACLPolicyBatchSet(2, policies))
1433
1434	// Snapshot the ACLs.
1435	snap := s.Snapshot()
1436	defer snap.Close()
1437
1438	// Alter the real state store.
1439	require.NoError(t, s.ACLPolicyDeleteByID(3, policies[0].ID))
1440
1441	// Verify the snapshot.
1442	require.Equal(t, uint64(2), snap.LastIndex())
1443
1444	iter, err := snap.ACLPolicies()
1445	require.NoError(t, err)
1446
1447	var dump structs.ACLPolicies
1448	for policy := iter.Next(); policy != nil; policy = iter.Next() {
1449		dump = append(dump, policy.(*structs.ACLPolicy))
1450	}
1451	require.ElementsMatch(t, dump, policies)
1452
1453	// Restore the values into a new state store.
1454	func() {
1455		s := testStateStore(t)
1456		restore := s.Restore()
1457		for _, policy := range dump {
1458			require.NoError(t, restore.ACLPolicy(policy))
1459		}
1460		restore.Commit()
1461
1462		// Read the restored ACLs back out and verify that they match.
1463		idx, res, err := s.ACLPolicyList(nil)
1464		require.NoError(t, err)
1465		require.Equal(t, uint64(2), idx)
1466		require.ElementsMatch(t, policies, res)
1467		require.Equal(t, uint64(2), s.maxIndex("acl-policies"))
1468	}()
1469}
1470