auth
auth/session.go
Remove old BUG. We implemented revoking tokens, so let's remove the BUG designation.
| paddy@70 | 1 package auth |
| paddy@70 | 2 |
| paddy@70 | 3 import ( |
| paddy@70 | 4 "errors" |
| paddy@89 | 5 "sort" |
| paddy@70 | 6 "time" |
| paddy@70 | 7 |
| paddy@70 | 8 "code.secondbit.org/uuid" |
| paddy@70 | 9 ) |
| paddy@70 | 10 |
| paddy@70 | 11 var ( |
| paddy@70 | 12 // ErrNoSessionStore is returned when a Context tries to act on a sessionStore without setting on first. |
| paddy@70 | 13 ErrNoSessionStore = errors.New("no sessionStore was specified for the Context") |
| paddy@70 | 14 // ErrSessionNotFound is returned when a Session is requested but not found in the sessionStore. |
| paddy@70 | 15 ErrSessionNotFound = errors.New("session not found in sessionStore") |
| paddy@70 | 16 // ErrInvalidSession is returned when a Session is specified but is not valid. |
| paddy@70 | 17 ErrInvalidSession = errors.New("session is not valid") |
| paddy@77 | 18 // ErrSessionAlreadyExists is returned when a sessionStore tries to store a Session with an ID that already exists in the sessionStore. |
| paddy@77 | 19 ErrSessionAlreadyExists = errors.New("session already exists") |
| paddy@70 | 20 ) |
| paddy@70 | 21 |
| paddy@70 | 22 // Session represents a user's authenticated session, associating it with a profile |
| paddy@70 | 23 // and some audit data. |
| paddy@70 | 24 type Session struct { |
| paddy@70 | 25 ID string |
| paddy@70 | 26 IP string |
| paddy@70 | 27 UserAgent string |
| paddy@70 | 28 ProfileID uuid.ID |
| paddy@70 | 29 Created time.Time |
| paddy@70 | 30 Login string |
| paddy@70 | 31 Active bool |
| paddy@70 | 32 } |
| paddy@70 | 33 |
| paddy@89 | 34 type sortedSessions []Session |
| paddy@89 | 35 |
| paddy@89 | 36 func (s sortedSessions) Len() int { |
| paddy@89 | 37 return len(s) |
| paddy@89 | 38 } |
| paddy@89 | 39 |
| paddy@89 | 40 func (s sortedSessions) Less(i, j int) bool { |
| paddy@89 | 41 return s[i].Created.After(s[j].Created) |
| paddy@89 | 42 } |
| paddy@89 | 43 |
| paddy@89 | 44 func (s sortedSessions) Swap(i, j int) { |
| paddy@89 | 45 s[i], s[j] = s[j], s[i] |
| paddy@89 | 46 } |
| paddy@89 | 47 |
| paddy@70 | 48 type sessionStore interface { |
| paddy@70 | 49 createSession(session Session) error |
| paddy@70 | 50 getSession(id string) (Session, error) |
| paddy@70 | 51 removeSession(id string) error |
| paddy@70 | 52 listSessions(profile uuid.ID, before time.Time, num int64) ([]Session, error) |
| paddy@70 | 53 } |
| paddy@77 | 54 |
| paddy@77 | 55 func (m *memstore) createSession(session Session) error { |
| paddy@77 | 56 m.sessionLock.Lock() |
| paddy@77 | 57 defer m.sessionLock.Unlock() |
| paddy@77 | 58 if _, ok := m.sessions[session.ID]; ok { |
| paddy@77 | 59 return ErrSessionAlreadyExists |
| paddy@77 | 60 } |
| paddy@77 | 61 m.sessions[session.ID] = session |
| paddy@77 | 62 return nil |
| paddy@77 | 63 } |
| paddy@77 | 64 |
| paddy@77 | 65 func (m *memstore) getSession(id string) (Session, error) { |
| paddy@77 | 66 m.sessionLock.RLock() |
| paddy@77 | 67 defer m.sessionLock.RUnlock() |
| paddy@77 | 68 if _, ok := m.sessions[id]; !ok { |
| paddy@77 | 69 return Session{}, ErrSessionNotFound |
| paddy@77 | 70 } |
| paddy@77 | 71 return m.sessions[id], nil |
| paddy@77 | 72 } |
| paddy@77 | 73 |
| paddy@77 | 74 func (m *memstore) removeSession(id string) error { |
| paddy@77 | 75 m.sessionLock.Lock() |
| paddy@77 | 76 defer m.sessionLock.Unlock() |
| paddy@77 | 77 if _, ok := m.sessions[id]; !ok { |
| paddy@77 | 78 return ErrSessionNotFound |
| paddy@77 | 79 } |
| paddy@77 | 80 delete(m.sessions, id) |
| paddy@77 | 81 return nil |
| paddy@77 | 82 } |
| paddy@77 | 83 |
| paddy@77 | 84 func (m *memstore) listSessions(profile uuid.ID, before time.Time, num int64) ([]Session, error) { |
| paddy@77 | 85 m.sessionLock.RLock() |
| paddy@77 | 86 defer m.sessionLock.RUnlock() |
| paddy@77 | 87 res := []Session{} |
| paddy@77 | 88 for _, session := range m.sessions { |
| paddy@77 | 89 if int64(len(res)) >= num { |
| paddy@77 | 90 break |
| paddy@77 | 91 } |
| paddy@77 | 92 if profile != nil && !profile.Equal(session.ProfileID) { |
| paddy@77 | 93 continue |
| paddy@77 | 94 } |
| paddy@77 | 95 if !before.IsZero() && session.Created.After(before) { |
| paddy@77 | 96 continue |
| paddy@77 | 97 } |
| paddy@77 | 98 res = append(res, session) |
| paddy@77 | 99 } |
| paddy@89 | 100 sorted := sortedSessions(res) |
| paddy@89 | 101 sort.Sort(sorted) |
| paddy@89 | 102 res = []Session(sorted) |
| paddy@77 | 103 return res, nil |
| paddy@77 | 104 } |