1// Copyright 2016 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package e2e
16
17import (
18	"fmt"
19	"os"
20	"testing"
21	"time"
22
23	"go.etcd.io/etcd/clientv3"
24)
25
26func TestCtlV3AuthEnable(t *testing.T)              { testCtl(t, authEnableTest) }
27func TestCtlV3AuthDisable(t *testing.T)             { testCtl(t, authDisableTest) }
28func TestCtlV3AuthWriteKey(t *testing.T)            { testCtl(t, authCredWriteKeyTest) }
29func TestCtlV3AuthRoleUpdate(t *testing.T)          { testCtl(t, authRoleUpdateTest) }
30func TestCtlV3AuthUserDeleteDuringOps(t *testing.T) { testCtl(t, authUserDeleteDuringOpsTest) }
31func TestCtlV3AuthRoleRevokeDuringOps(t *testing.T) { testCtl(t, authRoleRevokeDuringOpsTest) }
32func TestCtlV3AuthTxn(t *testing.T)                 { testCtl(t, authTestTxn) }
33func TestCtlV3AuthTxnJWT(t *testing.T)              { testCtl(t, authTestTxn, withCfg(configJWT)) }
34func TestCtlV3AuthPrefixPerm(t *testing.T)          { testCtl(t, authTestPrefixPerm) }
35func TestCtlV3AuthMemberAdd(t *testing.T)           { testCtl(t, authTestMemberAdd) }
36func TestCtlV3AuthMemberRemove(t *testing.T) {
37	testCtl(t, authTestMemberRemove, withQuorum(), withNoStrictReconfig())
38}
39func TestCtlV3AuthMemberUpdate(t *testing.T)     { testCtl(t, authTestMemberUpdate) }
40func TestCtlV3AuthCertCN(t *testing.T)           { testCtl(t, authTestCertCN, withCfg(configClientTLSCertAuth)) }
41func TestCtlV3AuthRevokeWithDelete(t *testing.T) { testCtl(t, authTestRevokeWithDelete) }
42func TestCtlV3AuthInvalidMgmt(t *testing.T)      { testCtl(t, authTestInvalidMgmt) }
43func TestCtlV3AuthFromKeyPerm(t *testing.T)      { testCtl(t, authTestFromKeyPerm) }
44func TestCtlV3AuthAndWatch(t *testing.T)         { testCtl(t, authTestWatch) }
45func TestCtlV3AuthAndWatchJWT(t *testing.T)      { testCtl(t, authTestWatch, withCfg(configJWT)) }
46
47func TestCtlV3AuthLeaseTestKeepAlive(t *testing.T) { testCtl(t, authLeaseTestKeepAlive) }
48func TestCtlV3AuthLeaseTestTimeToLiveExpired(t *testing.T) {
49	testCtl(t, authLeaseTestTimeToLiveExpired)
50}
51func TestCtlV3AuthLeaseGrantLeases(t *testing.T) { testCtl(t, authLeaseTestLeaseGrantLeases) }
52func TestCtlV3AuthLeaseGrantLeasesJWT(t *testing.T) {
53	testCtl(t, authLeaseTestLeaseGrantLeases, withCfg(configJWT))
54}
55func TestCtlV3AuthLeaseRevoke(t *testing.T) { testCtl(t, authLeaseTestLeaseRevoke) }
56
57func TestCtlV3AuthRoleGet(t *testing.T)  { testCtl(t, authTestRoleGet) }
58func TestCtlV3AuthUserGet(t *testing.T)  { testCtl(t, authTestUserGet) }
59func TestCtlV3AuthRoleList(t *testing.T) { testCtl(t, authTestRoleList) }
60
61func TestCtlV3AuthDefrag(t *testing.T) { testCtl(t, authTestDefrag) }
62func TestCtlV3AuthEndpointHealth(t *testing.T) {
63	testCtl(t, authTestEndpointHealth, withQuorum())
64}
65func TestCtlV3AuthSnapshot(t *testing.T)    { testCtl(t, authTestSnapshot) }
66func TestCtlV3AuthSnapshotJWT(t *testing.T) { testCtl(t, authTestSnapshot, withCfg(configJWT)) }
67func TestCtlV3AuthCertCNAndUsername(t *testing.T) {
68	testCtl(t, authTestCertCNAndUsername, withCfg(configClientTLSCertAuth))
69}
70func TestCtlV3AuthJWTExpire(t *testing.T) { testCtl(t, authTestJWTExpire, withCfg(configJWT)) }
71func TestCtlV3AuthCertCNAndUsernameNoPassword(t *testing.T) {
72	testCtl(t, authTestCertCNAndUsernameNoPassword, withCfg(configClientTLSCertAuth))
73}
74
75func authEnableTest(cx ctlCtx) {
76	if err := authEnable(cx); err != nil {
77		cx.t.Fatal(err)
78	}
79}
80
81func authEnable(cx ctlCtx) error {
82	// create root user with root role
83	if err := ctlV3User(cx, []string{"add", "root", "--interactive=false"}, "User root created", []string{"root"}); err != nil {
84		return fmt.Errorf("failed to create root user %v", err)
85	}
86	if err := ctlV3User(cx, []string{"grant-role", "root", "root"}, "Role root is granted to user root", nil); err != nil {
87		return fmt.Errorf("failed to grant root user root role %v", err)
88	}
89	if err := ctlV3AuthEnable(cx); err != nil {
90		return fmt.Errorf("authEnableTest ctlV3AuthEnable error (%v)", err)
91	}
92	return nil
93}
94
95func ctlV3AuthEnable(cx ctlCtx) error {
96	cmdArgs := append(cx.PrefixArgs(), "auth", "enable")
97	return spawnWithExpect(cmdArgs, "Authentication Enabled")
98}
99
100func authDisableTest(cx ctlCtx) {
101	// a key that isn't granted to test-user
102	if err := ctlV3Put(cx, "hoo", "a", ""); err != nil {
103		cx.t.Fatal(err)
104	}
105
106	if err := authEnable(cx); err != nil {
107		cx.t.Fatal(err)
108	}
109
110	cx.user, cx.pass = "root", "root"
111	authSetupTestUser(cx)
112
113	// test-user doesn't have the permission, it must fail
114	cx.user, cx.pass = "test-user", "pass"
115	if err := ctlV3PutFailPerm(cx, "hoo", "bar"); err != nil {
116		cx.t.Fatal(err)
117	}
118
119	cx.user, cx.pass = "root", "root"
120	if err := ctlV3AuthDisable(cx); err != nil {
121		cx.t.Fatalf("authDisableTest ctlV3AuthDisable error (%v)", err)
122	}
123
124	// now ErrAuthNotEnabled of Authenticate() is simply ignored
125	cx.user, cx.pass = "test-user", "pass"
126	if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
127		cx.t.Fatal(err)
128	}
129
130	// now the key can be accessed
131	cx.user, cx.pass = "", ""
132	if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
133		cx.t.Fatal(err)
134	}
135	// confirm put succeeded
136	if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil {
137		cx.t.Fatal(err)
138	}
139}
140
141func ctlV3AuthDisable(cx ctlCtx) error {
142	cmdArgs := append(cx.PrefixArgs(), "auth", "disable")
143	return spawnWithExpect(cmdArgs, "Authentication Disabled")
144}
145
146func authCredWriteKeyTest(cx ctlCtx) {
147	// baseline key to check for failed puts
148	if err := ctlV3Put(cx, "foo", "a", ""); err != nil {
149		cx.t.Fatal(err)
150	}
151
152	if err := authEnable(cx); err != nil {
153		cx.t.Fatal(err)
154	}
155
156	cx.user, cx.pass = "root", "root"
157	authSetupTestUser(cx)
158
159	// confirm root role can access to all keys
160	if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
161		cx.t.Fatal(err)
162	}
163	if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
164		cx.t.Fatal(err)
165	}
166
167	// try invalid user
168	cx.user, cx.pass = "a", "b"
169	if err := ctlV3PutFailAuth(cx, "foo", "bar"); err != nil {
170		cx.t.Fatal(err)
171	}
172	// confirm put failed
173	cx.user, cx.pass = "test-user", "pass"
174	if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
175		cx.t.Fatal(err)
176	}
177
178	// try good user
179	cx.user, cx.pass = "test-user", "pass"
180	if err := ctlV3Put(cx, "foo", "bar2", ""); err != nil {
181		cx.t.Fatal(err)
182	}
183	// confirm put succeeded
184	if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar2"}}...); err != nil {
185		cx.t.Fatal(err)
186	}
187
188	// try bad password
189	cx.user, cx.pass = "test-user", "badpass"
190	if err := ctlV3PutFailAuth(cx, "foo", "baz"); err != nil {
191		cx.t.Fatal(err)
192	}
193	// confirm put failed
194	cx.user, cx.pass = "test-user", "pass"
195	if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar2"}}...); err != nil {
196		cx.t.Fatal(err)
197	}
198}
199
200func authRoleUpdateTest(cx ctlCtx) {
201	if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
202		cx.t.Fatal(err)
203	}
204
205	if err := authEnable(cx); err != nil {
206		cx.t.Fatal(err)
207	}
208
209	cx.user, cx.pass = "root", "root"
210	authSetupTestUser(cx)
211
212	// try put to not granted key
213	cx.user, cx.pass = "test-user", "pass"
214	if err := ctlV3PutFailPerm(cx, "hoo", "bar"); err != nil {
215		cx.t.Fatal(err)
216	}
217
218	// grant a new key
219	cx.user, cx.pass = "root", "root"
220	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "hoo", "", false}); err != nil {
221		cx.t.Fatal(err)
222	}
223
224	// try a newly granted key
225	cx.user, cx.pass = "test-user", "pass"
226	if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
227		cx.t.Fatal(err)
228	}
229	// confirm put succeeded
230	if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil {
231		cx.t.Fatal(err)
232	}
233
234	// revoke the newly granted key
235	cx.user, cx.pass = "root", "root"
236	if err := ctlV3RoleRevokePermission(cx, "test-role", "hoo", "", false); err != nil {
237		cx.t.Fatal(err)
238	}
239
240	// try put to the revoked key
241	cx.user, cx.pass = "test-user", "pass"
242	if err := ctlV3PutFailPerm(cx, "hoo", "bar"); err != nil {
243		cx.t.Fatal(err)
244	}
245
246	// confirm a key still granted can be accessed
247	if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
248		cx.t.Fatal(err)
249	}
250}
251
252func authUserDeleteDuringOpsTest(cx ctlCtx) {
253	if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
254		cx.t.Fatal(err)
255	}
256
257	if err := authEnable(cx); err != nil {
258		cx.t.Fatal(err)
259	}
260
261	cx.user, cx.pass = "root", "root"
262	authSetupTestUser(cx)
263
264	// create a key
265	cx.user, cx.pass = "test-user", "pass"
266	if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
267		cx.t.Fatal(err)
268	}
269	// confirm put succeeded
270	if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
271		cx.t.Fatal(err)
272	}
273
274	// delete the user
275	cx.user, cx.pass = "root", "root"
276	err := ctlV3User(cx, []string{"delete", "test-user"}, "User test-user deleted", []string{})
277	if err != nil {
278		cx.t.Fatal(err)
279	}
280
281	// check the user is deleted
282	cx.user, cx.pass = "test-user", "pass"
283	if err := ctlV3PutFailAuth(cx, "foo", "baz"); err != nil {
284		cx.t.Fatal(err)
285	}
286}
287
288func authRoleRevokeDuringOpsTest(cx ctlCtx) {
289	if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
290		cx.t.Fatal(err)
291	}
292
293	if err := authEnable(cx); err != nil {
294		cx.t.Fatal(err)
295	}
296
297	cx.user, cx.pass = "root", "root"
298	authSetupTestUser(cx)
299
300	// create a key
301	cx.user, cx.pass = "test-user", "pass"
302	if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
303		cx.t.Fatal(err)
304	}
305	// confirm put succeeded
306	if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
307		cx.t.Fatal(err)
308	}
309
310	// create a new role
311	cx.user, cx.pass = "root", "root"
312	if err := ctlV3Role(cx, []string{"add", "test-role2"}, "Role test-role2 created"); err != nil {
313		cx.t.Fatal(err)
314	}
315	// grant a new key to the new role
316	if err := ctlV3RoleGrantPermission(cx, "test-role2", grantingPerm{true, true, "hoo", "", false}); err != nil {
317		cx.t.Fatal(err)
318	}
319	// grant the new role to the user
320	if err := ctlV3User(cx, []string{"grant-role", "test-user", "test-role2"}, "Role test-role2 is granted to user test-user", nil); err != nil {
321		cx.t.Fatal(err)
322	}
323
324	// try a newly granted key
325	cx.user, cx.pass = "test-user", "pass"
326	if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
327		cx.t.Fatal(err)
328	}
329	// confirm put succeeded
330	if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil {
331		cx.t.Fatal(err)
332	}
333
334	// revoke a role from the user
335	cx.user, cx.pass = "root", "root"
336	err := ctlV3User(cx, []string{"revoke-role", "test-user", "test-role"}, "Role test-role is revoked from user test-user", []string{})
337	if err != nil {
338		cx.t.Fatal(err)
339	}
340
341	// check the role is revoked and permission is lost from the user
342	cx.user, cx.pass = "test-user", "pass"
343	if err := ctlV3PutFailPerm(cx, "foo", "baz"); err != nil {
344		cx.t.Fatal(err)
345	}
346
347	// try a key that can be accessed from the remaining role
348	cx.user, cx.pass = "test-user", "pass"
349	if err := ctlV3Put(cx, "hoo", "bar2", ""); err != nil {
350		cx.t.Fatal(err)
351	}
352	// confirm put succeeded
353	if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar2"}}...); err != nil {
354		cx.t.Fatal(err)
355	}
356}
357
358func ctlV3PutFailAuth(cx ctlCtx, key, val string) error {
359	return spawnWithExpect(append(cx.PrefixArgs(), "put", key, val), "authentication failed")
360}
361
362func ctlV3PutFailPerm(cx ctlCtx, key, val string) error {
363	return spawnWithExpect(append(cx.PrefixArgs(), "put", key, val), "permission denied")
364}
365
366func authSetupTestUser(cx ctlCtx) {
367	if err := ctlV3User(cx, []string{"add", "test-user", "--interactive=false"}, "User test-user created", []string{"pass"}); err != nil {
368		cx.t.Fatal(err)
369	}
370	if err := spawnWithExpect(append(cx.PrefixArgs(), "role", "add", "test-role"), "Role test-role created"); err != nil {
371		cx.t.Fatal(err)
372	}
373	if err := ctlV3User(cx, []string{"grant-role", "test-user", "test-role"}, "Role test-role is granted to user test-user", nil); err != nil {
374		cx.t.Fatal(err)
375	}
376	cmd := append(cx.PrefixArgs(), "role", "grant-permission", "test-role", "readwrite", "foo")
377	if err := spawnWithExpect(cmd, "Role test-role updated"); err != nil {
378		cx.t.Fatal(err)
379	}
380}
381
382func authTestTxn(cx ctlCtx) {
383	// keys with 1 suffix aren't granted to test-user
384	// keys with 2 suffix are granted to test-user
385
386	keys := []string{"c1", "s1", "f1"}
387	grantedKeys := []string{"c2", "s2", "f2"}
388	for _, key := range keys {
389		if err := ctlV3Put(cx, key, "v", ""); err != nil {
390			cx.t.Fatal(err)
391		}
392	}
393
394	for _, key := range grantedKeys {
395		if err := ctlV3Put(cx, key, "v", ""); err != nil {
396			cx.t.Fatal(err)
397		}
398	}
399
400	if err := authEnable(cx); err != nil {
401		cx.t.Fatal(err)
402	}
403
404	cx.user, cx.pass = "root", "root"
405	authSetupTestUser(cx)
406
407	// grant keys to test-user
408	cx.user, cx.pass = "root", "root"
409	for _, key := range grantedKeys {
410		if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, key, "", false}); err != nil {
411			cx.t.Fatal(err)
412		}
413	}
414
415	// now test txn
416	cx.interactive = true
417	cx.user, cx.pass = "test-user", "pass"
418
419	rqs := txnRequests{
420		compare:  []string{`version("c2") = "1"`},
421		ifSucess: []string{"get s2"},
422		ifFail:   []string{"get f2"},
423		results:  []string{"SUCCESS", "s2", "v"},
424	}
425	if err := ctlV3Txn(cx, rqs); err != nil {
426		cx.t.Fatal(err)
427	}
428
429	// a key of compare case isn't granted
430	rqs = txnRequests{
431		compare:  []string{`version("c1") = "1"`},
432		ifSucess: []string{"get s2"},
433		ifFail:   []string{"get f2"},
434		results:  []string{"Error: etcdserver: permission denied"},
435	}
436	if err := ctlV3Txn(cx, rqs); err != nil {
437		cx.t.Fatal(err)
438	}
439
440	// a key of success case isn't granted
441	rqs = txnRequests{
442		compare:  []string{`version("c2") = "1"`},
443		ifSucess: []string{"get s1"},
444		ifFail:   []string{"get f2"},
445		results:  []string{"Error: etcdserver: permission denied"},
446	}
447	if err := ctlV3Txn(cx, rqs); err != nil {
448		cx.t.Fatal(err)
449	}
450
451	// a key of failure case isn't granted
452	rqs = txnRequests{
453		compare:  []string{`version("c2") = "1"`},
454		ifSucess: []string{"get s2"},
455		ifFail:   []string{"get f1"},
456		results:  []string{"Error: etcdserver: permission denied"},
457	}
458	if err := ctlV3Txn(cx, rqs); err != nil {
459		cx.t.Fatal(err)
460	}
461}
462
463func authTestPrefixPerm(cx ctlCtx) {
464	if err := authEnable(cx); err != nil {
465		cx.t.Fatal(err)
466	}
467
468	cx.user, cx.pass = "root", "root"
469	authSetupTestUser(cx)
470
471	prefix := "/prefix/" // directory like prefix
472	// grant keys to test-user
473	cx.user, cx.pass = "root", "root"
474	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, prefix, "", true}); err != nil {
475		cx.t.Fatal(err)
476	}
477
478	// try a prefix granted permission
479	cx.user, cx.pass = "test-user", "pass"
480	for i := 0; i < 10; i++ {
481		key := fmt.Sprintf("%s%d", prefix, i)
482		if err := ctlV3Put(cx, key, "val", ""); err != nil {
483			cx.t.Fatal(err)
484		}
485	}
486
487	if err := ctlV3PutFailPerm(cx, clientv3.GetPrefixRangeEnd(prefix), "baz"); err != nil {
488		cx.t.Fatal(err)
489	}
490
491	// grant the entire keys to test-user
492	cx.user, cx.pass = "root", "root"
493	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "", "", true}); err != nil {
494		cx.t.Fatal(err)
495	}
496
497	prefix2 := "/prefix2/"
498	cx.user, cx.pass = "test-user", "pass"
499	for i := 0; i < 10; i++ {
500		key := fmt.Sprintf("%s%d", prefix2, i)
501		if err := ctlV3Put(cx, key, "val", ""); err != nil {
502			cx.t.Fatal(err)
503		}
504	}
505}
506
507func authTestMemberAdd(cx ctlCtx) {
508	if err := authEnable(cx); err != nil {
509		cx.t.Fatal(err)
510	}
511
512	cx.user, cx.pass = "root", "root"
513	authSetupTestUser(cx)
514
515	peerURL := fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+11)
516	// ordinary user cannot add a new member
517	cx.user, cx.pass = "test-user", "pass"
518	if err := ctlV3MemberAdd(cx, peerURL, false); err == nil {
519		cx.t.Fatalf("ordinary user must not be allowed to add a member")
520	}
521
522	// root can add a new member
523	cx.user, cx.pass = "root", "root"
524	if err := ctlV3MemberAdd(cx, peerURL, false); err != nil {
525		cx.t.Fatal(err)
526	}
527}
528
529func authTestMemberRemove(cx ctlCtx) {
530	if err := authEnable(cx); err != nil {
531		cx.t.Fatal(err)
532	}
533
534	cx.user, cx.pass = "root", "root"
535	authSetupTestUser(cx)
536
537	ep, memIDToRemove, clusterID := cx.memberToRemove()
538
539	// ordinary user cannot remove a member
540	cx.user, cx.pass = "test-user", "pass"
541	if err := ctlV3MemberRemove(cx, ep, memIDToRemove, clusterID); err == nil {
542		cx.t.Fatalf("ordinary user must not be allowed to remove a member")
543	}
544
545	// root can remove a member
546	cx.user, cx.pass = "root", "root"
547	if err := ctlV3MemberRemove(cx, ep, memIDToRemove, clusterID); err != nil {
548		cx.t.Fatal(err)
549	}
550}
551
552func authTestMemberUpdate(cx ctlCtx) {
553	if err := authEnable(cx); err != nil {
554		cx.t.Fatal(err)
555	}
556
557	cx.user, cx.pass = "root", "root"
558	authSetupTestUser(cx)
559
560	mr, err := getMemberList(cx)
561	if err != nil {
562		cx.t.Fatal(err)
563	}
564
565	// ordinary user cannot update a member
566	cx.user, cx.pass = "test-user", "pass"
567	peerURL := fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+11)
568	memberID := fmt.Sprintf("%x", mr.Members[0].ID)
569	if err = ctlV3MemberUpdate(cx, memberID, peerURL); err == nil {
570		cx.t.Fatalf("ordinary user must not be allowed to update a member")
571	}
572
573	// root can update a member
574	cx.user, cx.pass = "root", "root"
575	if err = ctlV3MemberUpdate(cx, memberID, peerURL); err != nil {
576		cx.t.Fatal(err)
577	}
578}
579
580func authTestCertCN(cx ctlCtx) {
581	if err := authEnable(cx); err != nil {
582		cx.t.Fatal(err)
583	}
584
585	cx.user, cx.pass = "root", "root"
586	if err := ctlV3User(cx, []string{"add", "example.com", "--interactive=false"}, "User example.com created", []string{""}); err != nil {
587		cx.t.Fatal(err)
588	}
589	if err := spawnWithExpect(append(cx.PrefixArgs(), "role", "add", "test-role"), "Role test-role created"); err != nil {
590		cx.t.Fatal(err)
591	}
592	if err := ctlV3User(cx, []string{"grant-role", "example.com", "test-role"}, "Role test-role is granted to user example.com", nil); err != nil {
593		cx.t.Fatal(err)
594	}
595
596	// grant a new key
597	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "hoo", "", false}); err != nil {
598		cx.t.Fatal(err)
599	}
600
601	// try a granted key
602	cx.user, cx.pass = "", ""
603	if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
604		cx.t.Error(err)
605	}
606
607	// try a non granted key
608	cx.user, cx.pass = "", ""
609	if err := ctlV3PutFailPerm(cx, "baz", "bar"); err != nil {
610		cx.t.Error(err)
611	}
612}
613
614func authTestRevokeWithDelete(cx ctlCtx) {
615	if err := authEnable(cx); err != nil {
616		cx.t.Fatal(err)
617	}
618
619	cx.user, cx.pass = "root", "root"
620	authSetupTestUser(cx)
621
622	// create a new role
623	cx.user, cx.pass = "root", "root"
624	if err := ctlV3Role(cx, []string{"add", "test-role2"}, "Role test-role2 created"); err != nil {
625		cx.t.Fatal(err)
626	}
627
628	// grant the new role to the user
629	if err := ctlV3User(cx, []string{"grant-role", "test-user", "test-role2"}, "Role test-role2 is granted to user test-user", nil); err != nil {
630		cx.t.Fatal(err)
631	}
632
633	// check the result
634	if err := ctlV3User(cx, []string{"get", "test-user"}, "Roles: test-role test-role2", nil); err != nil {
635		cx.t.Fatal(err)
636	}
637
638	// delete the role, test-role2 must be revoked from test-user
639	if err := ctlV3Role(cx, []string{"delete", "test-role2"}, "Role test-role2 deleted"); err != nil {
640		cx.t.Fatal(err)
641	}
642
643	// check the result
644	if err := ctlV3User(cx, []string{"get", "test-user"}, "Roles: test-role", nil); err != nil {
645		cx.t.Fatal(err)
646	}
647}
648
649func authTestInvalidMgmt(cx ctlCtx) {
650	if err := authEnable(cx); err != nil {
651		cx.t.Fatal(err)
652	}
653
654	if err := ctlV3Role(cx, []string{"delete", "root"}, "Error: etcdserver: invalid auth management"); err == nil {
655		cx.t.Fatal("deleting the role root must not be allowed")
656	}
657
658	if err := ctlV3User(cx, []string{"revoke-role", "root", "root"}, "Error: etcdserver: invalid auth management", []string{}); err == nil {
659		cx.t.Fatal("revoking the role root from the user root must not be allowed")
660	}
661}
662
663func authTestFromKeyPerm(cx ctlCtx) {
664	if err := authEnable(cx); err != nil {
665		cx.t.Fatal(err)
666	}
667
668	cx.user, cx.pass = "root", "root"
669	authSetupTestUser(cx)
670
671	// grant keys after z to test-user
672	cx.user, cx.pass = "root", "root"
673	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "z", "\x00", false}); err != nil {
674		cx.t.Fatal(err)
675	}
676
677	// try the granted open ended permission
678	cx.user, cx.pass = "test-user", "pass"
679	for i := 0; i < 10; i++ {
680		key := fmt.Sprintf("z%d", i)
681		if err := ctlV3Put(cx, key, "val", ""); err != nil {
682			cx.t.Fatal(err)
683		}
684	}
685	largeKey := ""
686	for i := 0; i < 10; i++ {
687		largeKey += "\xff"
688		if err := ctlV3Put(cx, largeKey, "val", ""); err != nil {
689			cx.t.Fatal(err)
690		}
691	}
692
693	// try a non granted key
694	if err := ctlV3PutFailPerm(cx, "x", "baz"); err != nil {
695		cx.t.Fatal(err)
696	}
697
698	// revoke the open ended permission
699	cx.user, cx.pass = "root", "root"
700	if err := ctlV3RoleRevokePermission(cx, "test-role", "z", "", true); err != nil {
701		cx.t.Fatal(err)
702	}
703
704	// try the revoked open ended permission
705	cx.user, cx.pass = "test-user", "pass"
706	for i := 0; i < 10; i++ {
707		key := fmt.Sprintf("z%d", i)
708		if err := ctlV3PutFailPerm(cx, key, "val"); err != nil {
709			cx.t.Fatal(err)
710		}
711	}
712
713	// grant the entire keys
714	cx.user, cx.pass = "root", "root"
715	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "", "\x00", false}); err != nil {
716		cx.t.Fatal(err)
717	}
718
719	// try keys, of course it must be allowed because test-role has a permission of the entire keys
720	cx.user, cx.pass = "test-user", "pass"
721	for i := 0; i < 10; i++ {
722		key := fmt.Sprintf("z%d", i)
723		if err := ctlV3Put(cx, key, "val", ""); err != nil {
724			cx.t.Fatal(err)
725		}
726	}
727
728	// revoke the entire keys
729	cx.user, cx.pass = "root", "root"
730	if err := ctlV3RoleRevokePermission(cx, "test-role", "", "", true); err != nil {
731		cx.t.Fatal(err)
732	}
733
734	// try the revoked entire key permission
735	cx.user, cx.pass = "test-user", "pass"
736	for i := 0; i < 10; i++ {
737		key := fmt.Sprintf("z%d", i)
738		if err := ctlV3PutFailPerm(cx, key, "val"); err != nil {
739			cx.t.Fatal(err)
740		}
741	}
742}
743
744func authLeaseTestKeepAlive(cx ctlCtx) {
745	if err := authEnable(cx); err != nil {
746		cx.t.Fatal(err)
747	}
748
749	cx.user, cx.pass = "root", "root"
750	authSetupTestUser(cx)
751	// put with TTL 10 seconds and keep-alive
752	leaseID, err := ctlV3LeaseGrant(cx, 10)
753	if err != nil {
754		cx.t.Fatalf("leaseTestKeepAlive: ctlV3LeaseGrant error (%v)", err)
755	}
756	if err := ctlV3Put(cx, "key", "val", leaseID); err != nil {
757		cx.t.Fatalf("leaseTestKeepAlive: ctlV3Put error (%v)", err)
758	}
759	if err := ctlV3LeaseKeepAlive(cx, leaseID); err != nil {
760		cx.t.Fatalf("leaseTestKeepAlive: ctlV3LeaseKeepAlive error (%v)", err)
761	}
762	if err := ctlV3Get(cx, []string{"key"}, kv{"key", "val"}); err != nil {
763		cx.t.Fatalf("leaseTestKeepAlive: ctlV3Get error (%v)", err)
764	}
765}
766
767func authLeaseTestTimeToLiveExpired(cx ctlCtx) {
768	if err := authEnable(cx); err != nil {
769		cx.t.Fatal(err)
770	}
771
772	cx.user, cx.pass = "root", "root"
773	authSetupTestUser(cx)
774
775	ttl := 3
776	if err := leaseTestTimeToLiveExpire(cx, ttl); err != nil {
777		cx.t.Fatalf("leaseTestTimeToLiveExpire: error (%v)", err)
778	}
779}
780
781func authLeaseTestLeaseGrantLeases(cx ctlCtx) {
782	cx.user, cx.pass = "root", "root"
783	authSetupTestUser(cx)
784
785	if err := leaseTestGrantLeasesList(cx); err != nil {
786		cx.t.Fatalf("authLeaseTestLeaseGrantLeases: error (%v)", err)
787	}
788}
789
790func authLeaseTestLeaseRevoke(cx ctlCtx) {
791	cx.user, cx.pass = "root", "root"
792	authSetupTestUser(cx)
793
794	// put with TTL 10 seconds and revoke
795	leaseID, err := ctlV3LeaseGrant(cx, 10)
796	if err != nil {
797		cx.t.Fatalf("ctlV3LeaseGrant error (%v)", err)
798	}
799	if err := ctlV3Put(cx, "key", "val", leaseID); err != nil {
800		cx.t.Fatalf("ctlV3Put error (%v)", err)
801	}
802	if err := ctlV3LeaseRevoke(cx, leaseID); err != nil {
803		cx.t.Fatalf("ctlV3LeaseRevoke error (%v)", err)
804	}
805	if err := ctlV3GetWithErr(cx, []string{"key"}, []string{"retrying of unary invoker failed"}); err != nil { // expect errors
806		cx.t.Fatalf("ctlV3GetWithErr error (%v)", err)
807	}
808}
809
810func authTestWatch(cx ctlCtx) {
811	if err := authEnable(cx); err != nil {
812		cx.t.Fatal(err)
813	}
814
815	cx.user, cx.pass = "root", "root"
816	authSetupTestUser(cx)
817
818	// grant a key range
819	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "key", "key4", false}); err != nil {
820		cx.t.Fatal(err)
821	}
822
823	tests := []struct {
824		puts []kv
825		args []string
826
827		wkv  []kvExec
828		want bool
829	}{
830		{ // watch 1 key, should be successful
831			[]kv{{"key", "value"}},
832			[]string{"key", "--rev", "1"},
833			[]kvExec{{key: "key", val: "value"}},
834			true,
835		},
836		{ // watch 3 keys by range, should be successful
837			[]kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}},
838			[]string{"key", "key3", "--rev", "1"},
839			[]kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}},
840			true,
841		},
842
843		{ // watch 1 key, should not be successful
844			[]kv{},
845			[]string{"key5", "--rev", "1"},
846			[]kvExec{},
847			false,
848		},
849		{ // watch 3 keys by range, should not be successful
850			[]kv{},
851			[]string{"key", "key6", "--rev", "1"},
852			[]kvExec{},
853			false,
854		},
855	}
856
857	cx.user, cx.pass = "test-user", "pass"
858	for i, tt := range tests {
859		donec := make(chan struct{})
860		go func(i int, puts []kv) {
861			defer close(donec)
862			for j := range puts {
863				if err := ctlV3Put(cx, puts[j].key, puts[j].val, ""); err != nil {
864					cx.t.Errorf("watchTest #%d-%d: ctlV3Put error (%v)", i, j, err)
865				}
866			}
867		}(i, tt.puts)
868
869		var err error
870		if tt.want {
871			err = ctlV3Watch(cx, tt.args, tt.wkv...)
872		} else {
873			err = ctlV3WatchFailPerm(cx, tt.args)
874		}
875
876		if err != nil {
877			if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
878				cx.t.Errorf("watchTest #%d: ctlV3Watch error (%v)", i, err)
879			}
880		}
881
882		<-donec
883	}
884
885}
886
887func authTestRoleGet(cx ctlCtx) {
888	if err := authEnable(cx); err != nil {
889		cx.t.Fatal(err)
890	}
891	cx.user, cx.pass = "root", "root"
892	authSetupTestUser(cx)
893
894	expected := []string{
895		"Role test-role",
896		"KV Read:", "foo",
897		"KV Write:", "foo",
898	}
899	if err := spawnWithExpects(append(cx.PrefixArgs(), "role", "get", "test-role"), expected...); err != nil {
900		cx.t.Fatal(err)
901	}
902
903	// test-user can get the information of test-role because it belongs to the role
904	cx.user, cx.pass = "test-user", "pass"
905	if err := spawnWithExpects(append(cx.PrefixArgs(), "role", "get", "test-role"), expected...); err != nil {
906		cx.t.Fatal(err)
907	}
908
909	// test-user cannot get the information of root because it doesn't belong to the role
910	expected = []string{
911		"Error: etcdserver: permission denied",
912	}
913	if err := spawnWithExpects(append(cx.PrefixArgs(), "role", "get", "root"), expected...); err != nil {
914		cx.t.Fatal(err)
915	}
916}
917
918func authTestUserGet(cx ctlCtx) {
919	if err := authEnable(cx); err != nil {
920		cx.t.Fatal(err)
921	}
922	cx.user, cx.pass = "root", "root"
923	authSetupTestUser(cx)
924
925	expected := []string{
926		"User: test-user",
927		"Roles: test-role",
928	}
929
930	if err := spawnWithExpects(append(cx.PrefixArgs(), "user", "get", "test-user"), expected...); err != nil {
931		cx.t.Fatal(err)
932	}
933
934	// test-user can get the information of test-user itself
935	cx.user, cx.pass = "test-user", "pass"
936	if err := spawnWithExpects(append(cx.PrefixArgs(), "user", "get", "test-user"), expected...); err != nil {
937		cx.t.Fatal(err)
938	}
939
940	// test-user cannot get the information of root
941	expected = []string{
942		"Error: etcdserver: permission denied",
943	}
944	if err := spawnWithExpects(append(cx.PrefixArgs(), "user", "get", "root"), expected...); err != nil {
945		cx.t.Fatal(err)
946	}
947}
948
949func authTestRoleList(cx ctlCtx) {
950	if err := authEnable(cx); err != nil {
951		cx.t.Fatal(err)
952	}
953	cx.user, cx.pass = "root", "root"
954	authSetupTestUser(cx)
955	if err := spawnWithExpect(append(cx.PrefixArgs(), "role", "list"), "test-role"); err != nil {
956		cx.t.Fatal(err)
957	}
958}
959
960func authTestDefrag(cx ctlCtx) {
961	maintenanceInitKeys(cx)
962
963	if err := authEnable(cx); err != nil {
964		cx.t.Fatal(err)
965	}
966
967	cx.user, cx.pass = "root", "root"
968	authSetupTestUser(cx)
969
970	// ordinary user cannot defrag
971	cx.user, cx.pass = "test-user", "pass"
972	if err := ctlV3Defrag(cx); err == nil {
973		cx.t.Fatal("ordinary user should not be able to issue a defrag request")
974	}
975
976	// root can defrag
977	cx.user, cx.pass = "root", "root"
978	if err := ctlV3Defrag(cx); err != nil {
979		cx.t.Fatal(err)
980	}
981}
982
983func authTestSnapshot(cx ctlCtx) {
984	maintenanceInitKeys(cx)
985
986	if err := authEnable(cx); err != nil {
987		cx.t.Fatal(err)
988	}
989
990	cx.user, cx.pass = "root", "root"
991	authSetupTestUser(cx)
992
993	fpath := "test-auth.snapshot"
994	defer os.RemoveAll(fpath)
995
996	// ordinary user cannot save a snapshot
997	cx.user, cx.pass = "test-user", "pass"
998	if err := ctlV3SnapshotSave(cx, fpath); err == nil {
999		cx.t.Fatal("ordinary user should not be able to save a snapshot")
1000	}
1001
1002	// root can save a snapshot
1003	cx.user, cx.pass = "root", "root"
1004	if err := ctlV3SnapshotSave(cx, fpath); err != nil {
1005		cx.t.Fatalf("snapshotTest ctlV3SnapshotSave error (%v)", err)
1006	}
1007
1008	st, err := getSnapshotStatus(cx, fpath)
1009	if err != nil {
1010		cx.t.Fatalf("snapshotTest getSnapshotStatus error (%v)", err)
1011	}
1012	if st.Revision != 4 {
1013		cx.t.Fatalf("expected 4, got %d", st.Revision)
1014	}
1015	if st.TotalKey < 3 {
1016		cx.t.Fatalf("expected at least 3, got %d", st.TotalKey)
1017	}
1018}
1019
1020func authTestEndpointHealth(cx ctlCtx) {
1021	if err := authEnable(cx); err != nil {
1022		cx.t.Fatal(err)
1023	}
1024
1025	cx.user, cx.pass = "root", "root"
1026	authSetupTestUser(cx)
1027
1028	if err := ctlV3EndpointHealth(cx); err != nil {
1029		cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err)
1030	}
1031
1032	// health checking with an ordinary user "succeeds" since permission denial goes through consensus
1033	cx.user, cx.pass = "test-user", "pass"
1034	if err := ctlV3EndpointHealth(cx); err != nil {
1035		cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err)
1036	}
1037
1038	// succeed if permissions granted for ordinary user
1039	cx.user, cx.pass = "root", "root"
1040	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "health", "", false}); err != nil {
1041		cx.t.Fatal(err)
1042	}
1043	cx.user, cx.pass = "test-user", "pass"
1044	if err := ctlV3EndpointHealth(cx); err != nil {
1045		cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err)
1046	}
1047}
1048
1049func certCNAndUsername(cx ctlCtx, noPassword bool) {
1050	if err := authEnable(cx); err != nil {
1051		cx.t.Fatal(err)
1052	}
1053
1054	cx.user, cx.pass = "root", "root"
1055	authSetupTestUser(cx)
1056
1057	if noPassword {
1058		if err := ctlV3User(cx, []string{"add", "example.com", "--no-password"}, "User example.com created", []string{""}); err != nil {
1059			cx.t.Fatal(err)
1060		}
1061	} else {
1062		if err := ctlV3User(cx, []string{"add", "example.com", "--interactive=false"}, "User example.com created", []string{""}); err != nil {
1063			cx.t.Fatal(err)
1064		}
1065	}
1066	if err := spawnWithExpect(append(cx.PrefixArgs(), "role", "add", "test-role-cn"), "Role test-role-cn created"); err != nil {
1067		cx.t.Fatal(err)
1068	}
1069	if err := ctlV3User(cx, []string{"grant-role", "example.com", "test-role-cn"}, "Role test-role-cn is granted to user example.com", nil); err != nil {
1070		cx.t.Fatal(err)
1071	}
1072
1073	// grant a new key for CN based user
1074	if err := ctlV3RoleGrantPermission(cx, "test-role-cn", grantingPerm{true, true, "hoo", "", false}); err != nil {
1075		cx.t.Fatal(err)
1076	}
1077
1078	// grant a new key for username based user
1079	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "bar", "", false}); err != nil {
1080		cx.t.Fatal(err)
1081	}
1082
1083	// try a granted key for CN based user
1084	cx.user, cx.pass = "", ""
1085	if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
1086		cx.t.Error(err)
1087	}
1088
1089	// try a granted key for username based user
1090	cx.user, cx.pass = "test-user", "pass"
1091	if err := ctlV3Put(cx, "bar", "bar", ""); err != nil {
1092		cx.t.Error(err)
1093	}
1094
1095	// try a non granted key for both of them
1096	cx.user, cx.pass = "", ""
1097	if err := ctlV3PutFailPerm(cx, "baz", "bar"); err != nil {
1098		cx.t.Error(err)
1099	}
1100
1101	cx.user, cx.pass = "test-user", "pass"
1102	if err := ctlV3PutFailPerm(cx, "baz", "bar"); err != nil {
1103		cx.t.Error(err)
1104	}
1105}
1106
1107func authTestCertCNAndUsername(cx ctlCtx) {
1108	certCNAndUsername(cx, false)
1109}
1110
1111func authTestCertCNAndUsernameNoPassword(cx ctlCtx) {
1112	certCNAndUsername(cx, true)
1113}
1114
1115func authTestJWTExpire(cx ctlCtx) {
1116	if err := authEnable(cx); err != nil {
1117		cx.t.Fatal(err)
1118	}
1119
1120	cx.user, cx.pass = "root", "root"
1121	authSetupTestUser(cx)
1122
1123	// try a granted key
1124	if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
1125		cx.t.Error(err)
1126	}
1127
1128	// wait an expiration of my JWT token
1129	<-time.After(3 * time.Second)
1130
1131	if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
1132		cx.t.Error(err)
1133	}
1134}
1135