20862: Merge branch 'main' into 20862-google-api-client
[arvados.git] / services / ws / permission.go
index a39a959312aed582957d8845dddfc70394b649a4..f71ca61167dc70d7dded2623e6edfde6c1f3cb7c 100644 (file)
@@ -2,14 +2,16 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-package main
+package ws
 
 import (
+       "context"
        "net/http"
        "net/url"
        "time"
 
-       "git.curoverse.com/arvados.git/sdk/go/arvados"
+       "git.arvados.org/arvados.git/sdk/go/arvados"
+       "git.arvados.org/arvados.git/sdk/go/ctxlog"
 )
 
 const (
@@ -19,13 +21,13 @@ const (
 
 type permChecker interface {
        SetToken(token string)
-       Check(uuid string) (bool, error)
+       Check(ctx context.Context, uuid string) (bool, error)
 }
 
-func newPermChecker(ac arvados.Client) permChecker {
-       ac.AuthToken = ""
+func newPermChecker(ac *arvados.Client) permChecker {
        return &cachingPermChecker{
-               Client:     &ac,
+               ac:         ac,
+               token:      "-",
                cache:      make(map[string]cacheEnt),
                maxCurrent: 16,
        }
@@ -37,7 +39,8 @@ type cacheEnt struct {
 }
 
 type cachingPermChecker struct {
-       *arvados.Client
+       ac         *arvados.Client
+       token      string
        cache      map[string]cacheEnt
        maxCurrent int
 
@@ -47,17 +50,17 @@ type cachingPermChecker struct {
 }
 
 func (pc *cachingPermChecker) SetToken(token string) {
-       if pc.Client.AuthToken == token {
+       if pc.token == token {
                return
        }
-       pc.Client.AuthToken = token
+       pc.token = token
        pc.cache = make(map[string]cacheEnt)
 }
 
-func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
+func (pc *cachingPermChecker) Check(ctx context.Context, uuid string) (bool, error) {
        pc.nChecks++
-       logger := logger(nil).
-               WithField("token", pc.Client.AuthToken).
+       logger := ctxlog.FromContext(ctx).
+               WithField("token", pc.token).
                WithField("uuid", uuid)
        pc.tidy()
        now := time.Now()
@@ -65,15 +68,19 @@ func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
                logger.WithField("allowed", perm.allowed).Debug("cache hit")
                return perm.allowed, nil
        }
-       var buf map[string]interface{}
-       path, err := pc.PathForUUID("get", uuid)
+
+       path, err := pc.ac.PathForUUID("get", uuid)
        if err != nil {
                pc.nInvalid++
                return false, err
        }
 
        pc.nMisses++
-       err = pc.RequestAndDecode(&buf, "GET", path, nil, url.Values{
+       ctx = arvados.ContextWithAuthorization(ctx, "Bearer "+pc.token)
+       ctx, cancel := context.WithDeadline(ctx, time.Now().Add(time.Minute))
+       defer cancel()
+       var buf map[string]interface{}
+       err = pc.ac.RequestAndDecodeContext(ctx, &buf, "GET", path, nil, url.Values{
                "include_trash": {"true"},
                "select":        {`["uuid"]`},
        })
@@ -84,6 +91,9 @@ func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
        } else if txErr, ok := err.(*arvados.TransactionError); ok && pc.isNotAllowed(txErr.StatusCode) {
                allowed = false
        } else {
+               // If "context deadline exceeded", "client
+               // disconnected", HTTP 5xx, network error, etc., don't
+               // cache the result.
                logger.WithError(err).Error("lookup error")
                return false, err
        }