auth

Paddy 2014-11-02 Parent:e45bfa2abc00 Child:42bc3e44f4fe

63:dd75d24475c0 Go to Latest

auth/token.go

Turn our TODO into a BUG. Lack of CSRF protection is most decidedly a bug, so let's list it as such.

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