comparison pkg/auth/store.go @ 513:b6796cd91604

Simplified the function channel inside the session store.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Fri, 24 Aug 2018 18:06:24 +0200
parents 22e1bf563a04
children 4a637b333417
comparison
equal deleted inserted replaced
512:7474e9922ed5 513:b6796cd91604
15 var Sessions *SessionStore 15 var Sessions *SessionStore
16 16
17 type SessionStore struct { 17 type SessionStore struct {
18 storage *bolt.DB 18 storage *bolt.DB
19 sessions map[string]*Session 19 sessions map[string]*Session
20 cmds chan func(*SessionStore) 20 cmds chan func()
21 } 21 }
22 22
23 var sessionsBucket = []byte("sessions") 23 var sessionsBucket = []byte("sessions")
24 24
25 func NewSessionStore(filename string) (*SessionStore, error) { 25 func NewSessionStore(filename string) (*SessionStore, error) {
26 26
27 pcp := &SessionStore{ 27 ss := &SessionStore{
28 sessions: make(map[string]*Session), 28 sessions: make(map[string]*Session),
29 cmds: make(chan func(*SessionStore)), 29 cmds: make(chan func()),
30 } 30 }
31 if err := pcp.openStorage(filename); err != nil { 31 if err := ss.openStorage(filename); err != nil {
32 return nil, err 32 return nil, err
33 } 33 }
34 go pcp.run() 34 go ss.run()
35 return pcp, nil 35 return ss, nil
36 } 36 }
37 37
38 // openStorage opens a storage file. 38 // openStorage opens a storage file.
39 func (pcp *SessionStore) openStorage(filename string) error { 39 func (ss *SessionStore) openStorage(filename string) error {
40 40
41 // No file, nothing to restore/persist. 41 // No file, nothing to restore/persist.
42 if filename == "" { 42 if filename == "" {
43 return nil 43 return nil
44 } 44 }
60 for k, v := c.First(); k != nil; k, v = c.Next() { 60 for k, v := c.First(); k != nil; k, v = c.Next() {
61 var session Session 61 var session Session
62 if err := session.deserialize(bytes.NewReader(v)); err != nil { 62 if err := session.deserialize(bytes.NewReader(v)); err != nil {
63 return err 63 return err
64 } 64 }
65 pcp.sessions[string(k)] = &session 65 ss.sessions[string(k)] = &session
66 } 66 }
67 67
68 return nil 68 return nil
69 }) 69 })
70 70
71 if err != nil { 71 if err != nil {
72 db.Close() 72 db.Close()
73 return err 73 return err
74 } 74 }
75 75
76 pcp.storage = db 76 ss.storage = db
77 return nil 77 return nil
78 } 78 }
79 79
80 func (pcp *SessionStore) run() { 80 func (ss *SessionStore) run() {
81 for { 81 for {
82 select { 82 select {
83 case cmd := <-pcp.cmds: 83 case cmd := <-ss.cmds:
84 cmd(pcp) 84 cmd()
85 case <-time.After(time.Minute * 5): 85 case <-time.After(time.Minute * 5):
86 pcp.cleanToken() 86 ss.cleanToken()
87 } 87 }
88 } 88 }
89 } 89 }
90 90
91 func (pcp *SessionStore) cleanToken() { 91 func (ss *SessionStore) cleanToken() {
92 now := time.Now() 92 now := time.Now()
93 for token, session := range pcp.sessions { 93 for token, session := range ss.sessions {
94 expires := time.Unix(session.ExpiresAt, 0) 94 expires := time.Unix(session.ExpiresAt, 0)
95 if expires.Before(now) { 95 if expires.Before(now) {
96 delete(pcp.sessions, token) 96 delete(ss.sessions, token)
97 pcp.remove(token) 97 ss.remove(token)
98 } 98 }
99 } 99 }
100 } 100 }
101 101
102 func (pcp *SessionStore) remove(token string) { 102 func (ss *SessionStore) remove(token string) {
103 if pcp.storage == nil { 103 if ss.storage == nil {
104 return 104 return
105 } 105 }
106 err := pcp.storage.Update(func(tx *bolt.Tx) error { 106 err := ss.storage.Update(func(tx *bolt.Tx) error {
107 b := tx.Bucket(sessionsBucket) 107 b := tx.Bucket(sessionsBucket)
108 return b.Delete([]byte(token)) 108 return b.Delete([]byte(token))
109 }) 109 })
110 if err != nil { 110 if err != nil {
111 log.Printf("error: %v\n", err) 111 log.Printf("error: %v\n", err)
112 } 112 }
113 } 113 }
114 114
115 func (pcp *SessionStore) Delete(token string) bool { 115 func (ss *SessionStore) Delete(token string) bool {
116 res := make(chan bool) 116 res := make(chan bool)
117 pcp.cmds <- func(pcp *SessionStore) { 117 ss.cmds <- func() {
118 if _, found := pcp.sessions[token]; !found { 118 if _, found := ss.sessions[token]; !found {
119 res <- false 119 res <- false
120 return 120 return
121 } 121 }
122 delete(pcp.sessions, token) 122 delete(ss.sessions, token)
123 pcp.remove(token) 123 ss.remove(token)
124 res <- true 124 res <- true
125 } 125 }
126 return <-res 126 return <-res
127 } 127 }
128 128
129 func (pcp *SessionStore) store(token string, session *Session) { 129 func (ss *SessionStore) store(token string, session *Session) {
130 if pcp.storage == nil { 130 if ss.storage == nil {
131 return 131 return
132 } 132 }
133 err := pcp.storage.Update(func(tx *bolt.Tx) error { 133 err := ss.storage.Update(func(tx *bolt.Tx) error {
134 b := tx.Bucket(sessionsBucket) 134 b := tx.Bucket(sessionsBucket)
135 var buf bytes.Buffer 135 var buf bytes.Buffer
136 if err := session.serialize(&buf); err != nil { 136 if err := session.serialize(&buf); err != nil {
137 return err 137 return err
138 } 138 }
141 if err != nil { 141 if err != nil {
142 log.Printf("error: %v\n", err) 142 log.Printf("error: %v\n", err)
143 } 143 }
144 } 144 }
145 145
146 func (pcp *SessionStore) Add(token string, session *Session) *Session { 146 func (ss *SessionStore) Add(token string, session *Session) {
147 res := make(chan *Session) 147 res := make(chan struct{})
148 148
149 pcp.cmds <- func(cp *SessionStore) { 149 ss.cmds <- func() {
150 s := pcp.sessions[token] 150 defer close(res)
151 s := ss.sessions[token]
151 if s == nil { 152 if s == nil {
152 s = session 153 s = session
153 pcp.sessions[token] = session 154 ss.sessions[token] = session
154 } 155 }
155 s.touch() 156 s.touch()
156 pcp.store(token, s) 157 ss.store(token, s)
157 res <- s 158 }
158 } 159
159 160 <-res
160 s := <-res 161 }
161 return s 162
162 } 163 func (ss *SessionStore) Renew(token string) (string, error) {
163
164 func (pcp *SessionStore) Renew(token string) (string, error) {
165 164
166 type result struct { 165 type result struct {
167 newToken string 166 newToken string
168 err error 167 err error
169 } 168 }
170 169
171 resCh := make(chan result) 170 resCh := make(chan result)
172 171
173 pcp.cmds <- func(cp *SessionStore) { 172 ss.cmds <- func() {
174 session := pcp.sessions[token] 173 session := ss.sessions[token]
175 if session == nil { 174 if session == nil {
176 resCh <- result{err: ErrNoSuchToken} 175 resCh <- result{err: ErrNoSuchToken}
177 } else { 176 } else {
178 delete(pcp.sessions, token) 177 delete(ss.sessions, token)
179 pcp.remove(token) 178 ss.remove(token)
180 newToken := GenerateSessionKey() 179 newToken := GenerateSessionKey()
181 // TODO: Ensure that this is not racy! 180 // TODO: Ensure that this is not racy!
182 session.ExpiresAt = time.Now().Add(maxTokenValid).Unix() 181 session.ExpiresAt = time.Now().Add(maxTokenValid).Unix()
183 pcp.sessions[newToken] = session 182 ss.sessions[newToken] = session
184 pcp.store(newToken, session) 183 ss.store(newToken, session)
185 resCh <- result{newToken: newToken} 184 resCh <- result{newToken: newToken}
186 } 185 }
187 } 186 }
188 187
189 r := <-resCh 188 r := <-resCh
190 return r.newToken, r.err 189 return r.newToken, r.err
191 } 190 }
192 191
193 func (pcp *SessionStore) Session(token string) *Session { 192 func (ss *SessionStore) Session(token string) *Session {
194 res := make(chan *Session) 193 res := make(chan *Session)
195 pcp.cmds <- func(pcp *SessionStore) { 194 ss.cmds <- func() {
196 session := pcp.sessions[token] 195 session := ss.sessions[token]
197 if session == nil { 196 if session == nil {
198 res <- nil 197 res <- nil
199 } else { 198 } else {
200 session.touch() 199 session.touch()
201 pcp.store(token, session) 200 ss.store(token, session)
202 res <- session 201 res <- session
203 } 202 }
204 } 203 }
205 return <-res 204 return <-res
206 } 205 }
207 206
208 func (pcp *SessionStore) Logout(user string) { 207 func (ss *SessionStore) Logout(user string) {
209 pcp.cmds <- func(pcp *SessionStore) { 208 ss.cmds <- func() {
210 for token, session := range pcp.sessions { 209 for token, session := range ss.sessions {
211 if session.User == user { 210 if session.User == user {
212 delete(pcp.sessions, token) 211 delete(ss.sessions, token)
213 pcp.remove(token) 212 ss.remove(token)
214 } 213 }
215 } 214 }
216 } 215 }
217 } 216 }
218 217
219 func (pcp *SessionStore) Shutdown() error { 218 func (ss *SessionStore) Shutdown() error {
220 if db := pcp.storage; db != nil { 219 if db := ss.storage; db != nil {
221 log.Println("info: shutdown persistent connection pool.") 220 log.Println("info: shutdown persistent connection pool.")
222 pcp.storage = nil 221 ss.storage = nil
223 return db.Close() 222 return db.Close()
224 } 223 }
225 log.Println("info: shutdown in-memory connection pool.") 224 log.Println("info: shutdown in-memory connection pool.")
226 return nil 225 return nil
227 } 226 }