Merge branch '8784-dir-listings'
[arvados.git] / services / ws / permission.go
index 42f7b374331e60d46e7b4aeae56cbfe5abac265b..b40c1fa1863219048a2ba70f8b2afb1ffc394391 100644 (file)
@@ -1,3 +1,7 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
 package main
 
 import (
@@ -18,7 +22,7 @@ type permChecker interface {
        Check(uuid string) (bool, error)
 }
 
-func NewPermChecker(ac arvados.Client) permChecker {
+func newPermChecker(ac arvados.Client) permChecker {
        ac.AuthToken = ""
        return &cachingPermChecker{
                Client:     &ac,
@@ -36,13 +40,22 @@ type cachingPermChecker struct {
        *arvados.Client
        cache      map[string]cacheEnt
        maxCurrent int
+
+       nChecks  uint64
+       nMisses  uint64
+       nInvalid uint64
 }
 
 func (pc *cachingPermChecker) SetToken(token string) {
+       if pc.Client.AuthToken == token {
+               return
+       }
        pc.Client.AuthToken = token
+       pc.cache = make(map[string]cacheEnt)
 }
 
 func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
+       pc.nChecks++
        logger := logger(nil).
                WithField("token", pc.Client.AuthToken).
                WithField("uuid", uuid)
@@ -55,8 +68,11 @@ func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
        var buf map[string]interface{}
        path, err := pc.PathForUUID("get", uuid)
        if err != nil {
+               pc.nInvalid++
                return false, err
        }
+
+       pc.nMisses++
        err = pc.RequestAndDecode(&buf, "GET", path, nil, url.Values{
                "select": {`["uuid"]`},
        })
@@ -64,12 +80,7 @@ func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
        var allowed bool
        if err == nil {
                allowed = true
-       } else if txErr, ok := err.(*arvados.TransactionError); ok && txErr.StatusCode == http.StatusNotFound {
-               allowed = false
-       } else if txErr.StatusCode == http.StatusForbidden {
-               // Some requests are expressly forbidden for reasons
-               // other than "you aren't allowed to know whether this
-               // UUID exists" (404).
+       } else if txErr, ok := err.(*arvados.TransactionError); ok && pc.isNotAllowed(txErr.StatusCode) {
                allowed = false
        } else {
                logger.WithError(err).Error("lookup error")
@@ -80,6 +91,15 @@ func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
        return allowed, nil
 }
 
+func (pc *cachingPermChecker) isNotAllowed(status int) bool {
+       switch status {
+       case http.StatusForbidden, http.StatusUnauthorized, http.StatusNotFound:
+               return true
+       default:
+               return false
+       }
+}
+
 func (pc *cachingPermChecker) tidy() {
        if len(pc.cache) <= pc.maxCurrent*2 {
                return