auth

Paddy 2014-12-13 Parent:61a802849b51 Child:c1b3a36af1a7

89:229422395721 Go to Latest

auth/token.go

Sort sessions before returning them. When using the memstore, sort sessions by the date they were created, descending, before returning them.

History
1 package auth
3 import (
4 "errors"
5 "time"
7 "code.secondbit.org/uuid"
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 // BUG(paddy): need to be able to revoke tokens and refresh tokens
42 getToken(token string, refresh bool) (Token, error)
43 saveToken(token Token) error
44 removeToken(token string) 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) getTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) {
109 ids, err := m.lookupTokensByProfileID(profileID.String())
110 if err != nil {
111 return []Token{}, err
112 }
113 if len(ids) > num+offset {
114 ids = ids[offset : num+offset]
115 } else if len(ids) > offset {
116 ids = ids[offset:]
117 } else {
118 return []Token{}, nil
119 }
120 tokens := []Token{}
121 for _, id := range ids {
122 token, err := m.getToken(id, false)
123 if err != nil {
124 return []Token{}, err
125 }
126 tokens = append(tokens, token)
127 }
128 return tokens, nil
129 }