...

Source file src/go.etcd.io/etcd/server/v3/auth/store.go

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

     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  
    15  package auth
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"encoding/base64"
    21  	"encoding/binary"
    22  	"errors"
    23  	"sort"
    24  	"strings"
    25  	"sync"
    26  	"sync/atomic"
    27  	"time"
    28  
    29  	"go.etcd.io/etcd/api/v3/authpb"
    30  	pb "go.etcd.io/etcd/api/v3/etcdserverpb"
    31  	"go.etcd.io/etcd/api/v3/v3rpc/rpctypes"
    32  	"go.etcd.io/etcd/server/v3/mvcc/backend"
    33  	"go.etcd.io/etcd/server/v3/mvcc/buckets"
    34  
    35  	"go.uber.org/zap"
    36  	"golang.org/x/crypto/bcrypt"
    37  	"google.golang.org/grpc/credentials"
    38  	"google.golang.org/grpc/metadata"
    39  	"google.golang.org/grpc/peer"
    40  )
    41  
    42  var (
    43  	enableFlagKey = []byte("authEnabled")
    44  	authEnabled   = []byte{1}
    45  	authDisabled  = []byte{0}
    46  
    47  	revisionKey = []byte("authRevision")
    48  
    49  	ErrRootUserNotExist     = errors.New("auth: root user does not exist")
    50  	ErrRootRoleNotExist     = errors.New("auth: root user does not have root role")
    51  	ErrUserAlreadyExist     = errors.New("auth: user already exists")
    52  	ErrUserEmpty            = errors.New("auth: user name is empty")
    53  	ErrUserNotFound         = errors.New("auth: user not found")
    54  	ErrRoleAlreadyExist     = errors.New("auth: role already exists")
    55  	ErrRoleNotFound         = errors.New("auth: role not found")
    56  	ErrRoleEmpty            = errors.New("auth: role name is empty")
    57  	ErrPermissionNotGiven   = errors.New("auth: permission not given")
    58  	ErrAuthFailed           = errors.New("auth: authentication failed, invalid user ID or password")
    59  	ErrNoPasswordUser       = errors.New("auth: authentication failed, password was given for no password user")
    60  	ErrPermissionDenied     = errors.New("auth: permission denied")
    61  	ErrRoleNotGranted       = errors.New("auth: role is not granted to the user")
    62  	ErrPermissionNotGranted = errors.New("auth: permission is not granted to the role")
    63  	ErrAuthNotEnabled       = errors.New("auth: authentication is not enabled")
    64  	ErrAuthOldRevision      = errors.New("auth: revision in header is old")
    65  	ErrInvalidAuthToken     = errors.New("auth: invalid auth token")
    66  	ErrInvalidAuthOpts      = errors.New("auth: invalid auth options")
    67  	ErrInvalidAuthMgmt      = errors.New("auth: invalid auth management")
    68  	ErrInvalidAuthMethod    = errors.New("auth: invalid auth signature method")
    69  	ErrMissingKey           = errors.New("auth: missing key data")
    70  	ErrKeyMismatch          = errors.New("auth: public and private keys don't match")
    71  	ErrVerifyOnly           = errors.New("auth: token signing attempted with verify-only key")
    72  )
    73  
    74  const (
    75  	rootUser = "root"
    76  	rootRole = "root"
    77  
    78  	tokenTypeSimple = "simple"
    79  	tokenTypeJWT    = "jwt"
    80  
    81  	revBytesLen = 8
    82  )
    83  
    84  type AuthInfo struct {
    85  	Username string
    86  	Revision uint64
    87  }
    88  
    89  // AuthenticateParamIndex is used for a key of context in the parameters of Authenticate()
    90  type AuthenticateParamIndex struct{}
    91  
    92  // AuthenticateParamSimpleTokenPrefix is used for a key of context in the parameters of Authenticate()
    93  type AuthenticateParamSimpleTokenPrefix struct{}
    94  
    95  // AuthStore defines auth storage interface.
    96  type AuthStore interface {
    97  	// AuthEnable turns on the authentication feature
    98  	AuthEnable() error
    99  
   100  	// AuthDisable turns off the authentication feature
   101  	AuthDisable()
   102  
   103  	// IsAuthEnabled returns true if the authentication feature is enabled.
   104  	IsAuthEnabled() bool
   105  
   106  	// Authenticate does authentication based on given user name and password
   107  	Authenticate(ctx context.Context, username, password string) (*pb.AuthenticateResponse, error)
   108  
   109  	// Recover recovers the state of auth store from the given backend
   110  	Recover(b backend.Backend)
   111  
   112  	// UserAdd adds a new user
   113  	UserAdd(r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse, error)
   114  
   115  	// UserDelete deletes a user
   116  	UserDelete(r *pb.AuthUserDeleteRequest) (*pb.AuthUserDeleteResponse, error)
   117  
   118  	// UserChangePassword changes a password of a user
   119  	UserChangePassword(r *pb.AuthUserChangePasswordRequest) (*pb.AuthUserChangePasswordResponse, error)
   120  
   121  	// UserGrantRole grants a role to the user
   122  	UserGrantRole(r *pb.AuthUserGrantRoleRequest) (*pb.AuthUserGrantRoleResponse, error)
   123  
   124  	// UserGet gets the detailed information of a users
   125  	UserGet(r *pb.AuthUserGetRequest) (*pb.AuthUserGetResponse, error)
   126  
   127  	// UserRevokeRole revokes a role of a user
   128  	UserRevokeRole(r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUserRevokeRoleResponse, error)
   129  
   130  	// RoleAdd adds a new role
   131  	RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error)
   132  
   133  	// RoleGrantPermission grants a permission to a role
   134  	RoleGrantPermission(r *pb.AuthRoleGrantPermissionRequest) (*pb.AuthRoleGrantPermissionResponse, error)
   135  
   136  	// RoleGet gets the detailed information of a role
   137  	RoleGet(r *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse, error)
   138  
   139  	// RoleRevokePermission gets the detailed information of a role
   140  	RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error)
   141  
   142  	// RoleDelete gets the detailed information of a role
   143  	RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error)
   144  
   145  	// UserList gets a list of all users
   146  	UserList(r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error)
   147  
   148  	// RoleList gets a list of all roles
   149  	RoleList(r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error)
   150  
   151  	// IsPutPermitted checks put permission of the user
   152  	IsPutPermitted(authInfo *AuthInfo, key []byte) error
   153  
   154  	// IsRangePermitted checks range permission of the user
   155  	IsRangePermitted(authInfo *AuthInfo, key, rangeEnd []byte) error
   156  
   157  	// IsDeleteRangePermitted checks delete-range permission of the user
   158  	IsDeleteRangePermitted(authInfo *AuthInfo, key, rangeEnd []byte) error
   159  
   160  	// IsAdminPermitted checks admin permission of the user
   161  	IsAdminPermitted(authInfo *AuthInfo) error
   162  
   163  	// GenTokenPrefix produces a random string in a case of simple token
   164  	// in a case of JWT, it produces an empty string
   165  	GenTokenPrefix() (string, error)
   166  
   167  	// Revision gets current revision of authStore
   168  	Revision() uint64
   169  
   170  	// CheckPassword checks a given pair of username and password is correct
   171  	CheckPassword(username, password string) (uint64, error)
   172  
   173  	// Close does cleanup of AuthStore
   174  	Close() error
   175  
   176  	// AuthInfoFromCtx gets AuthInfo from gRPC's context
   177  	AuthInfoFromCtx(ctx context.Context) (*AuthInfo, error)
   178  
   179  	// AuthInfoFromTLS gets AuthInfo from TLS info of gRPC's context
   180  	AuthInfoFromTLS(ctx context.Context) *AuthInfo
   181  
   182  	// WithRoot generates and installs a token that can be used as a root credential
   183  	WithRoot(ctx context.Context) context.Context
   184  
   185  	// HasRole checks that user has role
   186  	HasRole(user, role string) bool
   187  
   188  	// BcryptCost gets strength of hashing bcrypted auth password
   189  	BcryptCost() int
   190  }
   191  
   192  type TokenProvider interface {
   193  	info(ctx context.Context, token string, revision uint64) (*AuthInfo, bool)
   194  	assign(ctx context.Context, username string, revision uint64) (string, error)
   195  	enable()
   196  	disable()
   197  
   198  	invalidateUser(string)
   199  	genTokenPrefix() (string, error)
   200  }
   201  
   202  type authStore struct {
   203  	// atomic operations; need 64-bit align, or 32-bit tests will crash
   204  	revision uint64
   205  
   206  	lg        *zap.Logger
   207  	be        backend.Backend
   208  	enabled   bool
   209  	enabledMu sync.RWMutex
   210  
   211  	// rangePermCache needs to be protected by rangePermCacheMu
   212  	// rangePermCacheMu needs to be write locked only in initialization phase or configuration changes
   213  	// Hot paths like Range(), needs to acquire read lock for improving performance
   214  	//
   215  	// Note that BatchTx and ReadTx cannot be a mutex for rangePermCache because they are independent resources
   216  	// see also: https://github.com/etcd-io/etcd/pull/13920#discussion_r849114855
   217  	rangePermCache   map[string]*unifiedRangePermissions // username -> unifiedRangePermissions
   218  	rangePermCacheMu sync.RWMutex
   219  
   220  	tokenProvider TokenProvider
   221  	bcryptCost    int // the algorithm cost / strength for hashing auth passwords
   222  }
   223  
   224  func (as *authStore) AuthEnable() error {
   225  	as.enabledMu.Lock()
   226  	defer as.enabledMu.Unlock()
   227  	if as.enabled {
   228  		as.lg.Info("authentication is already enabled; ignored auth enable request")
   229  		return nil
   230  	}
   231  	b := as.be
   232  	tx := b.BatchTx()
   233  	tx.LockInsideApply()
   234  	defer func() {
   235  		tx.Unlock()
   236  		b.ForceCommit()
   237  	}()
   238  
   239  	u := getUser(as.lg, tx, rootUser)
   240  	if u == nil {
   241  		return ErrRootUserNotExist
   242  	}
   243  
   244  	if !hasRootRole(u) {
   245  		return ErrRootRoleNotExist
   246  	}
   247  
   248  	tx.UnsafePut(buckets.Auth, enableFlagKey, authEnabled)
   249  
   250  	as.enabled = true
   251  	as.tokenProvider.enable()
   252  
   253  	as.refreshRangePermCache(tx)
   254  
   255  	as.setRevision(getRevision(tx))
   256  
   257  	as.lg.Info("enabled authentication")
   258  	return nil
   259  }
   260  
   261  func (as *authStore) AuthDisable() {
   262  	as.enabledMu.Lock()
   263  	defer as.enabledMu.Unlock()
   264  	if !as.enabled {
   265  		return
   266  	}
   267  	b := as.be
   268  	tx := b.BatchTx()
   269  	tx.LockInsideApply()
   270  	tx.UnsafePut(buckets.Auth, enableFlagKey, authDisabled)
   271  	as.commitRevision(tx)
   272  	tx.Unlock()
   273  	b.ForceCommit()
   274  
   275  	as.enabled = false
   276  	as.tokenProvider.disable()
   277  
   278  	as.lg.Info("disabled authentication")
   279  }
   280  
   281  func (as *authStore) Close() error {
   282  	as.enabledMu.Lock()
   283  	defer as.enabledMu.Unlock()
   284  	if !as.enabled {
   285  		return nil
   286  	}
   287  	as.tokenProvider.disable()
   288  	return nil
   289  }
   290  
   291  func (as *authStore) Authenticate(ctx context.Context, username, password string) (*pb.AuthenticateResponse, error) {
   292  	if !as.IsAuthEnabled() {
   293  		return nil, ErrAuthNotEnabled
   294  	}
   295  
   296  	tx := as.be.BatchTx()
   297  	tx.LockInsideApply()
   298  	defer tx.Unlock()
   299  
   300  	user := getUser(as.lg, tx, username)
   301  	if user == nil {
   302  		return nil, ErrAuthFailed
   303  	}
   304  
   305  	if user.Options != nil && user.Options.NoPassword {
   306  		return nil, ErrAuthFailed
   307  	}
   308  
   309  	// Password checking is already performed in the API layer, so we don't need to check for now.
   310  	// Staleness of password can be detected with OCC in the API layer, too.
   311  
   312  	token, err := as.tokenProvider.assign(ctx, username, as.Revision())
   313  	if err != nil {
   314  		return nil, err
   315  	}
   316  
   317  	as.lg.Debug(
   318  		"authenticated a user",
   319  		zap.String("user-name", username),
   320  		zap.String("token", token),
   321  	)
   322  	return &pb.AuthenticateResponse{Token: token}, nil
   323  }
   324  
   325  func (as *authStore) CheckPassword(username, password string) (uint64, error) {
   326  	if !as.IsAuthEnabled() {
   327  		return 0, ErrAuthNotEnabled
   328  	}
   329  
   330  	var user *authpb.User
   331  	// CompareHashAndPassword is very expensive, so we use closures
   332  	// to avoid putting it in the critical section of the tx lock.
   333  	revision, err := func() (uint64, error) {
   334  		tx := as.be.ReadTx()
   335  		tx.Lock()
   336  		defer tx.Unlock()
   337  
   338  		user = getUser(as.lg, tx, username)
   339  		if user == nil {
   340  			return 0, ErrAuthFailed
   341  		}
   342  
   343  		if user.Options != nil && user.Options.NoPassword {
   344  			return 0, ErrNoPasswordUser
   345  		}
   346  
   347  		return getRevision(tx), nil
   348  	}()
   349  	if err != nil {
   350  		return 0, err
   351  	}
   352  
   353  	if bcrypt.CompareHashAndPassword(user.Password, []byte(password)) != nil {
   354  		as.lg.Info("invalid password", zap.String("user-name", username))
   355  		return 0, ErrAuthFailed
   356  	}
   357  	return revision, nil
   358  }
   359  
   360  func (as *authStore) Recover(be backend.Backend) {
   361  	enabled := false
   362  	as.be = be
   363  	tx := be.ReadTx()
   364  	tx.Lock()
   365  	_, vs := tx.UnsafeRange(buckets.Auth, enableFlagKey, nil, 0)
   366  	if len(vs) == 1 {
   367  		if bytes.Equal(vs[0], authEnabled) {
   368  			enabled = true
   369  		}
   370  	}
   371  
   372  	as.setRevision(getRevision(tx))
   373  	as.refreshRangePermCache(tx)
   374  
   375  	tx.Unlock()
   376  
   377  	as.enabledMu.Lock()
   378  	as.enabled = enabled
   379  	if enabled {
   380  		as.tokenProvider.enable()
   381  	}
   382  	as.enabledMu.Unlock()
   383  }
   384  
   385  func (as *authStore) selectPassword(password string, hashedPassword string) ([]byte, error) {
   386  	if password != "" && hashedPassword == "" {
   387  		// This path is for processing log entries created by etcd whose version is older than 3.5
   388  		return bcrypt.GenerateFromPassword([]byte(password), as.bcryptCost)
   389  	}
   390  	return base64.StdEncoding.DecodeString(hashedPassword)
   391  }
   392  
   393  func (as *authStore) UserAdd(r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse, error) {
   394  	if len(r.Name) == 0 {
   395  		return nil, ErrUserEmpty
   396  	}
   397  
   398  	tx := as.be.BatchTx()
   399  	tx.LockInsideApply()
   400  	defer tx.Unlock()
   401  
   402  	user := getUser(as.lg, tx, r.Name)
   403  	if user != nil {
   404  		return nil, ErrUserAlreadyExist
   405  	}
   406  
   407  	options := r.Options
   408  	if options == nil {
   409  		options = &authpb.UserAddOptions{
   410  			NoPassword: false,
   411  		}
   412  	}
   413  
   414  	var password []byte
   415  	var err error
   416  
   417  	if !options.NoPassword {
   418  		password, err = as.selectPassword(r.Password, r.HashedPassword)
   419  		if err != nil {
   420  			return nil, ErrNoPasswordUser
   421  		}
   422  	}
   423  
   424  	newUser := &authpb.User{
   425  		Name:     []byte(r.Name),
   426  		Password: password,
   427  		Options:  options,
   428  	}
   429  
   430  	putUser(as.lg, tx, newUser)
   431  
   432  	as.commitRevision(tx)
   433  	as.refreshRangePermCache(tx)
   434  
   435  	as.lg.Info("added a user", zap.String("user-name", r.Name))
   436  	return &pb.AuthUserAddResponse{}, nil
   437  }
   438  
   439  func (as *authStore) UserDelete(r *pb.AuthUserDeleteRequest) (*pb.AuthUserDeleteResponse, error) {
   440  	if as.enabled && r.Name == rootUser {
   441  		as.lg.Error("cannot delete 'root' user", zap.String("user-name", r.Name))
   442  		return nil, ErrInvalidAuthMgmt
   443  	}
   444  
   445  	tx := as.be.BatchTx()
   446  	tx.LockInsideApply()
   447  	defer tx.Unlock()
   448  
   449  	user := getUser(as.lg, tx, r.Name)
   450  	if user == nil {
   451  		return nil, ErrUserNotFound
   452  	}
   453  
   454  	delUser(tx, r.Name)
   455  
   456  	as.commitRevision(tx)
   457  	as.refreshRangePermCache(tx)
   458  
   459  	as.tokenProvider.invalidateUser(r.Name)
   460  
   461  	as.lg.Info(
   462  		"deleted a user",
   463  		zap.String("user-name", r.Name),
   464  		zap.Strings("user-roles", user.Roles),
   465  	)
   466  	return &pb.AuthUserDeleteResponse{}, nil
   467  }
   468  
   469  func (as *authStore) UserChangePassword(r *pb.AuthUserChangePasswordRequest) (*pb.AuthUserChangePasswordResponse, error) {
   470  	tx := as.be.BatchTx()
   471  	tx.LockInsideApply()
   472  	defer tx.Unlock()
   473  
   474  	user := getUser(as.lg, tx, r.Name)
   475  	if user == nil {
   476  		return nil, ErrUserNotFound
   477  	}
   478  
   479  	var password []byte
   480  	var err error
   481  
   482  	// Backward compatible with old versions of etcd, user options is nil
   483  	if user.Options == nil || !user.Options.NoPassword {
   484  		password, err = as.selectPassword(r.Password, r.HashedPassword)
   485  		if err != nil {
   486  			return nil, ErrNoPasswordUser
   487  		}
   488  	}
   489  
   490  	updatedUser := &authpb.User{
   491  		Name:     []byte(r.Name),
   492  		Roles:    user.Roles,
   493  		Password: password,
   494  		Options:  user.Options,
   495  	}
   496  
   497  	putUser(as.lg, tx, updatedUser)
   498  
   499  	as.commitRevision(tx)
   500  	as.refreshRangePermCache(tx)
   501  
   502  	as.tokenProvider.invalidateUser(r.Name)
   503  
   504  	as.lg.Info(
   505  		"changed a password of a user",
   506  		zap.String("user-name", r.Name),
   507  		zap.Strings("user-roles", user.Roles),
   508  	)
   509  	return &pb.AuthUserChangePasswordResponse{}, nil
   510  }
   511  
   512  func (as *authStore) UserGrantRole(r *pb.AuthUserGrantRoleRequest) (*pb.AuthUserGrantRoleResponse, error) {
   513  	tx := as.be.BatchTx()
   514  	tx.LockInsideApply()
   515  	defer tx.Unlock()
   516  
   517  	user := getUser(as.lg, tx, r.User)
   518  	if user == nil {
   519  		return nil, ErrUserNotFound
   520  	}
   521  
   522  	if r.Role != rootRole {
   523  		role := getRole(as.lg, tx, r.Role)
   524  		if role == nil {
   525  			return nil, ErrRoleNotFound
   526  		}
   527  	}
   528  
   529  	idx := sort.SearchStrings(user.Roles, r.Role)
   530  	if idx < len(user.Roles) && user.Roles[idx] == r.Role {
   531  		as.lg.Warn(
   532  			"ignored grant role request to a user",
   533  			zap.String("user-name", r.User),
   534  			zap.Strings("user-roles", user.Roles),
   535  			zap.String("duplicate-role-name", r.Role),
   536  		)
   537  		return &pb.AuthUserGrantRoleResponse{}, nil
   538  	}
   539  
   540  	user.Roles = append(user.Roles, r.Role)
   541  	sort.Strings(user.Roles)
   542  
   543  	putUser(as.lg, tx, user)
   544  
   545  	as.commitRevision(tx)
   546  	as.refreshRangePermCache(tx)
   547  
   548  	as.lg.Info(
   549  		"granted a role to a user",
   550  		zap.String("user-name", r.User),
   551  		zap.Strings("user-roles", user.Roles),
   552  		zap.String("added-role-name", r.Role),
   553  	)
   554  	return &pb.AuthUserGrantRoleResponse{}, nil
   555  }
   556  
   557  func (as *authStore) UserGet(r *pb.AuthUserGetRequest) (*pb.AuthUserGetResponse, error) {
   558  	tx := as.be.BatchTx()
   559  	tx.LockInsideApply()
   560  	user := getUser(as.lg, tx, r.Name)
   561  	tx.Unlock()
   562  
   563  	if user == nil {
   564  		return nil, ErrUserNotFound
   565  	}
   566  
   567  	var resp pb.AuthUserGetResponse
   568  	resp.Roles = append(resp.Roles, user.Roles...)
   569  	return &resp, nil
   570  }
   571  
   572  func (as *authStore) UserList(r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error) {
   573  	tx := as.be.BatchTx()
   574  	tx.LockInsideApply()
   575  	users := getAllUsers(as.lg, tx)
   576  	tx.Unlock()
   577  
   578  	resp := &pb.AuthUserListResponse{Users: make([]string, len(users))}
   579  	for i := range users {
   580  		resp.Users[i] = string(users[i].Name)
   581  	}
   582  	return resp, nil
   583  }
   584  
   585  func (as *authStore) UserRevokeRole(r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUserRevokeRoleResponse, error) {
   586  	if as.enabled && r.Name == rootUser && r.Role == rootRole {
   587  		as.lg.Error(
   588  			"'root' user cannot revoke 'root' role",
   589  			zap.String("user-name", r.Name),
   590  			zap.String("role-name", r.Role),
   591  		)
   592  		return nil, ErrInvalidAuthMgmt
   593  	}
   594  
   595  	tx := as.be.BatchTx()
   596  	tx.LockInsideApply()
   597  	defer tx.Unlock()
   598  
   599  	user := getUser(as.lg, tx, r.Name)
   600  	if user == nil {
   601  		return nil, ErrUserNotFound
   602  	}
   603  
   604  	updatedUser := &authpb.User{
   605  		Name:     user.Name,
   606  		Password: user.Password,
   607  		Options:  user.Options,
   608  	}
   609  
   610  	for _, role := range user.Roles {
   611  		if role != r.Role {
   612  			updatedUser.Roles = append(updatedUser.Roles, role)
   613  		}
   614  	}
   615  
   616  	if len(updatedUser.Roles) == len(user.Roles) {
   617  		return nil, ErrRoleNotGranted
   618  	}
   619  
   620  	putUser(as.lg, tx, updatedUser)
   621  
   622  	as.commitRevision(tx)
   623  	as.refreshRangePermCache(tx)
   624  
   625  	as.lg.Info(
   626  		"revoked a role from a user",
   627  		zap.String("user-name", r.Name),
   628  		zap.Strings("old-user-roles", user.Roles),
   629  		zap.Strings("new-user-roles", updatedUser.Roles),
   630  		zap.String("revoked-role-name", r.Role),
   631  	)
   632  	return &pb.AuthUserRevokeRoleResponse{}, nil
   633  }
   634  
   635  func (as *authStore) RoleGet(r *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse, error) {
   636  	tx := as.be.BatchTx()
   637  	tx.LockInsideApply()
   638  	defer tx.Unlock()
   639  
   640  	var resp pb.AuthRoleGetResponse
   641  
   642  	role := getRole(as.lg, tx, r.Role)
   643  	if role == nil {
   644  		return nil, ErrRoleNotFound
   645  	}
   646  	resp.Perm = append(resp.Perm, role.KeyPermission...)
   647  	return &resp, nil
   648  }
   649  
   650  func (as *authStore) RoleList(r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error) {
   651  	tx := as.be.BatchTx()
   652  	tx.LockInsideApply()
   653  	roles := getAllRoles(as.lg, tx)
   654  	tx.Unlock()
   655  
   656  	resp := &pb.AuthRoleListResponse{Roles: make([]string, len(roles))}
   657  	for i := range roles {
   658  		resp.Roles[i] = string(roles[i].Name)
   659  	}
   660  	return resp, nil
   661  }
   662  
   663  func (as *authStore) RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error) {
   664  	tx := as.be.BatchTx()
   665  	tx.LockInsideApply()
   666  	defer tx.Unlock()
   667  
   668  	role := getRole(as.lg, tx, r.Role)
   669  	if role == nil {
   670  		return nil, ErrRoleNotFound
   671  	}
   672  
   673  	updatedRole := &authpb.Role{
   674  		Name: role.Name,
   675  	}
   676  
   677  	for _, perm := range role.KeyPermission {
   678  		if !bytes.Equal(perm.Key, r.Key) || !bytes.Equal(perm.RangeEnd, r.RangeEnd) {
   679  			updatedRole.KeyPermission = append(updatedRole.KeyPermission, perm)
   680  		}
   681  	}
   682  
   683  	if len(role.KeyPermission) == len(updatedRole.KeyPermission) {
   684  		return nil, ErrPermissionNotGranted
   685  	}
   686  
   687  	putRole(as.lg, tx, updatedRole)
   688  
   689  	as.commitRevision(tx)
   690  	as.refreshRangePermCache(tx)
   691  
   692  	as.lg.Info(
   693  		"revoked a permission on range",
   694  		zap.String("role-name", r.Role),
   695  		zap.String("key", string(r.Key)),
   696  		zap.String("range-end", string(r.RangeEnd)),
   697  	)
   698  	return &pb.AuthRoleRevokePermissionResponse{}, nil
   699  }
   700  
   701  func (as *authStore) RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error) {
   702  	if as.enabled && r.Role == rootRole {
   703  		as.lg.Error("cannot delete 'root' role", zap.String("role-name", r.Role))
   704  		return nil, ErrInvalidAuthMgmt
   705  	}
   706  
   707  	tx := as.be.BatchTx()
   708  	tx.LockInsideApply()
   709  	defer tx.Unlock()
   710  
   711  	role := getRole(as.lg, tx, r.Role)
   712  	if role == nil {
   713  		return nil, ErrRoleNotFound
   714  	}
   715  
   716  	delRole(tx, r.Role)
   717  
   718  	users := getAllUsers(as.lg, tx)
   719  	for _, user := range users {
   720  		updatedUser := &authpb.User{
   721  			Name:     user.Name,
   722  			Password: user.Password,
   723  			Options:  user.Options,
   724  		}
   725  
   726  		for _, role := range user.Roles {
   727  			if role != r.Role {
   728  				updatedUser.Roles = append(updatedUser.Roles, role)
   729  			}
   730  		}
   731  
   732  		if len(updatedUser.Roles) == len(user.Roles) {
   733  			continue
   734  		}
   735  
   736  		putUser(as.lg, tx, updatedUser)
   737  
   738  	}
   739  
   740  	as.commitRevision(tx)
   741  	as.refreshRangePermCache(tx)
   742  
   743  	as.lg.Info("deleted a role", zap.String("role-name", r.Role))
   744  	return &pb.AuthRoleDeleteResponse{}, nil
   745  }
   746  
   747  func (as *authStore) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error) {
   748  	if len(r.Name) == 0 {
   749  		return nil, ErrRoleEmpty
   750  	}
   751  
   752  	tx := as.be.BatchTx()
   753  	tx.LockInsideApply()
   754  	defer tx.Unlock()
   755  
   756  	role := getRole(as.lg, tx, r.Name)
   757  	if role != nil {
   758  		return nil, ErrRoleAlreadyExist
   759  	}
   760  
   761  	newRole := &authpb.Role{
   762  		Name: []byte(r.Name),
   763  	}
   764  
   765  	putRole(as.lg, tx, newRole)
   766  
   767  	as.commitRevision(tx)
   768  
   769  	as.lg.Info("created a role", zap.String("role-name", r.Name))
   770  	return &pb.AuthRoleAddResponse{}, nil
   771  }
   772  
   773  func (as *authStore) authInfoFromToken(ctx context.Context, token string) (*AuthInfo, bool) {
   774  	return as.tokenProvider.info(ctx, token, as.Revision())
   775  }
   776  
   777  type permSlice []*authpb.Permission
   778  
   779  func (perms permSlice) Len() int {
   780  	return len(perms)
   781  }
   782  
   783  func (perms permSlice) Less(i, j int) bool {
   784  	return bytes.Compare(perms[i].Key, perms[j].Key) < 0
   785  }
   786  
   787  func (perms permSlice) Swap(i, j int) {
   788  	perms[i], perms[j] = perms[j], perms[i]
   789  }
   790  
   791  func (as *authStore) RoleGrantPermission(r *pb.AuthRoleGrantPermissionRequest) (*pb.AuthRoleGrantPermissionResponse, error) {
   792  	if r.Perm == nil {
   793  		return nil, ErrPermissionNotGiven
   794  	}
   795  	if !isValidPermissionRange(r.Perm.Key, r.Perm.RangeEnd) {
   796  		return nil, ErrInvalidAuthMgmt
   797  	}
   798  
   799  	tx := as.be.BatchTx()
   800  	tx.LockInsideApply()
   801  	defer tx.Unlock()
   802  
   803  	role := getRole(as.lg, tx, r.Name)
   804  	if role == nil {
   805  		return nil, ErrRoleNotFound
   806  	}
   807  
   808  	idx := sort.Search(len(role.KeyPermission), func(i int) bool {
   809  		return bytes.Compare(role.KeyPermission[i].Key, r.Perm.Key) >= 0
   810  	})
   811  
   812  	if idx < len(role.KeyPermission) && bytes.Equal(role.KeyPermission[idx].Key, r.Perm.Key) && bytes.Equal(role.KeyPermission[idx].RangeEnd, r.Perm.RangeEnd) {
   813  		// update existing permission
   814  		role.KeyPermission[idx].PermType = r.Perm.PermType
   815  	} else {
   816  		// append new permission to the role
   817  		newPerm := &authpb.Permission{
   818  			Key:      r.Perm.Key,
   819  			RangeEnd: r.Perm.RangeEnd,
   820  			PermType: r.Perm.PermType,
   821  		}
   822  
   823  		role.KeyPermission = append(role.KeyPermission, newPerm)
   824  		sort.Sort(permSlice(role.KeyPermission))
   825  	}
   826  
   827  	putRole(as.lg, tx, role)
   828  
   829  	as.commitRevision(tx)
   830  	as.refreshRangePermCache(tx)
   831  
   832  	as.lg.Info(
   833  		"granted/updated a permission to a user",
   834  		zap.String("user-name", r.Name),
   835  		zap.String("permission-name", authpb.Permission_Type_name[int32(r.Perm.PermType)]),
   836  	)
   837  	return &pb.AuthRoleGrantPermissionResponse{}, nil
   838  }
   839  
   840  func (as *authStore) isOpPermitted(userName string, revision uint64, key, rangeEnd []byte, permTyp authpb.Permission_Type) error {
   841  	// TODO(mitake): this function would be costly so we need a caching mechanism
   842  	if !as.IsAuthEnabled() {
   843  		return nil
   844  	}
   845  
   846  	// only gets rev == 0 when passed AuthInfo{}; no user given
   847  	if revision == 0 {
   848  		return ErrUserEmpty
   849  	}
   850  	rev := as.Revision()
   851  	if revision < rev {
   852  		as.lg.Warn("request auth revision is less than current node auth revision",
   853  			zap.Uint64("current node auth revision", rev),
   854  			zap.Uint64("request auth revision", revision),
   855  			zap.ByteString("request key", key),
   856  			zap.Error(ErrAuthOldRevision))
   857  		return ErrAuthOldRevision
   858  	}
   859  
   860  	tx := as.be.ReadTx()
   861  	tx.Lock()
   862  	defer tx.Unlock()
   863  
   864  	user := getUser(as.lg, tx, userName)
   865  	if user == nil {
   866  		as.lg.Error("cannot find a user for permission check", zap.String("user-name", userName))
   867  		return ErrPermissionDenied
   868  	}
   869  
   870  	// root role should have permission on all ranges
   871  	if hasRootRole(user) {
   872  		return nil
   873  	}
   874  
   875  	if as.isRangeOpPermitted(userName, key, rangeEnd, permTyp) {
   876  		return nil
   877  	}
   878  
   879  	return ErrPermissionDenied
   880  }
   881  
   882  func (as *authStore) IsPutPermitted(authInfo *AuthInfo, key []byte) error {
   883  	return as.isOpPermitted(authInfo.Username, authInfo.Revision, key, nil, authpb.WRITE)
   884  }
   885  
   886  func (as *authStore) IsRangePermitted(authInfo *AuthInfo, key, rangeEnd []byte) error {
   887  	return as.isOpPermitted(authInfo.Username, authInfo.Revision, key, rangeEnd, authpb.READ)
   888  }
   889  
   890  func (as *authStore) IsDeleteRangePermitted(authInfo *AuthInfo, key, rangeEnd []byte) error {
   891  	return as.isOpPermitted(authInfo.Username, authInfo.Revision, key, rangeEnd, authpb.WRITE)
   892  }
   893  
   894  func (as *authStore) IsAdminPermitted(authInfo *AuthInfo) error {
   895  	if !as.IsAuthEnabled() {
   896  		return nil
   897  	}
   898  	if authInfo == nil || authInfo.Username == "" {
   899  		return ErrUserEmpty
   900  	}
   901  
   902  	tx := as.be.ReadTx()
   903  	tx.Lock()
   904  	u := getUser(as.lg, tx, authInfo.Username)
   905  	tx.Unlock()
   906  
   907  	if u == nil {
   908  		return ErrUserNotFound
   909  	}
   910  
   911  	if !hasRootRole(u) {
   912  		return ErrPermissionDenied
   913  	}
   914  
   915  	return nil
   916  }
   917  
   918  func getUser(lg *zap.Logger, tx backend.ReadTx, username string) *authpb.User {
   919  	_, vs := tx.UnsafeRange(buckets.AuthUsers, []byte(username), nil, 0)
   920  	if len(vs) == 0 {
   921  		return nil
   922  	}
   923  
   924  	user := &authpb.User{}
   925  	err := user.Unmarshal(vs[0])
   926  	if err != nil {
   927  		lg.Panic(
   928  			"failed to unmarshal 'authpb.User'",
   929  			zap.String("user-name", username),
   930  			zap.Error(err),
   931  		)
   932  	}
   933  	return user
   934  }
   935  
   936  func getAllUsers(lg *zap.Logger, tx backend.ReadTx) []*authpb.User {
   937  	var vs [][]byte
   938  	err := tx.UnsafeForEach(buckets.AuthUsers, func(k []byte, v []byte) error {
   939  		vs = append(vs, v)
   940  		return nil
   941  	})
   942  	if err != nil {
   943  		lg.Panic("failed to get users",
   944  			zap.Error(err))
   945  	}
   946  	if len(vs) == 0 {
   947  		return nil
   948  	}
   949  
   950  	users := make([]*authpb.User, len(vs))
   951  	for i := range vs {
   952  		user := &authpb.User{}
   953  		err := user.Unmarshal(vs[i])
   954  		if err != nil {
   955  			lg.Panic("failed to unmarshal 'authpb.User'", zap.Error(err))
   956  		}
   957  		users[i] = user
   958  	}
   959  	return users
   960  }
   961  
   962  func putUser(lg *zap.Logger, tx backend.BatchTx, user *authpb.User) {
   963  	b, err := user.Marshal()
   964  	if err != nil {
   965  		lg.Panic("failed to unmarshal 'authpb.User'", zap.Error(err))
   966  	}
   967  	tx.UnsafePut(buckets.AuthUsers, user.Name, b)
   968  }
   969  
   970  func delUser(tx backend.BatchTx, username string) {
   971  	tx.UnsafeDelete(buckets.AuthUsers, []byte(username))
   972  }
   973  
   974  func getRole(lg *zap.Logger, tx backend.ReadTx, rolename string) *authpb.Role {
   975  	_, vs := tx.UnsafeRange(buckets.AuthRoles, []byte(rolename), nil, 0)
   976  	if len(vs) == 0 {
   977  		return nil
   978  	}
   979  
   980  	role := &authpb.Role{}
   981  	err := role.Unmarshal(vs[0])
   982  	if err != nil {
   983  		lg.Panic("failed to unmarshal 'authpb.Role'", zap.Error(err))
   984  	}
   985  	return role
   986  }
   987  
   988  func getAllRoles(lg *zap.Logger, tx backend.ReadTx) []*authpb.Role {
   989  	_, vs := tx.UnsafeRange(buckets.AuthRoles, []byte{0}, []byte{0xff}, -1)
   990  	if len(vs) == 0 {
   991  		return nil
   992  	}
   993  
   994  	roles := make([]*authpb.Role, len(vs))
   995  	for i := range vs {
   996  		role := &authpb.Role{}
   997  		err := role.Unmarshal(vs[i])
   998  		if err != nil {
   999  			lg.Panic("failed to unmarshal 'authpb.Role'", zap.Error(err))
  1000  		}
  1001  		roles[i] = role
  1002  	}
  1003  	return roles
  1004  }
  1005  
  1006  func putRole(lg *zap.Logger, tx backend.BatchTx, role *authpb.Role) {
  1007  	b, err := role.Marshal()
  1008  	if err != nil {
  1009  		lg.Panic(
  1010  			"failed to marshal 'authpb.Role'",
  1011  			zap.String("role-name", string(role.Name)),
  1012  			zap.Error(err),
  1013  		)
  1014  	}
  1015  
  1016  	tx.UnsafePut(buckets.AuthRoles, role.Name, b)
  1017  }
  1018  
  1019  func delRole(tx backend.BatchTx, rolename string) {
  1020  	tx.UnsafeDelete(buckets.AuthRoles, []byte(rolename))
  1021  }
  1022  
  1023  func (as *authStore) IsAuthEnabled() bool {
  1024  	as.enabledMu.RLock()
  1025  	defer as.enabledMu.RUnlock()
  1026  	return as.enabled
  1027  }
  1028  
  1029  // NewAuthStore creates a new AuthStore.
  1030  func NewAuthStore(lg *zap.Logger, be backend.Backend, tp TokenProvider, bcryptCost int) *authStore {
  1031  	if lg == nil {
  1032  		lg = zap.NewNop()
  1033  	}
  1034  
  1035  	if bcryptCost < bcrypt.MinCost || bcryptCost > bcrypt.MaxCost {
  1036  		lg.Warn(
  1037  			"use default bcrypt cost instead of the invalid given cost",
  1038  			zap.Int("min-cost", bcrypt.MinCost),
  1039  			zap.Int("max-cost", bcrypt.MaxCost),
  1040  			zap.Int("default-cost", bcrypt.DefaultCost),
  1041  			zap.Int("given-cost", bcryptCost),
  1042  		)
  1043  		bcryptCost = bcrypt.DefaultCost
  1044  	}
  1045  
  1046  	tx := be.BatchTx()
  1047  	tx.LockOutsideApply()
  1048  
  1049  	tx.UnsafeCreateBucket(buckets.Auth)
  1050  	tx.UnsafeCreateBucket(buckets.AuthUsers)
  1051  	tx.UnsafeCreateBucket(buckets.AuthRoles)
  1052  
  1053  	enabled := false
  1054  	_, vs := tx.UnsafeRange(buckets.Auth, enableFlagKey, nil, 0)
  1055  	if len(vs) == 1 {
  1056  		if bytes.Equal(vs[0], authEnabled) {
  1057  			enabled = true
  1058  		}
  1059  	}
  1060  
  1061  	as := &authStore{
  1062  		revision:       getRevision(tx),
  1063  		lg:             lg,
  1064  		be:             be,
  1065  		enabled:        enabled,
  1066  		rangePermCache: make(map[string]*unifiedRangePermissions),
  1067  		tokenProvider:  tp,
  1068  		bcryptCost:     bcryptCost,
  1069  	}
  1070  
  1071  	if enabled {
  1072  		as.tokenProvider.enable()
  1073  	}
  1074  
  1075  	if as.Revision() == 0 {
  1076  		as.commitRevision(tx)
  1077  	}
  1078  
  1079  	as.setupMetricsReporter()
  1080  
  1081  	as.refreshRangePermCache(tx)
  1082  
  1083  	tx.Unlock()
  1084  	be.ForceCommit()
  1085  
  1086  	return as
  1087  }
  1088  
  1089  func hasRootRole(u *authpb.User) bool {
  1090  	// u.Roles is sorted in UserGrantRole(), so we can use binary search.
  1091  	idx := sort.SearchStrings(u.Roles, rootRole)
  1092  	return idx != len(u.Roles) && u.Roles[idx] == rootRole
  1093  }
  1094  
  1095  func (as *authStore) commitRevision(tx backend.BatchTx) {
  1096  	atomic.AddUint64(&as.revision, 1)
  1097  	revBytes := make([]byte, revBytesLen)
  1098  	binary.BigEndian.PutUint64(revBytes, as.Revision())
  1099  	tx.UnsafePut(buckets.Auth, revisionKey, revBytes)
  1100  }
  1101  
  1102  func getRevision(tx backend.ReadTx) uint64 {
  1103  	_, vs := tx.UnsafeRange(buckets.Auth, revisionKey, nil, 0)
  1104  	if len(vs) != 1 {
  1105  		// this can happen in the initialization phase
  1106  		return 0
  1107  	}
  1108  	return binary.BigEndian.Uint64(vs[0])
  1109  }
  1110  
  1111  func (as *authStore) setRevision(rev uint64) {
  1112  	atomic.StoreUint64(&as.revision, rev)
  1113  }
  1114  
  1115  func (as *authStore) Revision() uint64 {
  1116  	return atomic.LoadUint64(&as.revision)
  1117  }
  1118  
  1119  func (as *authStore) AuthInfoFromTLS(ctx context.Context) (ai *AuthInfo) {
  1120  	peer, ok := peer.FromContext(ctx)
  1121  	if !ok || peer == nil || peer.AuthInfo == nil {
  1122  		return nil
  1123  	}
  1124  
  1125  	tlsInfo := peer.AuthInfo.(credentials.TLSInfo)
  1126  	for _, chains := range tlsInfo.State.VerifiedChains {
  1127  		if len(chains) < 1 {
  1128  			continue
  1129  		}
  1130  		ai = &AuthInfo{
  1131  			Username: chains[0].Subject.CommonName,
  1132  			Revision: as.Revision(),
  1133  		}
  1134  		md, ok := metadata.FromIncomingContext(ctx)
  1135  		if !ok {
  1136  			return nil
  1137  		}
  1138  
  1139  		// gRPC-gateway proxy request to etcd server includes Grpcgateway-Accept
  1140  		// header. The proxy uses etcd client server certificate. If the certificate
  1141  		// has a CommonName we should never use this for authentication.
  1142  		if gw := md["grpcgateway-accept"]; len(gw) > 0 {
  1143  			as.lg.Warn(
  1144  				"ignoring common name in gRPC-gateway proxy request",
  1145  				zap.String("common-name", ai.Username),
  1146  				zap.String("user-name", ai.Username),
  1147  				zap.Uint64("revision", ai.Revision),
  1148  			)
  1149  			return nil
  1150  		}
  1151  		as.lg.Debug(
  1152  			"found command name",
  1153  			zap.String("common-name", ai.Username),
  1154  			zap.String("user-name", ai.Username),
  1155  			zap.Uint64("revision", ai.Revision),
  1156  		)
  1157  		break
  1158  	}
  1159  	return ai
  1160  }
  1161  
  1162  func (as *authStore) AuthInfoFromCtx(ctx context.Context) (*AuthInfo, error) {
  1163  	if !as.IsAuthEnabled() {
  1164  		return nil, nil
  1165  	}
  1166  	md, ok := metadata.FromIncomingContext(ctx)
  1167  	if !ok {
  1168  		return nil, nil
  1169  	}
  1170  
  1171  	//TODO(mitake|hexfusion) review unifying key names
  1172  	ts, ok := md[rpctypes.TokenFieldNameGRPC]
  1173  	if !ok {
  1174  		ts, ok = md[rpctypes.TokenFieldNameSwagger]
  1175  	}
  1176  	if !ok {
  1177  		return nil, nil
  1178  	}
  1179  
  1180  	token := ts[0]
  1181  	authInfo, uok := as.authInfoFromToken(ctx, token)
  1182  	if !uok {
  1183  		as.lg.Warn("invalid auth token", zap.String("token", token))
  1184  		return nil, ErrInvalidAuthToken
  1185  	}
  1186  
  1187  	return authInfo, nil
  1188  }
  1189  
  1190  func (as *authStore) GenTokenPrefix() (string, error) {
  1191  	return as.tokenProvider.genTokenPrefix()
  1192  }
  1193  
  1194  func decomposeOpts(lg *zap.Logger, optstr string) (string, map[string]string, error) {
  1195  	opts := strings.Split(optstr, ",")
  1196  	tokenType := opts[0]
  1197  
  1198  	typeSpecificOpts := make(map[string]string)
  1199  	for i := 1; i < len(opts); i++ {
  1200  		pair := strings.Split(opts[i], "=")
  1201  
  1202  		if len(pair) != 2 {
  1203  			if lg != nil {
  1204  				lg.Error("invalid token option", zap.String("option", optstr))
  1205  			}
  1206  			return "", nil, ErrInvalidAuthOpts
  1207  		}
  1208  
  1209  		if _, ok := typeSpecificOpts[pair[0]]; ok {
  1210  			if lg != nil {
  1211  				lg.Error(
  1212  					"invalid token option",
  1213  					zap.String("option", optstr),
  1214  					zap.String("duplicate-parameter", pair[0]),
  1215  				)
  1216  			}
  1217  			return "", nil, ErrInvalidAuthOpts
  1218  		}
  1219  
  1220  		typeSpecificOpts[pair[0]] = pair[1]
  1221  	}
  1222  
  1223  	return tokenType, typeSpecificOpts, nil
  1224  
  1225  }
  1226  
  1227  // NewTokenProvider creates a new token provider.
  1228  func NewTokenProvider(
  1229  	lg *zap.Logger,
  1230  	tokenOpts string,
  1231  	indexWaiter func(uint64) <-chan struct{},
  1232  	TokenTTL time.Duration) (TokenProvider, error) {
  1233  	tokenType, typeSpecificOpts, err := decomposeOpts(lg, tokenOpts)
  1234  	if err != nil {
  1235  		return nil, ErrInvalidAuthOpts
  1236  	}
  1237  
  1238  	switch tokenType {
  1239  	case tokenTypeSimple:
  1240  		if lg != nil {
  1241  			lg.Warn("simple token is not cryptographically signed")
  1242  		}
  1243  		return newTokenProviderSimple(lg, indexWaiter, TokenTTL), nil
  1244  
  1245  	case tokenTypeJWT:
  1246  		return newTokenProviderJWT(lg, typeSpecificOpts)
  1247  
  1248  	case "":
  1249  		return newTokenProviderNop()
  1250  
  1251  	default:
  1252  		if lg != nil {
  1253  			lg.Warn(
  1254  				"unknown token type",
  1255  				zap.String("type", tokenType),
  1256  				zap.Error(ErrInvalidAuthOpts),
  1257  			)
  1258  		}
  1259  		return nil, ErrInvalidAuthOpts
  1260  	}
  1261  }
  1262  
  1263  func (as *authStore) WithRoot(ctx context.Context) context.Context {
  1264  	if !as.IsAuthEnabled() {
  1265  		return ctx
  1266  	}
  1267  
  1268  	var ctxForAssign context.Context
  1269  	if ts, ok := as.tokenProvider.(*tokenSimple); ok && ts != nil {
  1270  		ctx1 := context.WithValue(ctx, AuthenticateParamIndex{}, uint64(0))
  1271  		prefix, err := ts.genTokenPrefix()
  1272  		if err != nil {
  1273  			as.lg.Error(
  1274  				"failed to generate prefix of internally used token",
  1275  				zap.Error(err),
  1276  			)
  1277  			return ctx
  1278  		}
  1279  		ctxForAssign = context.WithValue(ctx1, AuthenticateParamSimpleTokenPrefix{}, prefix)
  1280  	} else {
  1281  		ctxForAssign = ctx
  1282  	}
  1283  
  1284  	token, err := as.tokenProvider.assign(ctxForAssign, "root", as.Revision())
  1285  	if err != nil {
  1286  		// this must not happen
  1287  		as.lg.Error(
  1288  			"failed to assign token for lease revoking",
  1289  			zap.Error(err),
  1290  		)
  1291  		return ctx
  1292  	}
  1293  
  1294  	mdMap := map[string]string{
  1295  		rpctypes.TokenFieldNameGRPC: token,
  1296  	}
  1297  	tokenMD := metadata.New(mdMap)
  1298  
  1299  	// use "mdIncomingKey{}" since it's called from local etcdserver
  1300  	return metadata.NewIncomingContext(ctx, tokenMD)
  1301  }
  1302  
  1303  func (as *authStore) HasRole(user, role string) bool {
  1304  	tx := as.be.BatchTx()
  1305  	tx.LockInsideApply()
  1306  	u := getUser(as.lg, tx, user)
  1307  	tx.Unlock()
  1308  
  1309  	if u == nil {
  1310  		as.lg.Warn(
  1311  			"'has-role' requested for non-existing user",
  1312  			zap.String("user-name", user),
  1313  			zap.String("role-name", role),
  1314  		)
  1315  		return false
  1316  	}
  1317  
  1318  	for _, r := range u.Roles {
  1319  		if role == r {
  1320  			return true
  1321  		}
  1322  	}
  1323  	return false
  1324  }
  1325  
  1326  func (as *authStore) BcryptCost() int {
  1327  	return as.bcryptCost
  1328  }
  1329  
  1330  func (as *authStore) setupMetricsReporter() {
  1331  	reportCurrentAuthRevMu.Lock()
  1332  	reportCurrentAuthRev = func() float64 {
  1333  		return float64(as.Revision())
  1334  	}
  1335  	reportCurrentAuthRevMu.Unlock()
  1336  }
  1337  

View as plain text