auth
auth/memstore.go
Test authentication helper, fix bugs with authentication. Authentication needs to be hex encoded to be stored, so it only makes sense to decode the hex string stored to get the bytes we'll be comparing. Check for ErrLoginNotFound in addition to ErrProfileNotFound. ErrLoginNotFound is more likely to occur, anyways. Add unit tests for our authentication helper to verify it functions as expected.
| paddy@28 | 1 package auth |
| paddy@28 | 2 |
| paddy@31 | 3 import ( |
| paddy@31 | 4 "sync" |
| paddy@31 | 5 |
| paddy@45 | 6 "code.secondbit.org/uuid" |
| paddy@31 | 7 ) |
| paddy@28 | 8 |
| paddy@57 | 9 type memstore struct { |
| paddy@28 | 10 tokens map[string]Token |
| paddy@28 | 11 refreshTokenLookup map[string]string |
| paddy@28 | 12 profileTokenLookup map[string][]string |
| paddy@28 | 13 tokenLock sync.RWMutex |
| paddy@29 | 14 |
| paddy@29 | 15 grants map[string]Grant |
| paddy@29 | 16 grantLock sync.RWMutex |
| paddy@31 | 17 |
| paddy@31 | 18 clients map[string]Client |
| paddy@31 | 19 profileClientLookup map[string][]uuid.ID |
| paddy@31 | 20 clientLock sync.RWMutex |
| paddy@38 | 21 |
| paddy@41 | 22 endpoints map[string][]Endpoint |
| paddy@41 | 23 endpointLock sync.RWMutex |
| paddy@41 | 24 |
| paddy@38 | 25 profiles map[string]Profile |
| paddy@38 | 26 profileLock sync.RWMutex |
| paddy@44 | 27 |
| paddy@44 | 28 logins map[string]Login |
| paddy@44 | 29 profileLoginLookup map[string][]string |
| paddy@44 | 30 loginLock sync.RWMutex |
| paddy@77 | 31 |
| paddy@77 | 32 sessions map[string]Session |
| paddy@77 | 33 sessionLock sync.RWMutex |
| paddy@28 | 34 } |
| paddy@28 | 35 |
| paddy@57 | 36 // NewMemstore returns an in-memory version of our datastores, |
| paddy@57 | 37 // which is handy for tests. Though the implementation is concurrency-safe, |
| paddy@57 | 38 // if makes no attempt to persist the data, and therefore it is inadvisable |
| paddy@57 | 39 // to use it in a production setting. |
| paddy@57 | 40 func NewMemstore() *memstore { |
| paddy@57 | 41 return &memstore{ |
| paddy@31 | 42 tokens: map[string]Token{}, |
| paddy@31 | 43 refreshTokenLookup: map[string]string{}, |
| paddy@31 | 44 profileTokenLookup: map[string][]string{}, |
| paddy@31 | 45 grants: map[string]Grant{}, |
| paddy@31 | 46 clients: map[string]Client{}, |
| paddy@31 | 47 profileClientLookup: map[string][]uuid.ID{}, |
| paddy@41 | 48 endpoints: map[string][]Endpoint{}, |
| paddy@38 | 49 profiles: map[string]Profile{}, |
| paddy@44 | 50 logins: map[string]Login{}, |
| paddy@44 | 51 profileLoginLookup: map[string][]string{}, |
| paddy@77 | 52 sessions: map[string]Session{}, |
| paddy@28 | 53 } |
| paddy@28 | 54 } |
| paddy@28 | 55 |
| paddy@57 | 56 func (m *memstore) lookupTokenByRefresh(token string) (string, error) { |
| paddy@28 | 57 m.tokenLock.RLock() |
| paddy@28 | 58 defer m.tokenLock.RUnlock() |
| paddy@28 | 59 t, ok := m.refreshTokenLookup[token] |
| paddy@28 | 60 if !ok { |
| paddy@28 | 61 return "", ErrTokenNotFound |
| paddy@28 | 62 } |
| paddy@28 | 63 return t, nil |
| paddy@28 | 64 } |
| paddy@28 | 65 |
| paddy@57 | 66 func (m *memstore) lookupTokensByProfileID(id string) ([]string, error) { |
| paddy@28 | 67 m.tokenLock.RLock() |
| paddy@28 | 68 defer m.tokenLock.RUnlock() |
| paddy@28 | 69 return m.profileTokenLookup[id], nil |
| paddy@28 | 70 } |
| paddy@31 | 71 |
| paddy@57 | 72 func (m *memstore) lookupClientsByProfileID(id string) []uuid.ID { |
| paddy@31 | 73 m.clientLock.RLock() |
| paddy@31 | 74 defer m.clientLock.RUnlock() |
| paddy@33 | 75 c, ok := m.profileClientLookup[id] |
| paddy@33 | 76 if !ok { |
| paddy@33 | 77 return []uuid.ID{} |
| paddy@33 | 78 } |
| paddy@33 | 79 return c |
| paddy@31 | 80 } |