comparison pkg/auth/store.go @ 498:22e1bf563a04 metamorph-for-all

Throw away the connection level for sessions. This is not needed any more because the db connection are not bound to the sessions any more.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Fri, 24 Aug 2018 15:12:22 +0200
parents 5c08afd15ce7
children b6796cd91604
comparison
equal deleted inserted replaced
495:5c08afd15ce7 498:22e1bf563a04
1 package auth 1 package auth
2 2
3 import ( 3 import (
4 "bytes" 4 "bytes"
5 "errors"
5 "log" 6 "log"
6 "time" 7 "time"
7 8
8 bolt "github.com/coreos/bbolt" 9 bolt "github.com/coreos/bbolt"
9 ) 10 )
10 11
12 var ErrNoSuchToken = errors.New("No such token")
13
11 // Sessions is the global connection pool. 14 // Sessions is the global connection pool.
12 var Sessions *SessionStore 15 var Sessions *SessionStore
13 16
14 type SessionStore struct { 17 type SessionStore struct {
15 storage *bolt.DB 18 storage *bolt.DB
16 conns map[string]*Connection 19 sessions map[string]*Session
17 cmds chan func(*SessionStore) 20 cmds chan func(*SessionStore)
18 } 21 }
19 22
20 var sessionsBucket = []byte("sessions") 23 var sessionsBucket = []byte("sessions")
21 24
22 func NewSessionStore(filename string) (*SessionStore, error) { 25 func NewSessionStore(filename string) (*SessionStore, error) {
23 26
24 pcp := &SessionStore{ 27 pcp := &SessionStore{
25 conns: make(map[string]*Connection), 28 sessions: make(map[string]*Session),
26 cmds: make(chan func(*SessionStore)), 29 cmds: make(chan func(*SessionStore)),
27 } 30 }
28 if err := pcp.openStorage(filename); err != nil { 31 if err := pcp.openStorage(filename); err != nil {
29 return nil, err 32 return nil, err
30 } 33 }
31 go pcp.run() 34 go pcp.run()
53 56
54 // pre-load sessions 57 // pre-load sessions
55 c := b.Cursor() 58 c := b.Cursor()
56 59
57 for k, v := c.First(); k != nil; k, v = c.Next() { 60 for k, v := c.First(); k != nil; k, v = c.Next() {
58 var conn Connection 61 var session Session
59 if err := conn.deserialize(bytes.NewReader(v)); err != nil { 62 if err := session.deserialize(bytes.NewReader(v)); err != nil {
60 return err 63 return err
61 } 64 }
62 pcp.conns[string(k)] = &conn 65 pcp.sessions[string(k)] = &session
63 } 66 }
64 67
65 return nil 68 return nil
66 }) 69 })
67 70
85 } 88 }
86 } 89 }
87 90
88 func (pcp *SessionStore) cleanToken() { 91 func (pcp *SessionStore) cleanToken() {
89 now := time.Now() 92 now := time.Now()
90 for token, con := range pcp.conns { 93 for token, session := range pcp.sessions {
91 expires := time.Unix(con.session.ExpiresAt, 0) 94 expires := time.Unix(session.ExpiresAt, 0)
92 if expires.Before(now) { 95 if expires.Before(now) {
93 delete(pcp.conns, token) 96 delete(pcp.sessions, token)
94 pcp.remove(token) 97 pcp.remove(token)
95 } 98 }
96 } 99 }
97 } 100 }
98 101
110 } 113 }
111 114
112 func (pcp *SessionStore) Delete(token string) bool { 115 func (pcp *SessionStore) Delete(token string) bool {
113 res := make(chan bool) 116 res := make(chan bool)
114 pcp.cmds <- func(pcp *SessionStore) { 117 pcp.cmds <- func(pcp *SessionStore) {
115 if _, found := pcp.conns[token]; !found { 118 if _, found := pcp.sessions[token]; !found {
116 res <- false 119 res <- false
117 return 120 return
118 } 121 }
119 delete(pcp.conns, token) 122 delete(pcp.sessions, token)
120 pcp.remove(token) 123 pcp.remove(token)
121 res <- true 124 res <- true
122 } 125 }
123 return <-res 126 return <-res
124 } 127 }
125 128
126 func (pcp *SessionStore) store(token string, con *Connection) { 129 func (pcp *SessionStore) store(token string, session *Session) {
127 if pcp.storage == nil { 130 if pcp.storage == nil {
128 return 131 return
129 } 132 }
130 err := pcp.storage.Update(func(tx *bolt.Tx) error { 133 err := pcp.storage.Update(func(tx *bolt.Tx) error {
131 b := tx.Bucket(sessionsBucket) 134 b := tx.Bucket(sessionsBucket)
132 var buf bytes.Buffer 135 var buf bytes.Buffer
133 if err := con.serialize(&buf); err != nil { 136 if err := session.serialize(&buf); err != nil {
134 return err 137 return err
135 } 138 }
136 return b.Put([]byte(token), buf.Bytes()) 139 return b.Put([]byte(token), buf.Bytes())
137 }) 140 })
138 if err != nil { 141 if err != nil {
139 log.Printf("error: %v\n", err) 142 log.Printf("error: %v\n", err)
140 } 143 }
141 } 144 }
142 145
143 func (pcp *SessionStore) Add(token string, session *Session) *Connection { 146 func (pcp *SessionStore) Add(token string, session *Session) *Session {
144 res := make(chan *Connection) 147 res := make(chan *Session)
145 148
146 pcp.cmds <- func(cp *SessionStore) { 149 pcp.cmds <- func(cp *SessionStore) {
147 con := pcp.conns[token] 150 s := pcp.sessions[token]
148 if con == nil { 151 if s == nil {
149 con = &Connection{} 152 s = session
150 pcp.conns[token] = con 153 pcp.sessions[token] = session
151 } 154 }
152 con.set(session) 155 s.touch()
153 pcp.store(token, con) 156 pcp.store(token, s)
154 res <- con 157 res <- s
155 } 158 }
156 159
157 con := <-res 160 s := <-res
158 return con 161 return s
159 } 162 }
160 163
161 func (pcp *SessionStore) Renew(token string) (string, error) { 164 func (pcp *SessionStore) Renew(token string) (string, error) {
162 165
163 type result struct { 166 type result struct {
166 } 169 }
167 170
168 resCh := make(chan result) 171 resCh := make(chan result)
169 172
170 pcp.cmds <- func(cp *SessionStore) { 173 pcp.cmds <- func(cp *SessionStore) {
171 con := pcp.conns[token] 174 session := pcp.sessions[token]
172 if con == nil { 175 if session == nil {
173 resCh <- result{err: ErrNoSuchToken} 176 resCh <- result{err: ErrNoSuchToken}
174 } else { 177 } else {
175 delete(pcp.conns, token) 178 delete(pcp.sessions, token)
176 pcp.remove(token) 179 pcp.remove(token)
177 newToken := GenerateSessionKey() 180 newToken := GenerateSessionKey()
178 // TODO: Ensure that this is not racy! 181 // TODO: Ensure that this is not racy!
179 con.session.ExpiresAt = time.Now().Add(maxTokenValid).Unix() 182 session.ExpiresAt = time.Now().Add(maxTokenValid).Unix()
180 pcp.conns[newToken] = con 183 pcp.sessions[newToken] = session
181 pcp.store(newToken, con) 184 pcp.store(newToken, session)
182 resCh <- result{newToken: newToken} 185 resCh <- result{newToken: newToken}
183 } 186 }
184 } 187 }
185 188
186 r := <-resCh 189 r := <-resCh
187 return r.newToken, r.err 190 return r.newToken, r.err
188 }
189
190 func (pcp *SessionStore) Do(token string) (*Session, error) {
191
192 type result struct {
193 session *Session
194 err error
195 }
196
197 res := make(chan result)
198
199 pcp.cmds <- func(pcp *SessionStore) {
200 con := pcp.conns[token]
201 if con == nil {
202 res <- result{err: ErrNoSuchToken}
203 return
204 }
205 con.touch()
206 pcp.store(token, con)
207
208 res <- result{session: con.session}
209 }
210
211 r := <-res
212
213 if r.err != nil {
214 return nil, r.err
215 }
216
217 return r.session, nil
218 } 191 }
219 192
220 func (pcp *SessionStore) Session(token string) *Session { 193 func (pcp *SessionStore) Session(token string) *Session {
221 res := make(chan *Session) 194 res := make(chan *Session)
222 pcp.cmds <- func(pcp *SessionStore) { 195 pcp.cmds <- func(pcp *SessionStore) {
223 con := pcp.conns[token] 196 session := pcp.sessions[token]
224 if con == nil { 197 if session == nil {
225 res <- nil 198 res <- nil
226 } else { 199 } else {
227 con.touch() 200 session.touch()
228 pcp.store(token, con) 201 pcp.store(token, session)
229 res <- con.session 202 res <- session
230 } 203 }
231 } 204 }
232 return <-res 205 return <-res
233 } 206 }
234 207
235 func (pcp *SessionStore) Logout(user string) { 208 func (pcp *SessionStore) Logout(user string) {
236 pcp.cmds <- func(pcp *SessionStore) { 209 pcp.cmds <- func(pcp *SessionStore) {
237 for token, con := range pcp.conns { 210 for token, session := range pcp.sessions {
238 if con.session.User == user { 211 if session.User == user {
239 delete(pcp.conns, token) 212 delete(pcp.sessions, token)
240 pcp.remove(token) 213 pcp.remove(token)
241 } 214 }
242 } 215 }
243 } 216 }
244 } 217 }