X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/0c6cbd8a07e31decd703ef7fd9eca591e5661c32..0f644e242ef37c911ad3dc25aca8135c339de349:/services/ws/permission.go diff --git a/services/ws/permission.go b/services/ws/permission.go index 3f16a89cc6..b40c1fa186 100644 --- a/services/ws/permission.go +++ b/services/ws/permission.go @@ -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,24 +40,39 @@ 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) pc.tidy() now := time.Now() if perm, ok := pc.cache[uuid]; ok && now.Sub(perm.Time) < maxPermCacheAge { - debugLogf("perm (cached): %+q %+q => %s", pc.Client.AuthToken, uuid, perm.allowed) + logger.WithField("allowed", perm.allowed).Debug("cache hit") return perm.allowed, nil } 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"]`}, }) @@ -61,17 +80,26 @@ 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 { + } else if txErr, ok := err.(*arvados.TransactionError); ok && pc.isNotAllowed(txErr.StatusCode) { allowed = false } else { - errorLogf("perm err: %+q %+q: %s", pc.Client.AuthToken, uuid, err) + logger.WithError(err).Error("lookup error") return false, err } - debugLogf("perm: %+q %+q => %s", pc.Client.AuthToken, uuid, allowed) + logger.WithField("allowed", allowed).Debug("cache miss") pc.cache[uuid] = cacheEnt{Time: now, allowed: allowed} 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