mirror of https://github.com/portainer/portainer
70 lines
2.3 KiB
Go
70 lines
2.3 KiB
Go
package apikey
|
|
|
|
import (
|
|
lru "github.com/hashicorp/golang-lru"
|
|
portainer "github.com/portainer/portainer/api"
|
|
)
|
|
|
|
const defaultAPIKeyCacheSize = 1024
|
|
|
|
// entry is a tuple containing the user and API key associated to an API key digest
|
|
type entry struct {
|
|
user portainer.User
|
|
apiKey portainer.APIKey
|
|
}
|
|
|
|
// apiKeyCache is a concurrency-safe, in-memory cache which primarily exists for to reduce database roundtrips.
|
|
// We store the api-key digest (keys) and the associated user and key-data (values) in the cache.
|
|
// This is required because HTTP requests will contain only the api-key digest in the x-api-key request header;
|
|
// digest value must be mapped to a portainer user (and respective key data) for validation.
|
|
// This cache is used to avoid multiple database queries to retrieve these user/key associated to the digest.
|
|
type apiKeyCache struct {
|
|
// cache type [string]entry cache (key: string(digest), value: user/key entry)
|
|
// note: []byte keys are not supported by golang-lru Cache
|
|
cache *lru.Cache
|
|
}
|
|
|
|
// NewAPIKeyCache creates a new cache for API keys
|
|
func NewAPIKeyCache(cacheSize int) *apiKeyCache {
|
|
cache, _ := lru.New(cacheSize)
|
|
return &apiKeyCache{cache: cache}
|
|
}
|
|
|
|
// Get returns the user/key associated to an api-key's digest
|
|
// This is required because HTTP requests will contain the digest of the API key in header,
|
|
// the digest value must be mapped to a portainer user.
|
|
func (c *apiKeyCache) Get(digest []byte) (portainer.User, portainer.APIKey, bool) {
|
|
val, ok := c.cache.Get(string(digest))
|
|
if !ok {
|
|
return portainer.User{}, portainer.APIKey{}, false
|
|
}
|
|
tuple := val.(entry)
|
|
|
|
return tuple.user, tuple.apiKey, true
|
|
}
|
|
|
|
// Set persists a user/key entry to the cache
|
|
func (c *apiKeyCache) Set(digest []byte, user portainer.User, apiKey portainer.APIKey) {
|
|
c.cache.Add(string(digest), entry{
|
|
user: user,
|
|
apiKey: apiKey,
|
|
})
|
|
}
|
|
|
|
// Delete evicts a digest's user/key entry key from the cache
|
|
func (c *apiKeyCache) Delete(digest []byte) {
|
|
c.cache.Remove(string(digest))
|
|
}
|
|
|
|
// InvalidateUserKeyCache loops through all the api-keys associated to a user and removes them from the cache
|
|
func (c *apiKeyCache) InvalidateUserKeyCache(userId portainer.UserID) bool {
|
|
present := false
|
|
for _, k := range c.cache.Keys() {
|
|
user, _, _ := c.Get([]byte(k.(string)))
|
|
if user.ID == userId {
|
|
present = c.cache.Remove(k)
|
|
}
|
|
}
|
|
return present
|
|
}
|