auth: protect simpleToken with single mutex and check if enabled

Dual locking doesn't really give a convincing performance improvement and
the lock ordering makes it impossible to safely check if the TTL keeper
is enabled or not.

Fixes #7722
This commit is contained in:
Anthony Romano 2017-04-12 13:35:00 -07:00 committed by Gyu-Ho Lee
parent 288bccd288
commit 9be7fc5320
2 changed files with 22 additions and 24 deletions

View File

@ -37,20 +37,10 @@ var (
)
type simpleTokenTTLKeeper struct {
tokensMu sync.Mutex
tokens map[string]time.Time
stopCh chan chan struct{}
deleteTokenFunc func(string)
}
func NewSimpleTokenTTLKeeper(deletefunc func(string)) *simpleTokenTTLKeeper {
stk := &simpleTokenTTLKeeper{
tokens: make(map[string]time.Time),
stopCh: make(chan chan struct{}),
deleteTokenFunc: deletefunc,
}
go stk.run()
return stk
mu *sync.Mutex
}
func (tm *simpleTokenTTLKeeper) stop() {
@ -81,14 +71,14 @@ func (tm *simpleTokenTTLKeeper) run() {
select {
case <-tokenTicker.C:
nowtime := time.Now()
tm.tokensMu.Lock()
tm.mu.Lock()
for t, tokenendtime := range tm.tokens {
if nowtime.After(tokenendtime) {
tm.deleteTokenFunc(t)
delete(tm.tokens, t)
}
}
tm.tokensMu.Unlock()
tm.mu.Unlock()
case waitCh := <-tm.stopCh:
tm.tokens = make(map[string]time.Time)
waitCh <- struct{}{}
@ -97,6 +87,22 @@ func (tm *simpleTokenTTLKeeper) run() {
}
}
func (as *authStore) enable() {
delf := func(tk string) {
if username, ok := as.simpleTokens[tk]; ok {
plog.Infof("deleting token %s for user %s", tk, username)
delete(as.simpleTokens, tk)
}
}
as.simpleTokenKeeper = &simpleTokenTTLKeeper{
tokens: make(map[string]time.Time),
stopCh: make(chan chan struct{}),
deleteTokenFunc: delf,
mu: &as.simpleTokensMu,
}
go as.simpleTokenKeeper.run()
}
func (as *authStore) GenSimpleToken() (string, error) {
ret := make([]byte, defaultSimpleTokenLength)
@ -113,9 +119,7 @@ func (as *authStore) GenSimpleToken() (string, error) {
}
func (as *authStore) assignSimpleTokenToUser(username, token string) {
as.simpleTokenKeeper.tokensMu.Lock()
as.simpleTokensMu.Lock()
_, ok := as.simpleTokens[token]
if ok {
plog.Panicf("token %s is alredy used", token)
@ -124,14 +128,12 @@ func (as *authStore) assignSimpleTokenToUser(username, token string) {
as.simpleTokens[token] = username
as.simpleTokenKeeper.addSimpleToken(token)
as.simpleTokensMu.Unlock()
as.simpleTokenKeeper.tokensMu.Unlock()
}
func (as *authStore) invalidateUser(username string) {
if as.simpleTokenKeeper == nil {
return
}
as.simpleTokenKeeper.tokensMu.Lock()
as.simpleTokensMu.Lock()
for token, name := range as.simpleTokens {
if strings.Compare(name, username) == 0 {
@ -140,5 +142,4 @@ func (as *authStore) invalidateUser(username string) {
}
}
as.simpleTokensMu.Unlock()
as.simpleTokenKeeper.tokensMu.Unlock()
}

View File

@ -215,8 +215,7 @@ func (as *authStore) AuthEnable() error {
tx.UnsafePut(authBucketName, enableFlagKey, authEnabled)
as.enabled = true
as.simpleTokenKeeper = NewSimpleTokenTTLKeeper(newDeleterFunc(as))
as.enable()
as.rangePermCache = make(map[string]*unifiedRangePermissions)
@ -647,14 +646,12 @@ func (as *authStore) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse,
func (as *authStore) AuthInfoFromToken(token string) (*AuthInfo, bool) {
// same as '(t *tokenSimple) info' in v3.2+
as.simpleTokenKeeper.tokensMu.Lock()
as.simpleTokensMu.Lock()
username, ok := as.simpleTokens[token]
if ok {
if ok && as.simpleTokenKeeper != nil {
as.simpleTokenKeeper.resetSimpleToken(token)
}
as.simpleTokensMu.Unlock()
as.simpleTokenKeeper.tokensMu.Unlock()
return &AuthInfo{Username: username, Revision: as.revision}, ok
}
@ -914,7 +911,7 @@ func NewAuthStore(be backend.Backend, indexWaiter func(uint64) <-chan struct{})
}
if enabled {
as.simpleTokenKeeper = NewSimpleTokenTTLKeeper(newDeleterFunc(as))
as.enable()
}
if as.revision == 0 {