mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00

This contains a slight refactoring to expose enough information to write meaningful tests for auth applier v3. Signed-off-by: Thomas Jungblut <tjungblu@redhat.com>
123 lines
4.3 KiB
Go
123 lines
4.3 KiB
Go
// Copyright 2023 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 etcdserver
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
betesting "go.etcd.io/etcd/server/v3/mvcc/backend/testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"go.uber.org/zap/zaptest"
|
|
|
|
"go.etcd.io/etcd/api/v3/authpb"
|
|
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
|
"go.etcd.io/etcd/server/v3/auth"
|
|
"go.etcd.io/etcd/server/v3/lease"
|
|
)
|
|
|
|
func TestCheckLeasePutsKeys(t *testing.T) {
|
|
lg := zaptest.NewLogger(t)
|
|
|
|
b, _ := betesting.NewDefaultTmpBackend(t)
|
|
defer betesting.Close(t, b)
|
|
|
|
simpleTokenTTLDefault := 300 * time.Second
|
|
tokenTypeSimple := "simple"
|
|
dummyIndexWaiter := func(index uint64) <-chan struct{} {
|
|
ch := make(chan struct{}, 1)
|
|
go func() {
|
|
ch <- struct{}{}
|
|
}()
|
|
return ch
|
|
}
|
|
|
|
tp, _ := auth.NewTokenProvider(zaptest.NewLogger(t), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
|
|
as := auth.NewAuthStore(lg, b, tp, bcrypt.MinCost)
|
|
|
|
aa := authApplierV3{as: as}
|
|
assert.NoError(t, aa.checkLeasePutsKeys(lease.NewLease(lease.LeaseID(1), 3600)), "auth is disabled, should allow puts")
|
|
assert.NoError(t, enableAuthAndCreateRoot(aa.as), "error while enabling auth")
|
|
aa.authInfo = auth.AuthInfo{Username: "root"}
|
|
assert.NoError(t, aa.checkLeasePutsKeys(lease.NewLease(lease.LeaseID(1), 3600)), "auth is enabled, should allow puts for root")
|
|
|
|
l := lease.NewLease(lease.LeaseID(1), 3600)
|
|
l.SetLeaseItem(lease.LeaseItem{Key: "a"})
|
|
aa.authInfo = auth.AuthInfo{Username: "bob", Revision: 0}
|
|
assert.ErrorIs(t, aa.checkLeasePutsKeys(l), auth.ErrUserEmpty, "auth is enabled, should not allow bob, non existing at rev 0")
|
|
aa.authInfo = auth.AuthInfo{Username: "bob", Revision: 1}
|
|
assert.ErrorIs(t, aa.checkLeasePutsKeys(l), auth.ErrAuthOldRevision, "auth is enabled, old revision")
|
|
|
|
aa.authInfo = auth.AuthInfo{Username: "bob", Revision: aa.as.Revision()}
|
|
assert.ErrorIs(t, aa.checkLeasePutsKeys(l), auth.ErrPermissionDenied, "auth is enabled, bob does not have permissions, bob does not exist")
|
|
_, err := aa.as.UserAdd(&pb.AuthUserAddRequest{Name: "bob", Options: &authpb.UserAddOptions{NoPassword: true}})
|
|
assert.NoError(t, err, "bob should be added without error")
|
|
aa.authInfo = auth.AuthInfo{Username: "bob", Revision: aa.as.Revision()}
|
|
assert.ErrorIs(t, aa.checkLeasePutsKeys(l), auth.ErrPermissionDenied, "auth is enabled, bob exists yet does not have permissions")
|
|
|
|
// allow bob to access "a"
|
|
_, err = aa.as.RoleAdd(&pb.AuthRoleAddRequest{Name: "bobsrole"})
|
|
assert.NoError(t, err, "bobsrole should be added without error")
|
|
_, err = aa.as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
|
|
Name: "bobsrole",
|
|
Perm: &authpb.Permission{
|
|
PermType: authpb.READWRITE,
|
|
Key: []byte("a"),
|
|
RangeEnd: nil,
|
|
},
|
|
})
|
|
assert.NoError(t, err, "bobsrole should be granted permissions without error")
|
|
_, err = aa.as.UserGrantRole(&pb.AuthUserGrantRoleRequest{
|
|
User: "bob",
|
|
Role: "bobsrole",
|
|
})
|
|
assert.NoError(t, err, "bob should be granted bobsrole without error")
|
|
|
|
aa.authInfo = auth.AuthInfo{Username: "bob", Revision: aa.as.Revision()}
|
|
assert.NoError(t, aa.checkLeasePutsKeys(l), "bob should be able to access key 'a'")
|
|
|
|
}
|
|
|
|
func enableAuthAndCreateRoot(as auth.AuthStore) error {
|
|
_, err := as.UserAdd(&pb.AuthUserAddRequest{
|
|
Name: "root",
|
|
HashedPassword: encodePassword("root"),
|
|
Options: &authpb.UserAddOptions{NoPassword: false}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "root"})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "root", Role: "root"})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return as.AuthEnable()
|
|
}
|
|
|
|
func encodePassword(s string) string {
|
|
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(s), bcrypt.MinCost)
|
|
return base64.StdEncoding.EncodeToString(hashedPassword)
|
|
}
|