auth

Paddy 2014-10-15 Parent:73a9f7a6af54 Child:e45bfa2abc00

50:b620d32d9903 Go to Latest

auth/token.go

Create the Context type and its helpers. Create a Context type that ties together all our Stores and other configuration-specific items. Create helper functions for the Context, to throw errors when something is used without first being set, as all possible Context values _can_ be nil. Basically, it's better to throw an error than panic.

History
paddy@28 1 package auth
paddy@28 2
paddy@28 3 import (
paddy@28 4 "errors"
paddy@28 5 "time"
paddy@28 6
paddy@45 7 "code.secondbit.org/uuid"
paddy@28 8 )
paddy@28 9
paddy@28 10 var (
paddy@49 11 ErrNoTokenStore = errors.New("no TokenStore was specified for the Context")
paddy@49 12 ErrTokenNotFound = errors.New("token not found in TokenStore")
paddy@49 13 ErrTokenAlreadyExists = errors.New("token already exists in TokenStore")
paddy@28 14 )
paddy@28 15
paddy@28 16 type Token struct {
paddy@28 17 AccessToken string
paddy@28 18 RefreshToken string
paddy@28 19 Created time.Time
paddy@28 20 ExpiresIn int32
paddy@28 21 TokenType string
paddy@28 22 Scope string
paddy@28 23 ProfileID uuid.ID
paddy@28 24 }
paddy@28 25
paddy@28 26 type TokenStore interface {
paddy@28 27 GetToken(token string, refresh bool) (Token, error)
paddy@28 28 SaveToken(token Token) error
paddy@28 29 RemoveToken(token string) error
paddy@28 30 GetTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error)
paddy@28 31 }
paddy@28 32
paddy@28 33 func (m *Memstore) GetToken(token string, refresh bool) (Token, error) {
paddy@28 34 if refresh {
paddy@28 35 t, err := m.lookupTokenByRefresh(token)
paddy@28 36 if err != nil {
paddy@28 37 return Token{}, err
paddy@28 38 }
paddy@28 39 token = t
paddy@28 40 }
paddy@28 41 m.tokenLock.RLock()
paddy@28 42 defer m.tokenLock.RUnlock()
paddy@28 43 result, ok := m.tokens[token]
paddy@28 44 if !ok {
paddy@28 45 return Token{}, ErrTokenNotFound
paddy@28 46 }
paddy@28 47 return result, nil
paddy@28 48 }
paddy@28 49
paddy@28 50 func (m *Memstore) SaveToken(token Token) error {
paddy@28 51 m.tokenLock.Lock()
paddy@28 52 defer m.tokenLock.Unlock()
paddy@28 53 _, ok := m.tokens[token.AccessToken]
paddy@28 54 if ok {
paddy@28 55 return ErrTokenAlreadyExists
paddy@28 56 }
paddy@28 57 m.tokens[token.AccessToken] = token
paddy@28 58 if token.RefreshToken != "" {
paddy@28 59 m.refreshTokenLookup[token.RefreshToken] = token.AccessToken
paddy@28 60 }
paddy@28 61 if _, ok = m.profileTokenLookup[token.ProfileID.String()]; ok {
paddy@28 62 m.profileTokenLookup[token.ProfileID.String()] = append(m.profileTokenLookup[token.ProfileID.String()], token.AccessToken)
paddy@28 63 } else {
paddy@28 64 m.profileTokenLookup[token.ProfileID.String()] = []string{token.AccessToken}
paddy@28 65 }
paddy@28 66 return nil
paddy@28 67 }
paddy@28 68
paddy@28 69 func (m *Memstore) RemoveToken(token string) error {
paddy@28 70 m.tokenLock.Lock()
paddy@28 71 defer m.tokenLock.Unlock()
paddy@28 72 t, ok := m.tokens[token]
paddy@28 73 if !ok {
paddy@28 74 return ErrTokenNotFound
paddy@28 75 }
paddy@28 76 delete(m.tokens, token)
paddy@28 77 if t.RefreshToken != "" {
paddy@28 78 delete(m.refreshTokenLookup, t.RefreshToken)
paddy@28 79 }
paddy@28 80 pos := -1
paddy@28 81 for p, item := range m.profileTokenLookup[t.ProfileID.String()] {
paddy@28 82 if item == token {
paddy@28 83 pos = p
paddy@28 84 break
paddy@28 85 }
paddy@28 86 }
paddy@28 87 if pos >= 0 {
paddy@28 88 m.profileTokenLookup[t.ProfileID.String()] = append(m.profileTokenLookup[t.ProfileID.String()][:pos], m.profileTokenLookup[t.ProfileID.String()][pos+1:]...)
paddy@28 89 }
paddy@28 90 return nil
paddy@28 91 }
paddy@28 92
paddy@28 93 func (m *Memstore) GetTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) {
paddy@28 94 ids, err := m.lookupTokensByProfileID(profileID.String())
paddy@28 95 if err != nil {
paddy@28 96 return []Token{}, err
paddy@28 97 }
paddy@28 98 if len(ids) > num+offset {
paddy@28 99 ids = ids[offset : num+offset]
paddy@28 100 } else if len(ids) > offset {
paddy@28 101 ids = ids[offset:]
paddy@28 102 } else {
paddy@28 103 return []Token{}, nil
paddy@28 104 }
paddy@28 105 tokens := []Token{}
paddy@28 106 for _, id := range ids {
paddy@28 107 token, err := m.GetToken(id, false)
paddy@28 108 if err != nil {
paddy@28 109 return []Token{}, err
paddy@28 110 }
paddy@28 111 tokens = append(tokens, token)
paddy@28 112 }
paddy@28 113 return tokens, nil
paddy@28 114 }