auth

Paddy 2014-09-07 Parent:75cf37088852 Child:3a6a65ed380c

34:14599a5c7819 Go to Latest

auth/token.go

Further grant testing. Use the %T format to return the name of the GrantStore that failed the test, rather than just returning the position of the store. Test that storing a grant twice yields an ErrGrantAlreadyExists. Test that retrieving a grant that doesn't exist yields an ErrGrantNotFound. Compare returned grants against expectations.

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