...

Source file src/go.etcd.io/etcd/server/v3/etcdserver/apply_auth_test.go

Documentation: go.etcd.io/etcd/server/v3/etcdserver

     1  // Copyright 2023 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  
    15  package etcdserver
    16  
    17  import (
    18  	"encoding/base64"
    19  	"testing"
    20  	"time"
    21  
    22  	"golang.org/x/crypto/bcrypt"
    23  
    24  	betesting "go.etcd.io/etcd/server/v3/mvcc/backend/testing"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  	"go.uber.org/zap/zaptest"
    28  
    29  	"go.etcd.io/etcd/api/v3/authpb"
    30  	pb "go.etcd.io/etcd/api/v3/etcdserverpb"
    31  	"go.etcd.io/etcd/server/v3/auth"
    32  	"go.etcd.io/etcd/server/v3/lease"
    33  )
    34  
    35  func TestCheckLeasePutsKeys(t *testing.T) {
    36  	lg := zaptest.NewLogger(t)
    37  
    38  	b, _ := betesting.NewDefaultTmpBackend(t)
    39  	defer betesting.Close(t, b)
    40  
    41  	simpleTokenTTLDefault := 300 * time.Second
    42  	tokenTypeSimple := "simple"
    43  	dummyIndexWaiter := func(index uint64) <-chan struct{} {
    44  		ch := make(chan struct{}, 1)
    45  		go func() {
    46  			ch <- struct{}{}
    47  		}()
    48  		return ch
    49  	}
    50  
    51  	tp, _ := auth.NewTokenProvider(zaptest.NewLogger(t), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
    52  	as := auth.NewAuthStore(lg, b, tp, bcrypt.MinCost)
    53  	defer as.AuthDisable()
    54  
    55  	aa := authApplierV3{as: as}
    56  	assert.NoError(t, aa.checkLeasePutsKeys(lease.NewLease(lease.LeaseID(1), 3600)), "auth is disabled, should allow puts")
    57  	assert.NoError(t, enableAuthAndCreateRoot(aa.as), "error while enabling auth")
    58  	aa.authInfo = auth.AuthInfo{Username: "root"}
    59  	assert.NoError(t, aa.checkLeasePutsKeys(lease.NewLease(lease.LeaseID(1), 3600)), "auth is enabled, should allow puts for root")
    60  
    61  	l := lease.NewLease(lease.LeaseID(1), 3600)
    62  	l.SetLeaseItem(lease.LeaseItem{Key: "a"})
    63  	aa.authInfo = auth.AuthInfo{Username: "bob", Revision: 0}
    64  	assert.ErrorIs(t, aa.checkLeasePutsKeys(l), auth.ErrUserEmpty, "auth is enabled, should not allow bob, non existing at rev 0")
    65  	aa.authInfo = auth.AuthInfo{Username: "bob", Revision: 1}
    66  	assert.ErrorIs(t, aa.checkLeasePutsKeys(l), auth.ErrAuthOldRevision, "auth is enabled, old revision")
    67  
    68  	aa.authInfo = auth.AuthInfo{Username: "bob", Revision: aa.as.Revision()}
    69  	assert.ErrorIs(t, aa.checkLeasePutsKeys(l), auth.ErrPermissionDenied, "auth is enabled, bob does not have permissions, bob does not exist")
    70  	_, err := aa.as.UserAdd(&pb.AuthUserAddRequest{Name: "bob", Options: &authpb.UserAddOptions{NoPassword: true}})
    71  	assert.NoError(t, err, "bob should be added without error")
    72  	aa.authInfo = auth.AuthInfo{Username: "bob", Revision: aa.as.Revision()}
    73  	assert.ErrorIs(t, aa.checkLeasePutsKeys(l), auth.ErrPermissionDenied, "auth is enabled, bob exists yet does not have permissions")
    74  
    75  	// allow bob to access "a"
    76  	_, err = aa.as.RoleAdd(&pb.AuthRoleAddRequest{Name: "bobsrole"})
    77  	assert.NoError(t, err, "bobsrole should be added without error")
    78  	_, err = aa.as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
    79  		Name: "bobsrole",
    80  		Perm: &authpb.Permission{
    81  			PermType: authpb.READWRITE,
    82  			Key:      []byte("a"),
    83  			RangeEnd: nil,
    84  		},
    85  	})
    86  	assert.NoError(t, err, "bobsrole should be granted permissions without error")
    87  	_, err = aa.as.UserGrantRole(&pb.AuthUserGrantRoleRequest{
    88  		User: "bob",
    89  		Role: "bobsrole",
    90  	})
    91  	assert.NoError(t, err, "bob should be granted bobsrole without error")
    92  
    93  	aa.authInfo = auth.AuthInfo{Username: "bob", Revision: aa.as.Revision()}
    94  	assert.NoError(t, aa.checkLeasePutsKeys(l), "bob should be able to access key 'a'")
    95  
    96  }
    97  
    98  func enableAuthAndCreateRoot(as auth.AuthStore) error {
    99  	_, err := as.UserAdd(&pb.AuthUserAddRequest{
   100  		Name:           "root",
   101  		HashedPassword: encodePassword("root"),
   102  		Options:        &authpb.UserAddOptions{NoPassword: false}})
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	_, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "root"})
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	_, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "root", Role: "root"})
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	return as.AuthEnable()
   118  }
   119  
   120  func encodePassword(s string) string {
   121  	hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(s), bcrypt.MinCost)
   122  	return base64.StdEncoding.EncodeToString(hashedPassword)
   123  }
   124  

View as plain text