| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055 |
- // Copyright 2016 The etcd Authors
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package e2e
- import (
- "fmt"
- "os"
- "testing"
- "github.com/coreos/etcd/clientv3"
- )
- func TestCtlV3AuthEnable(t *testing.T) { testCtl(t, authEnableTest) }
- func TestCtlV3AuthDisable(t *testing.T) { testCtl(t, authDisableTest) }
- func TestCtlV3AuthWriteKey(t *testing.T) { testCtl(t, authCredWriteKeyTest) }
- func TestCtlV3AuthRoleUpdate(t *testing.T) { testCtl(t, authRoleUpdateTest) }
- func TestCtlV3AuthUserDeleteDuringOps(t *testing.T) { testCtl(t, authUserDeleteDuringOpsTest) }
- func TestCtlV3AuthRoleRevokeDuringOps(t *testing.T) { testCtl(t, authRoleRevokeDuringOpsTest) }
- func TestCtlV3AuthTxn(t *testing.T) { testCtl(t, authTestTxn) }
- func TestCtlV3AuthPrefixPerm(t *testing.T) { testCtl(t, authTestPrefixPerm) }
- func TestCtlV3AuthMemberAdd(t *testing.T) { testCtl(t, authTestMemberAdd) }
- func TestCtlV3AuthMemberRemove(t *testing.T) {
- testCtl(t, authTestMemberRemove, withQuorum(), withNoStrictReconfig())
- }
- func TestCtlV3AuthMemberUpdate(t *testing.T) { testCtl(t, authTestMemberUpdate) }
- func TestCtlV3AuthCertCN(t *testing.T) { testCtl(t, authTestCertCN, withCfg(configClientTLSCertAuth)) }
- func TestCtlV3AuthRevokeWithDelete(t *testing.T) { testCtl(t, authTestRevokeWithDelete) }
- func TestCtlV3AuthInvalidMgmt(t *testing.T) { testCtl(t, authTestInvalidMgmt) }
- func TestCtlV3AuthFromKeyPerm(t *testing.T) { testCtl(t, authTestFromKeyPerm) }
- func TestCtlV3AuthAndWatch(t *testing.T) { testCtl(t, authTestWatch) }
- func TestCtlV3AuthLeaseTestKeepAlive(t *testing.T) { testCtl(t, authLeaseTestKeepAlive) }
- func TestCtlV3AuthLeaseTestTimeToLiveExpired(t *testing.T) { testCtl(t, authLeaseTestTimeToLiveExpired) }
- func TestCtlV3AuthRoleGet(t *testing.T) { testCtl(t, authTestRoleGet) }
- func TestCtlV3AuthUserGet(t *testing.T) { testCtl(t, authTestUserGet) }
- func TestCtlV3AuthRoleList(t *testing.T) { testCtl(t, authTestRoleList) }
- func TestCtlV3AuthDefrag(t *testing.T) { testCtl(t, authTestDefrag) }
- func TestCtlV3AuthEndpointHealth(t *testing.T) {
- testCtl(t, authTestEndpointHealth, withQuorum())
- }
- func TestCtlV3AuthSnapshot(t *testing.T) { testCtl(t, authTestSnapshot) }
- func TestCtlV3AuthCertCNAndUsername(t *testing.T) {
- testCtl(t, authTestCertCNAndUsername, withCfg(configClientTLSCertAuth))
- }
- func authEnableTest(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authEnable(cx ctlCtx) error {
- // create root user with root role
- if err := ctlV3User(cx, []string{"add", "root", "--interactive=false"}, "User root created", []string{"root"}); err != nil {
- return fmt.Errorf("failed to create root user %v", err)
- }
- if err := ctlV3User(cx, []string{"grant-role", "root", "root"}, "Role root is granted to user root", nil); err != nil {
- return fmt.Errorf("failed to grant root user root role %v", err)
- }
- if err := ctlV3AuthEnable(cx); err != nil {
- return fmt.Errorf("authEnableTest ctlV3AuthEnable error (%v)", err)
- }
- return nil
- }
- func ctlV3AuthEnable(cx ctlCtx) error {
- cmdArgs := append(cx.PrefixArgs(), "auth", "enable")
- return spawnWithExpect(cmdArgs, "Authentication Enabled")
- }
- func authDisableTest(cx ctlCtx) {
- // a key that isn't granted to test-user
- if err := ctlV3Put(cx, "hoo", "a", ""); err != nil {
- cx.t.Fatal(err)
- }
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // test-user doesn't have the permission, it must fail
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3PutFailPerm(cx, "hoo", "bar"); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- if err := ctlV3AuthDisable(cx); err != nil {
- cx.t.Fatalf("authDisableTest ctlV3AuthDisable error (%v)", err)
- }
- // now ErrAuthNotEnabled of Authenticate() is simply ignored
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
- cx.t.Fatal(err)
- }
- // now the key can be accessed
- cx.user, cx.pass = "", ""
- if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
- cx.t.Fatal(err)
- }
- // confirm put succeeded
- if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil {
- cx.t.Fatal(err)
- }
- }
- func ctlV3AuthDisable(cx ctlCtx) error {
- cmdArgs := append(cx.PrefixArgs(), "auth", "disable")
- return spawnWithExpect(cmdArgs, "Authentication Disabled")
- }
- func authCredWriteKeyTest(cx ctlCtx) {
- // baseline key to check for failed puts
- if err := ctlV3Put(cx, "foo", "a", ""); err != nil {
- cx.t.Fatal(err)
- }
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // confirm root role can access to all keys
- if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
- cx.t.Fatal(err)
- }
- if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
- cx.t.Fatal(err)
- }
- // try invalid user
- cx.user, cx.pass = "a", "b"
- if err := ctlV3PutFailAuth(cx, "foo", "bar"); err != nil {
- cx.t.Fatal(err)
- }
- // confirm put failed
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
- cx.t.Fatal(err)
- }
- // try good user
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Put(cx, "foo", "bar2", ""); err != nil {
- cx.t.Fatal(err)
- }
- // confirm put succeeded
- if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar2"}}...); err != nil {
- cx.t.Fatal(err)
- }
- // try bad password
- cx.user, cx.pass = "test-user", "badpass"
- if err := ctlV3PutFailAuth(cx, "foo", "baz"); err != nil {
- cx.t.Fatal(err)
- }
- // confirm put failed
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar2"}}...); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authRoleUpdateTest(cx ctlCtx) {
- if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
- cx.t.Fatal(err)
- }
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // try put to not granted key
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3PutFailPerm(cx, "hoo", "bar"); err != nil {
- cx.t.Fatal(err)
- }
- // grant a new key
- cx.user, cx.pass = "root", "root"
- if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "hoo", "", false}); err != nil {
- cx.t.Fatal(err)
- }
- // try a newly granted key
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
- cx.t.Fatal(err)
- }
- // confirm put succeeded
- if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil {
- cx.t.Fatal(err)
- }
- // revoke the newly granted key
- cx.user, cx.pass = "root", "root"
- if err := ctlV3RoleRevokePermission(cx, "test-role", "hoo", "", false); err != nil {
- cx.t.Fatal(err)
- }
- // try put to the revoked key
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3PutFailPerm(cx, "hoo", "bar"); err != nil {
- cx.t.Fatal(err)
- }
- // confirm a key still granted can be accessed
- if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authUserDeleteDuringOpsTest(cx ctlCtx) {
- if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
- cx.t.Fatal(err)
- }
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // create a key
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
- cx.t.Fatal(err)
- }
- // confirm put succeeded
- if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
- cx.t.Fatal(err)
- }
- // delete the user
- cx.user, cx.pass = "root", "root"
- err := ctlV3User(cx, []string{"delete", "test-user"}, "User test-user deleted", []string{})
- if err != nil {
- cx.t.Fatal(err)
- }
- // check the user is deleted
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3PutFailAuth(cx, "foo", "baz"); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authRoleRevokeDuringOpsTest(cx ctlCtx) {
- if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
- cx.t.Fatal(err)
- }
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // create a key
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
- cx.t.Fatal(err)
- }
- // confirm put succeeded
- if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
- cx.t.Fatal(err)
- }
- // create a new role
- cx.user, cx.pass = "root", "root"
- if err := ctlV3Role(cx, []string{"add", "test-role2"}, "Role test-role2 created"); err != nil {
- cx.t.Fatal(err)
- }
- // grant a new key to the new role
- if err := ctlV3RoleGrantPermission(cx, "test-role2", grantingPerm{true, true, "hoo", "", false}); err != nil {
- cx.t.Fatal(err)
- }
- // grant the new role to the user
- if err := ctlV3User(cx, []string{"grant-role", "test-user", "test-role2"}, "Role test-role2 is granted to user test-user", nil); err != nil {
- cx.t.Fatal(err)
- }
- // try a newly granted key
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
- cx.t.Fatal(err)
- }
- // confirm put succeeded
- if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil {
- cx.t.Fatal(err)
- }
- // revoke a role from the user
- cx.user, cx.pass = "root", "root"
- err := ctlV3User(cx, []string{"revoke-role", "test-user", "test-role"}, "Role test-role is revoked from user test-user", []string{})
- if err != nil {
- cx.t.Fatal(err)
- }
- // check the role is revoked and permission is lost from the user
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3PutFailPerm(cx, "foo", "baz"); err != nil {
- cx.t.Fatal(err)
- }
- // try a key that can be accessed from the remaining role
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Put(cx, "hoo", "bar2", ""); err != nil {
- cx.t.Fatal(err)
- }
- // confirm put succeeded
- if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar2"}}...); err != nil {
- cx.t.Fatal(err)
- }
- }
- func ctlV3PutFailAuth(cx ctlCtx, key, val string) error {
- return spawnWithExpect(append(cx.PrefixArgs(), "put", key, val), "authentication failed")
- }
- func ctlV3PutFailPerm(cx ctlCtx, key, val string) error {
- return spawnWithExpect(append(cx.PrefixArgs(), "put", key, val), "permission denied")
- }
- func authSetupTestUser(cx ctlCtx) {
- if err := ctlV3User(cx, []string{"add", "test-user", "--interactive=false"}, "User test-user created", []string{"pass"}); err != nil {
- cx.t.Fatal(err)
- }
- if err := spawnWithExpect(append(cx.PrefixArgs(), "role", "add", "test-role"), "Role test-role created"); err != nil {
- cx.t.Fatal(err)
- }
- if err := ctlV3User(cx, []string{"grant-role", "test-user", "test-role"}, "Role test-role is granted to user test-user", nil); err != nil {
- cx.t.Fatal(err)
- }
- cmd := append(cx.PrefixArgs(), "role", "grant-permission", "test-role", "readwrite", "foo")
- if err := spawnWithExpect(cmd, "Role test-role updated"); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestTxn(cx ctlCtx) {
- // keys with 1 suffix aren't granted to test-user
- // keys with 2 suffix are granted to test-user
- keys := []string{"c1", "s1", "f1"}
- grantedKeys := []string{"c2", "s2", "f2"}
- for _, key := range keys {
- if err := ctlV3Put(cx, key, "v", ""); err != nil {
- cx.t.Fatal(err)
- }
- }
- for _, key := range grantedKeys {
- if err := ctlV3Put(cx, key, "v", ""); err != nil {
- cx.t.Fatal(err)
- }
- }
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // grant keys to test-user
- cx.user, cx.pass = "root", "root"
- for _, key := range grantedKeys {
- if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, key, "", false}); err != nil {
- cx.t.Fatal(err)
- }
- }
- // now test txn
- cx.interactive = true
- cx.user, cx.pass = "test-user", "pass"
- rqs := txnRequests{
- compare: []string{`version("c2") = "1"`},
- ifSucess: []string{"get s2"},
- ifFail: []string{"get f2"},
- results: []string{"SUCCESS", "s2", "v"},
- }
- if err := ctlV3Txn(cx, rqs); err != nil {
- cx.t.Fatal(err)
- }
- // a key of compare case isn't granted
- rqs = txnRequests{
- compare: []string{`version("c1") = "1"`},
- ifSucess: []string{"get s2"},
- ifFail: []string{"get f2"},
- results: []string{"Error: etcdserver: permission denied"},
- }
- if err := ctlV3Txn(cx, rqs); err != nil {
- cx.t.Fatal(err)
- }
- // a key of success case isn't granted
- rqs = txnRequests{
- compare: []string{`version("c2") = "1"`},
- ifSucess: []string{"get s1"},
- ifFail: []string{"get f2"},
- results: []string{"Error: etcdserver: permission denied"},
- }
- if err := ctlV3Txn(cx, rqs); err != nil {
- cx.t.Fatal(err)
- }
- // a key of failure case isn't granted
- rqs = txnRequests{
- compare: []string{`version("c2") = "1"`},
- ifSucess: []string{"get s2"},
- ifFail: []string{"get f1"},
- results: []string{"Error: etcdserver: permission denied"},
- }
- if err := ctlV3Txn(cx, rqs); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestPrefixPerm(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- prefix := "/prefix/" // directory like prefix
- // grant keys to test-user
- cx.user, cx.pass = "root", "root"
- if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, prefix, "", true}); err != nil {
- cx.t.Fatal(err)
- }
- // try a prefix granted permission
- cx.user, cx.pass = "test-user", "pass"
- for i := 0; i < 10; i++ {
- key := fmt.Sprintf("%s%d", prefix, i)
- if err := ctlV3Put(cx, key, "val", ""); err != nil {
- cx.t.Fatal(err)
- }
- }
- if err := ctlV3PutFailPerm(cx, clientv3.GetPrefixRangeEnd(prefix), "baz"); err != nil {
- cx.t.Fatal(err)
- }
- // grant the entire keys to test-user
- cx.user, cx.pass = "root", "root"
- if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "", "", true}); err != nil {
- cx.t.Fatal(err)
- }
- prefix2 := "/prefix2/"
- cx.user, cx.pass = "test-user", "pass"
- for i := 0; i < 10; i++ {
- key := fmt.Sprintf("%s%d", prefix2, i)
- if err := ctlV3Put(cx, key, "val", ""); err != nil {
- cx.t.Fatal(err)
- }
- }
- }
- func authTestMemberAdd(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- peerURL := fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+11)
- // ordinary user cannot add a new member
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3MemberAdd(cx, peerURL); err == nil {
- cx.t.Fatalf("ordinary user must not be allowed to add a member")
- }
- // root can add a new member
- cx.user, cx.pass = "root", "root"
- if err := ctlV3MemberAdd(cx, peerURL); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestMemberRemove(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- ep, memIDToRemove, clusterID := cx.memberToRemove()
- // ordinary user cannot remove a member
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3MemberRemove(cx, ep, memIDToRemove, clusterID); err == nil {
- cx.t.Fatalf("ordinary user must not be allowed to remove a member")
- }
- // root can remove a member
- cx.user, cx.pass = "root", "root"
- if err := ctlV3MemberRemove(cx, ep, memIDToRemove, clusterID); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestMemberUpdate(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- mr, err := getMemberList(cx)
- if err != nil {
- cx.t.Fatal(err)
- }
- // ordinary user cannot update a member
- cx.user, cx.pass = "test-user", "pass"
- peerURL := fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+11)
- memberID := fmt.Sprintf("%x", mr.Members[0].ID)
- if err = ctlV3MemberUpdate(cx, memberID, peerURL); err == nil {
- cx.t.Fatalf("ordinary user must not be allowed to update a member")
- }
- // root can update a member
- cx.user, cx.pass = "root", "root"
- if err = ctlV3MemberUpdate(cx, memberID, peerURL); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestCertCN(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- if err := ctlV3User(cx, []string{"add", "example.com", "--interactive=false"}, "User example.com created", []string{""}); err != nil {
- cx.t.Fatal(err)
- }
- if err := spawnWithExpect(append(cx.PrefixArgs(), "role", "add", "test-role"), "Role test-role created"); err != nil {
- cx.t.Fatal(err)
- }
- if err := ctlV3User(cx, []string{"grant-role", "example.com", "test-role"}, "Role test-role is granted to user example.com", nil); err != nil {
- cx.t.Fatal(err)
- }
- // grant a new key
- if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "hoo", "", false}); err != nil {
- cx.t.Fatal(err)
- }
- // try a granted key
- cx.user, cx.pass = "", ""
- if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
- cx.t.Error(err)
- }
- // try a non granted key
- cx.user, cx.pass = "", ""
- if err := ctlV3PutFailPerm(cx, "baz", "bar"); err != nil {
- cx.t.Error(err)
- }
- }
- func authTestRevokeWithDelete(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // create a new role
- cx.user, cx.pass = "root", "root"
- if err := ctlV3Role(cx, []string{"add", "test-role2"}, "Role test-role2 created"); err != nil {
- cx.t.Fatal(err)
- }
- // grant the new role to the user
- if err := ctlV3User(cx, []string{"grant-role", "test-user", "test-role2"}, "Role test-role2 is granted to user test-user", nil); err != nil {
- cx.t.Fatal(err)
- }
- // check the result
- if err := ctlV3User(cx, []string{"get", "test-user"}, "Roles: test-role test-role2", nil); err != nil {
- cx.t.Fatal(err)
- }
- // delete the role, test-role2 must be revoked from test-user
- if err := ctlV3Role(cx, []string{"delete", "test-role2"}, "Role test-role2 deleted"); err != nil {
- cx.t.Fatal(err)
- }
- // check the result
- if err := ctlV3User(cx, []string{"get", "test-user"}, "Roles: test-role", nil); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestInvalidMgmt(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- if err := ctlV3Role(cx, []string{"delete", "root"}, "Error: etcdserver: invalid auth management"); err == nil {
- cx.t.Fatal("deleting the role root must not be allowed")
- }
- if err := ctlV3User(cx, []string{"revoke-role", "root", "root"}, "Error: etcdserver: invalid auth management", []string{}); err == nil {
- cx.t.Fatal("revoking the role root from the user root must not be allowed")
- }
- }
- func authTestFromKeyPerm(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // grant keys after z to test-user
- cx.user, cx.pass = "root", "root"
- if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "z", "\x00", false}); err != nil {
- cx.t.Fatal(err)
- }
- // try the granted open ended permission
- cx.user, cx.pass = "test-user", "pass"
- for i := 0; i < 10; i++ {
- key := fmt.Sprintf("z%d", i)
- if err := ctlV3Put(cx, key, "val", ""); err != nil {
- cx.t.Fatal(err)
- }
- }
- largeKey := ""
- for i := 0; i < 10; i++ {
- largeKey += "\xff"
- if err := ctlV3Put(cx, largeKey, "val", ""); err != nil {
- cx.t.Fatal(err)
- }
- }
- // try a non granted key
- if err := ctlV3PutFailPerm(cx, "x", "baz"); err != nil {
- cx.t.Fatal(err)
- }
- // revoke the open ended permission
- cx.user, cx.pass = "root", "root"
- if err := ctlV3RoleRevokePermission(cx, "test-role", "z", "", true); err != nil {
- cx.t.Fatal(err)
- }
- // try the revoked open ended permission
- cx.user, cx.pass = "test-user", "pass"
- for i := 0; i < 10; i++ {
- key := fmt.Sprintf("z%d", i)
- if err := ctlV3PutFailPerm(cx, key, "val"); err != nil {
- cx.t.Fatal(err)
- }
- }
- // grant the entire keys
- cx.user, cx.pass = "root", "root"
- if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "", "\x00", false}); err != nil {
- cx.t.Fatal(err)
- }
- // try keys, of course it must be allowed because test-role has a permission of the entire keys
- cx.user, cx.pass = "test-user", "pass"
- for i := 0; i < 10; i++ {
- key := fmt.Sprintf("z%d", i)
- if err := ctlV3Put(cx, key, "val", ""); err != nil {
- cx.t.Fatal(err)
- }
- }
- // revoke the entire keys
- cx.user, cx.pass = "root", "root"
- if err := ctlV3RoleRevokePermission(cx, "test-role", "", "", true); err != nil {
- cx.t.Fatal(err)
- }
- // try the revoked entire key permission
- cx.user, cx.pass = "test-user", "pass"
- for i := 0; i < 10; i++ {
- key := fmt.Sprintf("z%d", i)
- if err := ctlV3PutFailPerm(cx, key, "val"); err != nil {
- cx.t.Fatal(err)
- }
- }
- }
- func authLeaseTestKeepAlive(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // put with TTL 10 seconds and keep-alive
- leaseID, err := ctlV3LeaseGrant(cx, 10)
- if err != nil {
- cx.t.Fatalf("leaseTestKeepAlive: ctlV3LeaseGrant error (%v)", err)
- }
- if err := ctlV3Put(cx, "key", "val", leaseID); err != nil {
- cx.t.Fatalf("leaseTestKeepAlive: ctlV3Put error (%v)", err)
- }
- if err := ctlV3LeaseKeepAlive(cx, leaseID); err != nil {
- cx.t.Fatalf("leaseTestKeepAlive: ctlV3LeaseKeepAlive error (%v)", err)
- }
- if err := ctlV3Get(cx, []string{"key"}, kv{"key", "val"}); err != nil {
- cx.t.Fatalf("leaseTestKeepAlive: ctlV3Get error (%v)", err)
- }
- }
- func authLeaseTestTimeToLiveExpired(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- ttl := 3
- if err := leaseTestTimeToLiveExpire(cx, ttl); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestWatch(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // grant a key range
- if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "key", "key4", false}); err != nil {
- cx.t.Fatal(err)
- }
- tests := []struct {
- puts []kv
- args []string
- wkv []kvExec
- want bool
- }{
- { // watch 1 key, should be successful
- []kv{{"key", "value"}},
- []string{"key", "--rev", "1"},
- []kvExec{{key: "key", val: "value"}},
- true,
- },
- { // watch 3 keys by range, should be successful
- []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}},
- []string{"key", "key3", "--rev", "1"},
- []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}},
- true,
- },
- { // watch 1 key, should not be successful
- []kv{},
- []string{"key5", "--rev", "1"},
- []kvExec{},
- false,
- },
- { // watch 3 keys by range, should not be successful
- []kv{},
- []string{"key", "key6", "--rev", "1"},
- []kvExec{},
- false,
- },
- }
- cx.user, cx.pass = "test-user", "pass"
- for i, tt := range tests {
- donec := make(chan struct{})
- go func(i int, puts []kv) {
- defer close(donec)
- for j := range puts {
- if err := ctlV3Put(cx, puts[j].key, puts[j].val, ""); err != nil {
- cx.t.Fatalf("watchTest #%d-%d: ctlV3Put error (%v)", i, j, err)
- }
- }
- }(i, tt.puts)
- var err error
- if tt.want {
- err = ctlV3Watch(cx, tt.args, tt.wkv...)
- } else {
- err = ctlV3WatchFailPerm(cx, tt.args)
- }
- if err != nil {
- if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
- cx.t.Errorf("watchTest #%d: ctlV3Watch error (%v)", i, err)
- }
- }
- <-donec
- }
- }
- func authTestRoleGet(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- expected := []string{
- "Role test-role",
- "KV Read:", "foo",
- "KV Write:", "foo",
- }
- if err := spawnWithExpects(append(cx.PrefixArgs(), "role", "get", "test-role"), expected...); err != nil {
- cx.t.Fatal(err)
- }
- // test-user can get the information of test-role because it belongs to the role
- cx.user, cx.pass = "test-user", "pass"
- if err := spawnWithExpects(append(cx.PrefixArgs(), "role", "get", "test-role"), expected...); err != nil {
- cx.t.Fatal(err)
- }
- // test-user cannot get the information of root because it doesn't belong to the role
- expected = []string{
- "Error: etcdserver: permission denied",
- }
- if err := spawnWithExpects(append(cx.PrefixArgs(), "role", "get", "root"), expected...); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestUserGet(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- expected := []string{
- "User: test-user",
- "Roles: test-role",
- }
- if err := spawnWithExpects(append(cx.PrefixArgs(), "user", "get", "test-user"), expected...); err != nil {
- cx.t.Fatal(err)
- }
- // test-user can get the information of test-user itself
- cx.user, cx.pass = "test-user", "pass"
- if err := spawnWithExpects(append(cx.PrefixArgs(), "user", "get", "test-user"), expected...); err != nil {
- cx.t.Fatal(err)
- }
- // test-user cannot get the information of root
- expected = []string{
- "Error: etcdserver: permission denied",
- }
- if err := spawnWithExpects(append(cx.PrefixArgs(), "user", "get", "root"), expected...); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestRoleList(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- if err := spawnWithExpect(append(cx.PrefixArgs(), "role", "list"), "test-role"); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestDefrag(cx ctlCtx) {
- maintenanceInitKeys(cx)
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- // ordinary user cannot defrag
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Defrag(cx); err == nil {
- cx.t.Fatal("ordinary user should not be able to issue a defrag request")
- }
- // root can defrag
- cx.user, cx.pass = "root", "root"
- if err := ctlV3Defrag(cx); err != nil {
- cx.t.Fatal(err)
- }
- }
- func authTestSnapshot(cx ctlCtx) {
- maintenanceInitKeys(cx)
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- fpath := "test.snapshot"
- defer os.RemoveAll(fpath)
- // ordinary user cannot save a snapshot
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3SnapshotSave(cx, fpath); err == nil {
- cx.t.Fatal("ordinary user should not be able to save a snapshot")
- }
- // root can save a snapshot
- cx.user, cx.pass = "root", "root"
- if err := ctlV3SnapshotSave(cx, fpath); err != nil {
- cx.t.Fatalf("snapshotTest ctlV3SnapshotSave error (%v)", err)
- }
- st, err := getSnapshotStatus(cx, fpath)
- if err != nil {
- cx.t.Fatalf("snapshotTest getSnapshotStatus error (%v)", err)
- }
- if st.Revision != 4 {
- cx.t.Fatalf("expected 4, got %d", st.Revision)
- }
- if st.TotalKey < 3 {
- cx.t.Fatalf("expected at least 3, got %d", st.TotalKey)
- }
- }
- func authTestEndpointHealth(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- if err := ctlV3EndpointHealth(cx); err != nil {
- cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err)
- }
- // health checking with an ordinary user "succeeds" since permission denial goes through consensus
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3EndpointHealth(cx); err != nil {
- cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err)
- }
- // succeed if permissions granted for ordinary user
- cx.user, cx.pass = "root", "root"
- if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "health", "", false}); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3EndpointHealth(cx); err != nil {
- cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err)
- }
- }
- func authTestCertCNAndUsername(cx ctlCtx) {
- if err := authEnable(cx); err != nil {
- cx.t.Fatal(err)
- }
- cx.user, cx.pass = "root", "root"
- authSetupTestUser(cx)
- if err := ctlV3User(cx, []string{"add", "example.com", "--interactive=false"}, "User example.com created", []string{""}); err != nil {
- cx.t.Fatal(err)
- }
- if err := spawnWithExpect(append(cx.PrefixArgs(), "role", "add", "test-role-cn"), "Role test-role-cn created"); err != nil {
- cx.t.Fatal(err)
- }
- 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 {
- cx.t.Fatal(err)
- }
- // grant a new key for CN based user
- if err := ctlV3RoleGrantPermission(cx, "test-role-cn", grantingPerm{true, true, "hoo", "", false}); err != nil {
- cx.t.Fatal(err)
- }
- // grant a new key for username based user
- if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "bar", "", false}); err != nil {
- cx.t.Fatal(err)
- }
- // try a granted key for CN based user
- cx.user, cx.pass = "", ""
- if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
- cx.t.Error(err)
- }
- // try a granted key for username based user
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3Put(cx, "bar", "bar", ""); err != nil {
- cx.t.Error(err)
- }
- // try a non granted key for both of them
- cx.user, cx.pass = "", ""
- if err := ctlV3PutFailPerm(cx, "baz", "bar"); err != nil {
- cx.t.Error(err)
- }
- cx.user, cx.pass = "test-user", "pass"
- if err := ctlV3PutFailPerm(cx, "baz", "bar"); err != nil {
- cx.t.Error(err)
- }
- }
|