2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2018-10-19 16:04:07 +00:00
|
|
|
package structs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
2019-04-15 20:43:19 +00:00
|
|
|
lru "github.com/hashicorp/golang-lru"
|
2021-09-22 23:13:55 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/consul/acl"
|
2018-10-19 16:04:07 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type ACLCachesConfig struct {
|
|
|
|
Identities int
|
|
|
|
Policies int
|
|
|
|
ParsedPolicies int
|
|
|
|
Authorizers int
|
2019-04-15 20:43:19 +00:00
|
|
|
Roles int
|
2018-10-19 16:04:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type ACLCaches struct {
|
|
|
|
identities *lru.TwoQueueCache // identity id -> structs.ACLIdentity
|
|
|
|
parsedPolicies *lru.TwoQueueCache // policy content hash -> acl.Policy
|
|
|
|
policies *lru.TwoQueueCache // policy ID -> ACLPolicy
|
|
|
|
authorizers *lru.TwoQueueCache // token secret -> acl.Authorizer
|
2019-04-15 20:43:19 +00:00
|
|
|
roles *lru.TwoQueueCache // role ID -> ACLRole
|
2018-10-19 16:04:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type IdentityCacheEntry struct {
|
|
|
|
Identity ACLIdentity
|
|
|
|
CacheTime time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *IdentityCacheEntry) Age() time.Duration {
|
|
|
|
return time.Since(e.CacheTime)
|
|
|
|
}
|
|
|
|
|
|
|
|
type ParsedPolicyCacheEntry struct {
|
|
|
|
Policy *acl.Policy
|
|
|
|
CacheTime time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *ParsedPolicyCacheEntry) Age() time.Duration {
|
|
|
|
return time.Since(e.CacheTime)
|
|
|
|
}
|
|
|
|
|
|
|
|
type PolicyCacheEntry struct {
|
|
|
|
Policy *ACLPolicy
|
|
|
|
CacheTime time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *PolicyCacheEntry) Age() time.Duration {
|
|
|
|
return time.Since(e.CacheTime)
|
|
|
|
}
|
|
|
|
|
|
|
|
type AuthorizerCacheEntry struct {
|
|
|
|
Authorizer acl.Authorizer
|
|
|
|
CacheTime time.Time
|
|
|
|
TTL time.Duration
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *AuthorizerCacheEntry) Age() time.Duration {
|
|
|
|
return time.Since(e.CacheTime)
|
|
|
|
}
|
|
|
|
|
2019-04-15 20:43:19 +00:00
|
|
|
type RoleCacheEntry struct {
|
|
|
|
Role *ACLRole
|
|
|
|
CacheTime time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *RoleCacheEntry) Age() time.Duration {
|
|
|
|
return time.Since(e.CacheTime)
|
|
|
|
}
|
|
|
|
|
2018-10-19 16:04:07 +00:00
|
|
|
func NewACLCaches(config *ACLCachesConfig) (*ACLCaches, error) {
|
|
|
|
cache := &ACLCaches{}
|
|
|
|
|
|
|
|
if config != nil && config.Identities > 0 {
|
|
|
|
identCache, err := lru.New2Q(config.Identities)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cache.identities = identCache
|
|
|
|
}
|
|
|
|
|
|
|
|
if config != nil && config.Policies > 0 {
|
|
|
|
policyCache, err := lru.New2Q(config.Policies)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cache.policies = policyCache
|
|
|
|
}
|
|
|
|
|
|
|
|
if config != nil && config.ParsedPolicies > 0 {
|
|
|
|
parsedCache, err := lru.New2Q(config.ParsedPolicies)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cache.parsedPolicies = parsedCache
|
|
|
|
}
|
|
|
|
|
|
|
|
if config != nil && config.Authorizers > 0 {
|
|
|
|
authCache, err := lru.New2Q(config.Authorizers)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cache.authorizers = authCache
|
|
|
|
}
|
|
|
|
|
2019-04-15 20:43:19 +00:00
|
|
|
if config != nil && config.Roles > 0 {
|
|
|
|
roleCache, err := lru.New2Q(config.Roles)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cache.roles = roleCache
|
|
|
|
}
|
|
|
|
|
2018-10-19 16:04:07 +00:00
|
|
|
return cache, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetIdentity fetches an identity from the cache and returns it
|
|
|
|
func (c *ACLCaches) GetIdentity(id string) *IdentityCacheEntry {
|
|
|
|
if c == nil || c.identities == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if raw, ok := c.identities.Get(id); ok {
|
|
|
|
return raw.(*IdentityCacheEntry)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-05-04 16:38:45 +00:00
|
|
|
// GetIdentityWithSecretToken fetches the identity with the given secret token
|
|
|
|
// from the cache.
|
|
|
|
func (c *ACLCaches) GetIdentityWithSecretToken(secretToken string) *IdentityCacheEntry {
|
|
|
|
return c.GetIdentity(cacheIDSecretToken(secretToken))
|
|
|
|
}
|
|
|
|
|
2018-10-19 16:04:07 +00:00
|
|
|
// GetPolicy fetches a policy from the cache and returns it
|
|
|
|
func (c *ACLCaches) GetPolicy(policyID string) *PolicyCacheEntry {
|
|
|
|
if c == nil || c.policies == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if raw, ok := c.policies.Get(policyID); ok {
|
|
|
|
return raw.(*PolicyCacheEntry)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPolicy fetches a policy from the cache and returns it
|
|
|
|
func (c *ACLCaches) GetParsedPolicy(id string) *ParsedPolicyCacheEntry {
|
|
|
|
if c == nil || c.parsedPolicies == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if raw, ok := c.parsedPolicies.Get(id); ok {
|
|
|
|
return raw.(*ParsedPolicyCacheEntry)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetAuthorizer fetches a acl from the cache and returns it
|
|
|
|
func (c *ACLCaches) GetAuthorizer(id string) *AuthorizerCacheEntry {
|
|
|
|
if c == nil || c.authorizers == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if raw, ok := c.authorizers.Get(id); ok {
|
|
|
|
return raw.(*AuthorizerCacheEntry)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-04-26 17:49:28 +00:00
|
|
|
// GetRole fetches a role from the cache by id and returns it
|
2019-04-15 20:43:19 +00:00
|
|
|
func (c *ACLCaches) GetRole(roleID string) *RoleCacheEntry {
|
|
|
|
if c == nil || c.roles == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if raw, ok := c.roles.Get(roleID); ok {
|
|
|
|
return raw.(*RoleCacheEntry)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-10-19 16:04:07 +00:00
|
|
|
// PutIdentity adds a new identity to the cache
|
2022-05-04 16:38:45 +00:00
|
|
|
func (c *ACLCaches) PutIdentity(id string, ident ACLIdentity) {
|
|
|
|
if c == nil || c.identities == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.identities.Add(id, &IdentityCacheEntry{Identity: ident, CacheTime: time.Now()})
|
|
|
|
}
|
|
|
|
|
|
|
|
// PutIdentityWithSecretToken adds a new identity to the cache, keyed by the
|
|
|
|
// given secret token (with a prefix to prevent collisions).
|
|
|
|
func (c *ACLCaches) PutIdentityWithSecretToken(secretToken string, identity ACLIdentity) {
|
|
|
|
c.PutIdentity(cacheIDSecretToken(secretToken), identity)
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveIdentityWithSecretToken removes the identity from the cache with the
|
|
|
|
// given secret token.
|
|
|
|
func (c *ACLCaches) RemoveIdentityWithSecretToken(secretToken string) {
|
2018-10-19 16:04:07 +00:00
|
|
|
if c == nil || c.identities == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-05-04 16:38:45 +00:00
|
|
|
c.identities.Remove(cacheIDSecretToken(secretToken))
|
2018-10-19 16:04:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ACLCaches) PutPolicy(policyId string, policy *ACLPolicy) {
|
|
|
|
if c == nil || c.policies == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.policies.Add(policyId, &PolicyCacheEntry{Policy: policy, CacheTime: time.Now()})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ACLCaches) PutParsedPolicy(id string, policy *acl.Policy) {
|
|
|
|
if c == nil || c.parsedPolicies == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.parsedPolicies.Add(id, &ParsedPolicyCacheEntry{Policy: policy, CacheTime: time.Now()})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ACLCaches) PutAuthorizer(id string, authorizer acl.Authorizer) {
|
|
|
|
if c == nil || c.authorizers == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.authorizers.Add(id, &AuthorizerCacheEntry{Authorizer: authorizer, CacheTime: time.Now()})
|
|
|
|
}
|
|
|
|
|
2019-04-15 20:43:19 +00:00
|
|
|
func (c *ACLCaches) PutRole(roleID string, role *ACLRole) {
|
2019-04-26 17:49:28 +00:00
|
|
|
if c == nil || c.roles == nil {
|
|
|
|
return
|
2019-04-15 20:43:19 +00:00
|
|
|
}
|
2019-04-26 17:49:28 +00:00
|
|
|
|
|
|
|
c.roles.Add(roleID, &RoleCacheEntry{Role: role, CacheTime: time.Now()})
|
2019-04-15 20:43:19 +00:00
|
|
|
}
|
|
|
|
|
2018-10-19 16:04:07 +00:00
|
|
|
func (c *ACLCaches) RemoveIdentity(id string) {
|
|
|
|
if c != nil && c.identities != nil {
|
|
|
|
c.identities.Remove(id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ACLCaches) RemovePolicy(policyID string) {
|
|
|
|
if c != nil && c.policies != nil {
|
|
|
|
c.policies.Remove(policyID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-15 20:43:19 +00:00
|
|
|
func (c *ACLCaches) RemoveRole(roleID string) {
|
2019-04-26 17:49:28 +00:00
|
|
|
if c != nil && c.roles != nil {
|
2019-04-15 20:43:19 +00:00
|
|
|
c.roles.Remove(roleID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-19 16:04:07 +00:00
|
|
|
func (c *ACLCaches) Purge() {
|
|
|
|
if c != nil {
|
|
|
|
if c.identities != nil {
|
|
|
|
c.identities.Purge()
|
|
|
|
}
|
|
|
|
if c.policies != nil {
|
|
|
|
c.policies.Purge()
|
|
|
|
}
|
|
|
|
if c.parsedPolicies != nil {
|
|
|
|
c.parsedPolicies.Purge()
|
|
|
|
}
|
|
|
|
if c.authorizers != nil {
|
|
|
|
c.authorizers.Purge()
|
|
|
|
}
|
2019-04-15 20:43:19 +00:00
|
|
|
if c.roles != nil {
|
|
|
|
c.roles.Purge()
|
|
|
|
}
|
2018-10-19 16:04:07 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-04 16:38:45 +00:00
|
|
|
|
|
|
|
func cacheIDSecretToken(token string) string {
|
|
|
|
return "token-secret:" + token
|
|
|
|
}
|