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