auth

Paddy 2015-01-10 Parent:c03b5eb3179e Child:0a1e16b9c141

112:da2a0954e8d3 Go to Latest

auth/token.go

Flesh out auth code grant (in)validation. Flesh out our tests for functions that do the validation and invalidation of the authorization code grant type's authorization codes. Basically, make sure that the auth code's are being checked right and that marking them as used after they're used works.

History
1 package auth
3 import (
4 "errors"
5 "time"
7 "code.secondbit.org/uuid.hg"
8 )
10 const (
11 defaultTokenExpiration = 3600 // one hour
12 defaultRefreshTokenExpiration = 86400 // one day
13 )
15 var (
16 // ErrNoTokenStore is returned when a Context tries to act on a tokenStore without setting one first.
17 ErrNoTokenStore = errors.New("no tokenStore was specified for the Context")
18 // ErrTokenNotFound is returned when a Token is requested but not found in a tokenStore.
19 ErrTokenNotFound = errors.New("token not found in tokenStore")
20 // ErrTokenAlreadyExists is returned when a Token is added to a tokenStore, but another Token with
21 // the same AccessToken property already exists in the tokenStore.
22 ErrTokenAlreadyExists = errors.New("token already exists in tokenStore")
23 )
25 // Token represents an access and/or refresh token that the Client can use to access user data
26 // or obtain a new access token.
27 type Token struct {
28 AccessToken string
29 RefreshToken string
30 Created time.Time
31 CreatedFrom string
32 ExpiresIn int32
33 RefreshExpiresIn int32
34 TokenType string
35 Scope string
36 ProfileID uuid.ID
37 Revoked bool
38 }
40 type tokenStore interface {
41 getToken(token string, refresh bool) (Token, error)
42 saveToken(token Token) error
43 removeToken(token string) error
44 revokeToken(token string, refresh bool) error
45 getTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error)
46 }
48 func (m *memstore) getToken(token string, refresh bool) (Token, error) {
49 if refresh {
50 t, err := m.lookupTokenByRefresh(token)
51 if err != nil {
52 return Token{}, err
53 }
54 token = t
55 }
56 m.tokenLock.RLock()
57 defer m.tokenLock.RUnlock()
58 result, ok := m.tokens[token]
59 if !ok {
60 return Token{}, ErrTokenNotFound
61 }
62 return result, nil
63 }
65 func (m *memstore) saveToken(token Token) error {
66 m.tokenLock.Lock()
67 defer m.tokenLock.Unlock()
68 _, ok := m.tokens[token.AccessToken]
69 if ok {
70 return ErrTokenAlreadyExists
71 }
72 m.tokens[token.AccessToken] = token
73 if token.RefreshToken != "" {
74 m.refreshTokenLookup[token.RefreshToken] = token.AccessToken
75 }
76 if _, ok = m.profileTokenLookup[token.ProfileID.String()]; ok {
77 m.profileTokenLookup[token.ProfileID.String()] = append(m.profileTokenLookup[token.ProfileID.String()], token.AccessToken)
78 } else {
79 m.profileTokenLookup[token.ProfileID.String()] = []string{token.AccessToken}
80 }
81 return nil
82 }
84 func (m *memstore) removeToken(token string) error {
85 m.tokenLock.Lock()
86 defer m.tokenLock.Unlock()
87 t, ok := m.tokens[token]
88 if !ok {
89 return ErrTokenNotFound
90 }
91 delete(m.tokens, token)
92 if t.RefreshToken != "" {
93 delete(m.refreshTokenLookup, t.RefreshToken)
94 }
95 pos := -1
96 for p, item := range m.profileTokenLookup[t.ProfileID.String()] {
97 if item == token {
98 pos = p
99 break
100 }
101 }
102 if pos >= 0 {
103 m.profileTokenLookup[t.ProfileID.String()] = append(m.profileTokenLookup[t.ProfileID.String()][:pos], m.profileTokenLookup[t.ProfileID.String()][pos+1:]...)
104 }
105 return nil
106 }
108 func (m *memstore) revokeToken(token string, refresh bool) error {
109 if refresh {
110 t, err := m.lookupTokenByRefresh(token)
111 if err != nil {
112 return err
113 }
114 token = t
115 }
116 m.tokenLock.Lock()
117 defer m.tokenLock.Unlock()
118 t, ok := m.tokens[token]
119 if !ok {
120 return ErrTokenNotFound
121 }
122 t.Revoked = true
123 m.tokens[token] = t
124 return nil
125 }
127 func (m *memstore) getTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) {
128 ids, err := m.lookupTokensByProfileID(profileID.String())
129 if err != nil {
130 return []Token{}, err
131 }
132 if len(ids) > num+offset {
133 ids = ids[offset : num+offset]
134 } else if len(ids) > offset {
135 ids = ids[offset:]
136 } else {
137 return []Token{}, nil
138 }
139 tokens := []Token{}
140 for _, id := range ids {
141 token, err := m.getToken(id, false)
142 if err != nil {
143 return []Token{}, err
144 }
145 tokens = append(tokens, token)
146 }
147 return tokens, nil
148 }