auth

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

65:f97ca45d5657 Go to Latest

auth/token.go

Fix bug with response_type redirect, add tests. Test that we redirect with an error when an invalid response_type is supplied. Fix a bug that would not add any of our parameters to the redirect URL.

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