1package structs
2
3import (
4	"time"
5
6	"github.com/hashicorp/consul/acl"
7	lru "github.com/hashicorp/golang-lru"
8)
9
10type ACLCachesConfig struct {
11	Identities     int
12	Policies       int
13	ParsedPolicies int
14	Authorizers    int
15	Roles          int
16}
17
18type ACLCaches struct {
19	identities     *lru.TwoQueueCache // identity id -> structs.ACLIdentity
20	parsedPolicies *lru.TwoQueueCache // policy content hash -> acl.Policy
21	policies       *lru.TwoQueueCache // policy ID -> ACLPolicy
22	authorizers    *lru.TwoQueueCache // token secret -> acl.Authorizer
23	roles          *lru.TwoQueueCache // role ID -> ACLRole
24}
25
26type IdentityCacheEntry struct {
27	Identity  ACLIdentity
28	CacheTime time.Time
29}
30
31func (e *IdentityCacheEntry) Age() time.Duration {
32	return time.Since(e.CacheTime)
33}
34
35type ParsedPolicyCacheEntry struct {
36	Policy    *acl.Policy
37	CacheTime time.Time
38}
39
40func (e *ParsedPolicyCacheEntry) Age() time.Duration {
41	return time.Since(e.CacheTime)
42}
43
44type PolicyCacheEntry struct {
45	Policy    *ACLPolicy
46	CacheTime time.Time
47}
48
49func (e *PolicyCacheEntry) Age() time.Duration {
50	return time.Since(e.CacheTime)
51}
52
53type AuthorizerCacheEntry struct {
54	Authorizer acl.Authorizer
55	CacheTime  time.Time
56	TTL        time.Duration
57}
58
59func (e *AuthorizerCacheEntry) Age() time.Duration {
60	return time.Since(e.CacheTime)
61}
62
63type RoleCacheEntry struct {
64	Role      *ACLRole
65	CacheTime time.Time
66}
67
68func (e *RoleCacheEntry) Age() time.Duration {
69	return time.Since(e.CacheTime)
70}
71
72func NewACLCaches(config *ACLCachesConfig) (*ACLCaches, error) {
73	cache := &ACLCaches{}
74
75	if config != nil && config.Identities > 0 {
76		identCache, err := lru.New2Q(config.Identities)
77		if err != nil {
78			return nil, err
79		}
80
81		cache.identities = identCache
82	}
83
84	if config != nil && config.Policies > 0 {
85		policyCache, err := lru.New2Q(config.Policies)
86		if err != nil {
87			return nil, err
88		}
89
90		cache.policies = policyCache
91	}
92
93	if config != nil && config.ParsedPolicies > 0 {
94		parsedCache, err := lru.New2Q(config.ParsedPolicies)
95		if err != nil {
96			return nil, err
97		}
98
99		cache.parsedPolicies = parsedCache
100	}
101
102	if config != nil && config.Authorizers > 0 {
103		authCache, err := lru.New2Q(config.Authorizers)
104		if err != nil {
105			return nil, err
106		}
107
108		cache.authorizers = authCache
109	}
110
111	if config != nil && config.Roles > 0 {
112		roleCache, err := lru.New2Q(config.Roles)
113		if err != nil {
114			return nil, err
115		}
116
117		cache.roles = roleCache
118	}
119
120	return cache, nil
121}
122
123// GetIdentity fetches an identity from the cache and returns it
124func (c *ACLCaches) GetIdentity(id string) *IdentityCacheEntry {
125	if c == nil || c.identities == nil {
126		return nil
127	}
128
129	if raw, ok := c.identities.Get(id); ok {
130		return raw.(*IdentityCacheEntry)
131	}
132
133	return nil
134}
135
136// GetPolicy fetches a policy from the cache and returns it
137func (c *ACLCaches) GetPolicy(policyID string) *PolicyCacheEntry {
138	if c == nil || c.policies == nil {
139		return nil
140	}
141
142	if raw, ok := c.policies.Get(policyID); ok {
143		return raw.(*PolicyCacheEntry)
144	}
145
146	return nil
147}
148
149// GetPolicy fetches a policy from the cache and returns it
150func (c *ACLCaches) GetParsedPolicy(id string) *ParsedPolicyCacheEntry {
151	if c == nil || c.parsedPolicies == nil {
152		return nil
153	}
154
155	if raw, ok := c.parsedPolicies.Get(id); ok {
156		return raw.(*ParsedPolicyCacheEntry)
157	}
158
159	return nil
160}
161
162// GetAuthorizer fetches a acl from the cache and returns it
163func (c *ACLCaches) GetAuthorizer(id string) *AuthorizerCacheEntry {
164	if c == nil || c.authorizers == nil {
165		return nil
166	}
167
168	if raw, ok := c.authorizers.Get(id); ok {
169		return raw.(*AuthorizerCacheEntry)
170	}
171
172	return nil
173}
174
175// GetRole fetches a role from the cache by id and returns it
176func (c *ACLCaches) GetRole(roleID string) *RoleCacheEntry {
177	if c == nil || c.roles == nil {
178		return nil
179	}
180
181	if raw, ok := c.roles.Get(roleID); ok {
182		return raw.(*RoleCacheEntry)
183	}
184
185	return nil
186}
187
188// PutIdentity adds a new identity to the cache
189func (c *ACLCaches) PutIdentity(id string, ident ACLIdentity) {
190	if c == nil || c.identities == nil {
191		return
192	}
193
194	c.identities.Add(id, &IdentityCacheEntry{Identity: ident, CacheTime: time.Now()})
195}
196
197func (c *ACLCaches) PutPolicy(policyId string, policy *ACLPolicy) {
198	if c == nil || c.policies == nil {
199		return
200	}
201
202	c.policies.Add(policyId, &PolicyCacheEntry{Policy: policy, CacheTime: time.Now()})
203}
204
205func (c *ACLCaches) PutParsedPolicy(id string, policy *acl.Policy) {
206	if c == nil || c.parsedPolicies == nil {
207		return
208	}
209
210	c.parsedPolicies.Add(id, &ParsedPolicyCacheEntry{Policy: policy, CacheTime: time.Now()})
211}
212
213func (c *ACLCaches) PutAuthorizer(id string, authorizer acl.Authorizer) {
214	if c == nil || c.authorizers == nil {
215		return
216	}
217
218	c.authorizers.Add(id, &AuthorizerCacheEntry{Authorizer: authorizer, CacheTime: time.Now()})
219}
220
221func (c *ACLCaches) PutAuthorizerWithTTL(id string, authorizer acl.Authorizer, ttl time.Duration) {
222	if c == nil || c.authorizers == nil {
223		return
224	}
225
226	c.authorizers.Add(id, &AuthorizerCacheEntry{Authorizer: authorizer, CacheTime: time.Now(), TTL: ttl})
227}
228
229func (c *ACLCaches) PutRole(roleID string, role *ACLRole) {
230	if c == nil || c.roles == nil {
231		return
232	}
233
234	c.roles.Add(roleID, &RoleCacheEntry{Role: role, CacheTime: time.Now()})
235}
236
237func (c *ACLCaches) RemoveIdentity(id string) {
238	if c != nil && c.identities != nil {
239		c.identities.Remove(id)
240	}
241}
242
243func (c *ACLCaches) RemovePolicy(policyID string) {
244	if c != nil && c.policies != nil {
245		c.policies.Remove(policyID)
246	}
247}
248
249func (c *ACLCaches) RemoveRole(roleID string) {
250	if c != nil && c.roles != nil {
251		c.roles.Remove(roleID)
252	}
253}
254
255func (c *ACLCaches) Purge() {
256	if c != nil {
257		if c.identities != nil {
258			c.identities.Purge()
259		}
260		if c.policies != nil {
261			c.policies.Purge()
262		}
263		if c.parsedPolicies != nil {
264			c.parsedPolicies.Purge()
265		}
266		if c.authorizers != nil {
267			c.authorizers.Purge()
268		}
269		if c.roles != nil {
270			c.roles.Purge()
271		}
272	}
273}
274