mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Merge pull request #12078 from cfc4n/automated-cherry-pick-of-#11980-upstream-release-3.3
Automated cherry pick of #11980
This commit is contained in:
@@ -35,7 +35,7 @@ const (
|
||||
|
||||
// var for testing purposes
|
||||
var (
|
||||
simpleTokenTTL = 5 * time.Minute
|
||||
simpleTokenTTLDefault = 300 * time.Second
|
||||
simpleTokenTTLResolution = 1 * time.Second
|
||||
)
|
||||
|
||||
@@ -45,6 +45,7 @@ type simpleTokenTTLKeeper struct {
|
||||
stopc chan struct{}
|
||||
deleteTokenFunc func(string)
|
||||
mu *sync.Mutex
|
||||
simpleTokenTTL time.Duration
|
||||
}
|
||||
|
||||
func (tm *simpleTokenTTLKeeper) stop() {
|
||||
@@ -56,12 +57,12 @@ func (tm *simpleTokenTTLKeeper) stop() {
|
||||
}
|
||||
|
||||
func (tm *simpleTokenTTLKeeper) addSimpleToken(token string) {
|
||||
tm.tokens[token] = time.Now().Add(simpleTokenTTL)
|
||||
tm.tokens[token] = time.Now().Add(tm.simpleTokenTTL)
|
||||
}
|
||||
|
||||
func (tm *simpleTokenTTLKeeper) resetSimpleToken(token string) {
|
||||
if _, ok := tm.tokens[token]; ok {
|
||||
tm.tokens[token] = time.Now().Add(simpleTokenTTL)
|
||||
tm.tokens[token] = time.Now().Add(tm.simpleTokenTTL)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +99,7 @@ type tokenSimple struct {
|
||||
simpleTokenKeeper *simpleTokenTTLKeeper
|
||||
simpleTokensMu sync.Mutex
|
||||
simpleTokens map[string]string // token -> username
|
||||
simpleTokenTTL time.Duration
|
||||
}
|
||||
|
||||
func (t *tokenSimple) genTokenPrefix() (string, error) {
|
||||
@@ -146,6 +148,10 @@ func (t *tokenSimple) invalidateUser(username string) {
|
||||
}
|
||||
|
||||
func (t *tokenSimple) enable() {
|
||||
if t.simpleTokenTTL <= 0 {
|
||||
t.simpleTokenTTL = simpleTokenTTLDefault
|
||||
}
|
||||
|
||||
delf := func(tk string) {
|
||||
if username, ok := t.simpleTokens[tk]; ok {
|
||||
plog.Infof("deleting token %s for user %s", tk, username)
|
||||
@@ -158,6 +164,7 @@ func (t *tokenSimple) enable() {
|
||||
stopc: make(chan struct{}),
|
||||
deleteTokenFunc: delf,
|
||||
mu: &t.simpleTokensMu,
|
||||
simpleTokenTTL: t.simpleTokenTTL,
|
||||
}
|
||||
go t.simpleTokenKeeper.run()
|
||||
}
|
||||
@@ -215,9 +222,10 @@ func (t *tokenSimple) isValidSimpleToken(ctx context.Context, token string) bool
|
||||
return false
|
||||
}
|
||||
|
||||
func newTokenProviderSimple(indexWaiter func(uint64) <-chan struct{}) *tokenSimple {
|
||||
func newTokenProviderSimple(indexWaiter func(uint64) <-chan struct{}, TokenTTL time.Duration) *tokenSimple {
|
||||
return &tokenSimple{
|
||||
simpleTokens: make(map[string]string),
|
||||
indexWaiter: indexWaiter,
|
||||
simpleTokens: make(map[string]string),
|
||||
indexWaiter: indexWaiter,
|
||||
simpleTokenTTL: TokenTTL,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ import (
|
||||
// TestSimpleTokenDisabled ensures that TokenProviderSimple behaves correctly when
|
||||
// disabled.
|
||||
func TestSimpleTokenDisabled(t *testing.T) {
|
||||
initialState := newTokenProviderSimple(dummyIndexWaiter)
|
||||
initialState := newTokenProviderSimple(dummyIndexWaiter, simpleTokenTTLDefault)
|
||||
|
||||
explicitlyDisabled := newTokenProviderSimple(dummyIndexWaiter)
|
||||
explicitlyDisabled := newTokenProviderSimple(dummyIndexWaiter, simpleTokenTTLDefault)
|
||||
explicitlyDisabled.enable()
|
||||
explicitlyDisabled.disable()
|
||||
|
||||
@@ -46,7 +46,7 @@ func TestSimpleTokenDisabled(t *testing.T) {
|
||||
// TestSimpleTokenAssign ensures that TokenProviderSimple can correctly assign a
|
||||
// token, look it up with info, and invalidate it by user.
|
||||
func TestSimpleTokenAssign(t *testing.T) {
|
||||
tp := newTokenProviderSimple(dummyIndexWaiter)
|
||||
tp := newTokenProviderSimple(dummyIndexWaiter, simpleTokenTTLDefault)
|
||||
tp.enable()
|
||||
ctx := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, "dummy")
|
||||
token, err := tp.assign(ctx, "user1", 0)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/auth/authpb"
|
||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||
@@ -1087,7 +1088,11 @@ func decomposeOpts(optstr string) (string, map[string]string, error) {
|
||||
|
||||
}
|
||||
|
||||
func NewTokenProvider(tokenOpts string, indexWaiter func(uint64) <-chan struct{}) (TokenProvider, error) {
|
||||
// NewTokenProvider creates a new token provider.
|
||||
func NewTokenProvider(
|
||||
tokenOpts string,
|
||||
indexWaiter func(uint64) <-chan struct{},
|
||||
TokenTTL time.Duration) (TokenProvider, error) {
|
||||
tokenType, typeSpecificOpts, err := decomposeOpts(tokenOpts)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidAuthOpts
|
||||
@@ -1096,7 +1101,7 @@ func NewTokenProvider(tokenOpts string, indexWaiter func(uint64) <-chan struct{}
|
||||
switch tokenType {
|
||||
case tokenTypeSimple:
|
||||
plog.Warningf("simple token is not cryptographically signed")
|
||||
return newTokenProviderSimple(indexWaiter), nil
|
||||
return newTokenProviderSimple(indexWaiter, TokenTTL), nil
|
||||
|
||||
case tokenTypeJWT:
|
||||
return newTokenProviderJWT(typeSpecificOpts)
|
||||
|
||||
@@ -17,6 +17,7 @@ package auth
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -48,7 +49,7 @@ func TestNewAuthStoreRevision(t *testing.T) {
|
||||
b, tPath := backend.NewDefaultTmpBackend()
|
||||
defer os.Remove(tPath)
|
||||
|
||||
tp, err := NewTokenProvider(tokenTypeSimple, dummyIndexWaiter)
|
||||
tp, err := NewTokenProvider(tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -73,10 +74,32 @@ func TestNewAuthStoreRevision(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewAuthStoreBryptCost ensures that NewAuthStore uses default when given bcrypt-cost is invalid
|
||||
func TestNewAuthStoreBcryptCost(t *testing.T) {
|
||||
b, tPath := backend.NewDefaultTmpBackend()
|
||||
defer os.Remove(tPath)
|
||||
|
||||
tp, err := NewTokenProvider(tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
invalidCosts := [2]int{bcrypt.MinCost - 1, bcrypt.MaxCost + 1}
|
||||
for _, invalidCost := range invalidCosts {
|
||||
as := NewAuthStore(b, nil, tp, invalidCost)
|
||||
if as.BcryptCost() != bcrypt.DefaultCost {
|
||||
t.Fatalf("expected DefaultCost when bcryptcost is invalid")
|
||||
}
|
||||
as.Close()
|
||||
}
|
||||
|
||||
b.Close()
|
||||
}
|
||||
|
||||
func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testing.T)) {
|
||||
b, tPath := backend.NewDefaultTmpBackend()
|
||||
|
||||
tp, err := NewTokenProvider(tokenTypeSimple, dummyIndexWaiter)
|
||||
tp, err := NewTokenProvider(tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -513,7 +536,7 @@ func TestAuthInfoFromCtxRace(t *testing.T) {
|
||||
b, tPath := backend.NewDefaultTmpBackend()
|
||||
defer os.Remove(tPath)
|
||||
|
||||
tp, err := NewTokenProvider(tokenTypeSimple, dummyIndexWaiter)
|
||||
tp, err := NewTokenProvider(tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -585,7 +608,11 @@ func TestRecoverFromSnapshot(t *testing.T) {
|
||||
|
||||
as.Close()
|
||||
|
||||
<<<<<<< HEAD
|
||||
tp, err := NewTokenProvider(tokenTypeSimple, dummyIndexWaiter)
|
||||
=======
|
||||
tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
|
||||
>>>>>>> auth: Customize simpleTokenTTL settings.
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -618,13 +645,13 @@ func contains(array []string, str string) bool {
|
||||
|
||||
func TestHammerSimpleAuthenticate(t *testing.T) {
|
||||
// set TTL values low to try to trigger races
|
||||
oldTTL, oldTTLRes := simpleTokenTTL, simpleTokenTTLResolution
|
||||
oldTTL, oldTTLRes := simpleTokenTTLDefault, simpleTokenTTLResolution
|
||||
defer func() {
|
||||
simpleTokenTTL = oldTTL
|
||||
simpleTokenTTLDefault = oldTTL
|
||||
simpleTokenTTLResolution = oldTTLRes
|
||||
}()
|
||||
simpleTokenTTL = 10 * time.Millisecond
|
||||
simpleTokenTTLResolution = simpleTokenTTL
|
||||
simpleTokenTTLDefault = 10 * time.Millisecond
|
||||
simpleTokenTTLResolution = simpleTokenTTLDefault
|
||||
users := make(map[string]struct{})
|
||||
|
||||
as, tearDown := setupAuthStore(t)
|
||||
@@ -667,7 +694,7 @@ func TestRolesOrder(t *testing.T) {
|
||||
b, tPath := backend.NewDefaultTmpBackend()
|
||||
defer os.Remove(tPath)
|
||||
|
||||
tp, err := NewTokenProvider(tokenTypeSimple, dummyIndexWaiter)
|
||||
tp, err := NewTokenProvider(tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -722,7 +749,7 @@ func testAuthInfoFromCtxWithRoot(t *testing.T, opts string) {
|
||||
b, tPath := backend.NewDefaultTmpBackend()
|
||||
defer os.Remove(tPath)
|
||||
|
||||
tp, err := NewTokenProvider(opts, dummyIndexWaiter)
|
||||
tp, err := NewTokenProvider(opts, dummyIndexWaiter, simpleTokenTTLDefault)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -222,6 +222,9 @@ type Config struct {
|
||||
|
||||
// Experimental flags
|
||||
|
||||
//The AuthTokenTTL in seconds of the simple token
|
||||
AuthTokenTTL uint `json:"auth-token-ttl"`
|
||||
|
||||
ExperimentalInitialCorruptCheck bool `json:"experimental-initial-corrupt-check"`
|
||||
ExperimentalCorruptCheckTime time.Duration `json:"experimental-corrupt-check-time"`
|
||||
ExperimentalEnableV2V3 string `json:"experimental-enable-v2v3"`
|
||||
@@ -284,6 +287,7 @@ func NewConfig() *Config {
|
||||
Metrics: "basic",
|
||||
EnableV2: DefaultEnableV2,
|
||||
AuthToken: "simple",
|
||||
AuthTokenTTL: 300,
|
||||
}
|
||||
cfg.InitialCluster = cfg.InitialClusterFromName(cfg.Name)
|
||||
return cfg
|
||||
|
||||
@@ -171,6 +171,7 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) {
|
||||
StrictReconfigCheck: cfg.StrictReconfigCheck,
|
||||
ClientCertAuthEnabled: cfg.ClientTLSInfo.ClientCertAuth,
|
||||
AuthToken: cfg.AuthToken,
|
||||
TokenTTL: cfg.AuthTokenTTL,
|
||||
InitialCorruptCheck: cfg.ExperimentalInitialCorruptCheck,
|
||||
CorruptCheckTime: cfg.ExperimentalCorruptCheckTime,
|
||||
Debug: cfg.Debug,
|
||||
|
||||
@@ -215,6 +215,7 @@ func newConfig() *config {
|
||||
|
||||
// auth
|
||||
fs.StringVar(&cfg.ec.AuthToken, "auth-token", cfg.ec.AuthToken, "Specify auth token specific options.")
|
||||
fs.UintVar(&cfg.ec.AuthTokenTTL, "auth-token-ttl", cfg.ec.AuthTokenTTL, "The lifetime in seconds of the auth token.")
|
||||
|
||||
// experimental
|
||||
fs.BoolVar(&cfg.ec.ExperimentalInitialCorruptCheck, "experimental-initial-corrupt-check", cfg.ec.ExperimentalInitialCorruptCheck, "Enable to check data corruption before serving any client/peer traffic.")
|
||||
|
||||
@@ -193,6 +193,8 @@ profiling flags:
|
||||
auth flags:
|
||||
--auth-token 'simple'
|
||||
Specify a v3 authentication token type and its options ('simple' or 'jwt').
|
||||
--auth-token-ttl 300
|
||||
Time (in seconds) of the auth-token-ttl.
|
||||
|
||||
experimental flags:
|
||||
--experimental-initial-corrupt-check 'false'
|
||||
|
||||
@@ -95,6 +95,7 @@ type ServerConfig struct {
|
||||
ClientCertAuthEnabled bool
|
||||
|
||||
AuthToken string
|
||||
TokenTTL uint
|
||||
|
||||
// InitialCorruptCheck is true to check data corruption on boot
|
||||
// before serving any peer/client traffic.
|
||||
|
||||
@@ -461,6 +461,7 @@ func NewServer(cfg ServerConfig) (srv *EtcdServer, err error) {
|
||||
func(index uint64) <-chan struct{} {
|
||||
return srv.applyWait.Wait(index)
|
||||
},
|
||||
time.Duration(cfg.TokenTTL)*time.Second,
|
||||
)
|
||||
if err != nil {
|
||||
plog.Warningf("failed to create token provider,err is %v", err)
|
||||
|
||||
Reference in New Issue
Block a user