8460: Return recent events if last_log_id given.
[arvados.git] / services / ws / permission.go
1 package main
2
3 import (
4         "net/http"
5         "net/url"
6         "time"
7
8         "git.curoverse.com/arvados.git/sdk/go/arvados"
9 )
10
11 const (
12         maxPermCacheAge = time.Hour
13         minPermCacheAge = 5 * time.Minute
14 )
15
16 type permChecker interface {
17         SetToken(token string)
18         Check(uuid string) (bool, error)
19 }
20
21 func NewPermChecker(ac arvados.Client) permChecker {
22         ac.AuthToken = ""
23         return &cachingPermChecker{
24                 Client:     &ac,
25                 cache:      make(map[string]cacheEnt),
26                 maxCurrent: 16,
27         }
28 }
29
30 type cacheEnt struct {
31         time.Time
32         allowed bool
33 }
34
35 type cachingPermChecker struct {
36         *arvados.Client
37         cache      map[string]cacheEnt
38         maxCurrent int
39 }
40
41 func (pc *cachingPermChecker) SetToken(token string) {
42         pc.Client.AuthToken = token
43 }
44
45 func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
46         pc.tidy()
47         now := time.Now()
48         if perm, ok := pc.cache[uuid]; ok && now.Sub(perm.Time) < maxPermCacheAge {
49                 debugLogf("perm (cached): %+q %+q ...%v", pc.Client.AuthToken, uuid, perm.allowed)
50                 return perm.allowed, nil
51         }
52         var buf map[string]interface{}
53         path, err := pc.PathForUUID("get", uuid)
54         if err != nil {
55                 return false, err
56         }
57         err = pc.RequestAndDecode(&buf, "GET", path, nil, url.Values{
58                 "select": {`["uuid"]`},
59         })
60
61         var allowed bool
62         if err == nil {
63                 allowed = true
64         } else if txErr, ok := err.(arvados.TransactionError); ok && txErr.StatusCode == http.StatusNotFound {
65                 allowed = false
66         } else {
67                 errorLogf("perm err: %+q %+q: %T %s", pc.Client.AuthToken, uuid, err, err)
68                 return false, err
69         }
70         debugLogf("perm: %+q %+q ...%v", pc.Client.AuthToken, uuid, allowed)
71         pc.cache[uuid] = cacheEnt{Time: now, allowed: allowed}
72         return allowed, nil
73 }
74
75 func (pc *cachingPermChecker) tidy() {
76         if len(pc.cache) <= pc.maxCurrent*2 {
77                 return
78         }
79         tooOld := time.Now().Add(-minPermCacheAge)
80         for uuid, t := range pc.cache {
81                 if t.Before(tooOld) {
82                         delete(pc.cache, uuid)
83                 }
84         }
85         pc.maxCurrent = len(pc.cache)
86 }