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
parent 712f6cb0e1
commit 18bccb4285

View File

@ -41,20 +41,10 @@ var (
) )
type simpleTokenTTLKeeper struct { type simpleTokenTTLKeeper struct {
tokensMu sync.Mutex
tokens map[string]time.Time tokens map[string]time.Time
stopCh chan chan struct{} stopCh chan chan struct{}
deleteTokenFunc func(string) deleteTokenFunc func(string)
} mu *sync.Mutex
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
} }
func (tm *simpleTokenTTLKeeper) stop() { func (tm *simpleTokenTTLKeeper) stop() {
@ -85,14 +75,14 @@ func (tm *simpleTokenTTLKeeper) run() {
select { select {
case <-tokenTicker.C: case <-tokenTicker.C:
nowtime := time.Now() nowtime := time.Now()
tm.tokensMu.Lock() tm.mu.Lock()
for t, tokenendtime := range tm.tokens { for t, tokenendtime := range tm.tokens {
if nowtime.After(tokenendtime) { if nowtime.After(tokenendtime) {
tm.deleteTokenFunc(t) tm.deleteTokenFunc(t)
delete(tm.tokens, t) delete(tm.tokens, t)
} }
} }
tm.tokensMu.Unlock() tm.mu.Unlock()
case waitCh := <-tm.stopCh: case waitCh := <-tm.stopCh:
tm.tokens = make(map[string]time.Time) tm.tokens = make(map[string]time.Time)
waitCh <- struct{}{} waitCh <- struct{}{}
@ -124,9 +114,7 @@ func (t *tokenSimple) genTokenPrefix() (string, error) {
} }
func (t *tokenSimple) assignSimpleTokenToUser(username, token string) { func (t *tokenSimple) assignSimpleTokenToUser(username, token string) {
t.simpleTokenKeeper.tokensMu.Lock()
t.simpleTokensMu.Lock() t.simpleTokensMu.Lock()
_, ok := t.simpleTokens[token] _, ok := t.simpleTokens[token]
if ok { if ok {
plog.Panicf("token %s is alredy used", token) plog.Panicf("token %s is alredy used", token)
@ -135,14 +123,12 @@ func (t *tokenSimple) assignSimpleTokenToUser(username, token string) {
t.simpleTokens[token] = username t.simpleTokens[token] = username
t.simpleTokenKeeper.addSimpleToken(token) t.simpleTokenKeeper.addSimpleToken(token)
t.simpleTokensMu.Unlock() t.simpleTokensMu.Unlock()
t.simpleTokenKeeper.tokensMu.Unlock()
} }
func (t *tokenSimple) invalidateUser(username string) { func (t *tokenSimple) invalidateUser(username string) {
if t.simpleTokenKeeper == nil { if t.simpleTokenKeeper == nil {
return return
} }
t.simpleTokenKeeper.tokensMu.Lock()
t.simpleTokensMu.Lock() t.simpleTokensMu.Lock()
for token, name := range t.simpleTokens { for token, name := range t.simpleTokens {
if strings.Compare(name, username) == 0 { if strings.Compare(name, username) == 0 {
@ -151,22 +137,22 @@ func (t *tokenSimple) invalidateUser(username string) {
} }
} }
t.simpleTokensMu.Unlock() t.simpleTokensMu.Unlock()
t.simpleTokenKeeper.tokensMu.Unlock()
} }
func newDeleterFunc(t *tokenSimple) func(string) { func (t *tokenSimple) enable() {
return func(tk string) { delf := func(tk string) {
t.simpleTokensMu.Lock()
defer t.simpleTokensMu.Unlock()
if username, ok := t.simpleTokens[tk]; ok { if username, ok := t.simpleTokens[tk]; ok {
plog.Infof("deleting token %s for user %s", tk, username) plog.Infof("deleting token %s for user %s", tk, username)
delete(t.simpleTokens, tk) delete(t.simpleTokens, tk)
} }
} }
} t.simpleTokenKeeper = &simpleTokenTTLKeeper{
tokens: make(map[string]time.Time),
func (t *tokenSimple) enable() { stopCh: make(chan chan struct{}),
t.simpleTokenKeeper = NewSimpleTokenTTLKeeper(newDeleterFunc(t)) deleteTokenFunc: delf,
mu: &t.simpleTokensMu,
}
go t.simpleTokenKeeper.run()
} }
func (t *tokenSimple) disable() { func (t *tokenSimple) disable() {
@ -183,14 +169,12 @@ func (t *tokenSimple) info(ctx context.Context, token string, revision uint64) (
if !t.isValidSimpleToken(ctx, token) { if !t.isValidSimpleToken(ctx, token) {
return nil, false return nil, false
} }
t.simpleTokenKeeper.tokensMu.Lock()
t.simpleTokensMu.Lock() t.simpleTokensMu.Lock()
username, ok := t.simpleTokens[token] username, ok := t.simpleTokens[token]
if ok { if ok && t.simpleTokenKeeper != nil {
t.simpleTokenKeeper.resetSimpleToken(token) t.simpleTokenKeeper.resetSimpleToken(token)
} }
t.simpleTokensMu.Unlock() t.simpleTokensMu.Unlock()
t.simpleTokenKeeper.tokensMu.Unlock()
return &AuthInfo{Username: username, Revision: revision}, ok return &AuthInfo{Username: username, Revision: revision}, ok
} }