1package acl
2
3// ChainedAuthorizer can combine multiple Authorizers into one.
4// Each Authorizer in the chain is asked (in order) for an
5// enforcement decision. The first non-Default decision that
6// is rendered by an Authorizer in the chain will be used
7// as the overall decision of the ChainedAuthorizer
8type ChainedAuthorizer struct {
9	chain []Authorizer
10}
11
12// NewChainedAuthorizer creates a ChainedAuthorizer with the provided
13// chain of Authorizers. The slice provided should be in the order of
14// most precedent Authorizer at the beginning and least precedent
15// Authorizer at the end.
16func NewChainedAuthorizer(chain []Authorizer) *ChainedAuthorizer {
17	return &ChainedAuthorizer{
18		chain: chain,
19	}
20}
21
22func (c *ChainedAuthorizer) AuthorizerChain() []Authorizer {
23	return c.chain
24}
25
26func (c *ChainedAuthorizer) executeChain(enforce func(authz Authorizer) EnforcementDecision) EnforcementDecision {
27	for _, authz := range c.chain {
28		decision := enforce(authz)
29		if decision != Default {
30			return decision
31		}
32	}
33	return Deny
34}
35
36// ACLRead checks for permission to list all the ACLs
37func (c *ChainedAuthorizer) ACLRead(entCtx *AuthorizerContext) EnforcementDecision {
38	return c.executeChain(func(authz Authorizer) EnforcementDecision {
39		return authz.ACLRead(entCtx)
40	})
41}
42
43// ACLWrite checks for permission to manipulate ACLs
44func (c *ChainedAuthorizer) ACLWrite(entCtx *AuthorizerContext) EnforcementDecision {
45	return c.executeChain(func(authz Authorizer) EnforcementDecision {
46		return authz.ACLWrite(entCtx)
47	})
48}
49
50// AgentRead checks for permission to read from agent endpoints for a
51// given node.
52func (c *ChainedAuthorizer) AgentRead(node string, entCtx *AuthorizerContext) EnforcementDecision {
53	return c.executeChain(func(authz Authorizer) EnforcementDecision {
54		return authz.AgentRead(node, entCtx)
55	})
56}
57
58// AgentWrite checks for permission to make changes via agent endpoints
59// for a given node.
60func (c *ChainedAuthorizer) AgentWrite(node string, entCtx *AuthorizerContext) EnforcementDecision {
61	return c.executeChain(func(authz Authorizer) EnforcementDecision {
62		return authz.AgentWrite(node, entCtx)
63	})
64}
65
66// EventRead determines if a specific event can be queried.
67func (c *ChainedAuthorizer) EventRead(name string, entCtx *AuthorizerContext) EnforcementDecision {
68	return c.executeChain(func(authz Authorizer) EnforcementDecision {
69		return authz.EventRead(name, entCtx)
70	})
71}
72
73// EventWrite determines if a specific event may be fired.
74func (c *ChainedAuthorizer) EventWrite(name string, entCtx *AuthorizerContext) EnforcementDecision {
75	return c.executeChain(func(authz Authorizer) EnforcementDecision {
76		return authz.EventWrite(name, entCtx)
77	})
78}
79
80// IntentionDefaultAllow determines the default authorized behavior
81// when no intentions match a Connect request.
82func (c *ChainedAuthorizer) IntentionDefaultAllow(entCtx *AuthorizerContext) EnforcementDecision {
83	return c.executeChain(func(authz Authorizer) EnforcementDecision {
84		return authz.IntentionDefaultAllow(entCtx)
85	})
86}
87
88// IntentionRead determines if a specific intention can be read.
89func (c *ChainedAuthorizer) IntentionRead(prefix string, entCtx *AuthorizerContext) EnforcementDecision {
90	return c.executeChain(func(authz Authorizer) EnforcementDecision {
91		return authz.IntentionRead(prefix, entCtx)
92	})
93}
94
95// IntentionWrite determines if a specific intention can be
96// created, modified, or deleted.
97func (c *ChainedAuthorizer) IntentionWrite(prefix string, entCtx *AuthorizerContext) EnforcementDecision {
98	return c.executeChain(func(authz Authorizer) EnforcementDecision {
99		return authz.IntentionWrite(prefix, entCtx)
100	})
101}
102
103// KeyList checks for permission to list keys under a prefix
104func (c *ChainedAuthorizer) KeyList(keyPrefix string, entCtx *AuthorizerContext) EnforcementDecision {
105	return c.executeChain(func(authz Authorizer) EnforcementDecision {
106		return authz.KeyList(keyPrefix, entCtx)
107	})
108}
109
110// KeyRead checks for permission to read a given key
111func (c *ChainedAuthorizer) KeyRead(key string, entCtx *AuthorizerContext) EnforcementDecision {
112	return c.executeChain(func(authz Authorizer) EnforcementDecision {
113		return authz.KeyRead(key, entCtx)
114	})
115}
116
117// KeyWrite checks for permission to write a given key
118func (c *ChainedAuthorizer) KeyWrite(key string, entCtx *AuthorizerContext) EnforcementDecision {
119	return c.executeChain(func(authz Authorizer) EnforcementDecision {
120		return authz.KeyWrite(key, entCtx)
121	})
122}
123
124// KeyWritePrefix checks for permission to write to an
125// entire key prefix. This means there must be no sub-policies
126// that deny a write.
127func (c *ChainedAuthorizer) KeyWritePrefix(keyPrefix string, entCtx *AuthorizerContext) EnforcementDecision {
128	return c.executeChain(func(authz Authorizer) EnforcementDecision {
129		return authz.KeyWritePrefix(keyPrefix, entCtx)
130	})
131}
132
133// KeyringRead determines if the encryption keyring used in
134// the gossip layer can be read.
135func (c *ChainedAuthorizer) KeyringRead(entCtx *AuthorizerContext) EnforcementDecision {
136	return c.executeChain(func(authz Authorizer) EnforcementDecision {
137		return authz.KeyringRead(entCtx)
138	})
139}
140
141// KeyringWrite determines if the keyring can be manipulated
142func (c *ChainedAuthorizer) KeyringWrite(entCtx *AuthorizerContext) EnforcementDecision {
143	return c.executeChain(func(authz Authorizer) EnforcementDecision {
144		return authz.KeyringWrite(entCtx)
145	})
146}
147
148// NodeRead checks for permission to read (discover) a given node.
149func (c *ChainedAuthorizer) NodeRead(node string, entCtx *AuthorizerContext) EnforcementDecision {
150	return c.executeChain(func(authz Authorizer) EnforcementDecision {
151		return authz.NodeRead(node, entCtx)
152	})
153}
154
155// NodeWrite checks for permission to create or update (register) a
156// given node.
157func (c *ChainedAuthorizer) NodeWrite(node string, entCtx *AuthorizerContext) EnforcementDecision {
158	return c.executeChain(func(authz Authorizer) EnforcementDecision {
159		return authz.NodeWrite(node, entCtx)
160	})
161}
162
163// OperatorRead determines if the read-only Consul operator functions
164// can be used.
165func (c *ChainedAuthorizer) OperatorRead(entCtx *AuthorizerContext) EnforcementDecision {
166	return c.executeChain(func(authz Authorizer) EnforcementDecision {
167		return authz.OperatorRead(entCtx)
168	})
169}
170
171// OperatorWrite determines if the state-changing Consul operator
172// functions can be used.
173func (c *ChainedAuthorizer) OperatorWrite(entCtx *AuthorizerContext) EnforcementDecision {
174	return c.executeChain(func(authz Authorizer) EnforcementDecision {
175		return authz.OperatorWrite(entCtx)
176	})
177}
178
179// PreparedQueryRead determines if a specific prepared query can be read
180// to show its contents (this is not used for execution).
181func (c *ChainedAuthorizer) PreparedQueryRead(query string, entCtx *AuthorizerContext) EnforcementDecision {
182	return c.executeChain(func(authz Authorizer) EnforcementDecision {
183		return authz.PreparedQueryRead(query, entCtx)
184	})
185}
186
187// PreparedQueryWrite determines if a specific prepared query can be
188// created, modified, or deleted.
189func (c *ChainedAuthorizer) PreparedQueryWrite(query string, entCtx *AuthorizerContext) EnforcementDecision {
190	return c.executeChain(func(authz Authorizer) EnforcementDecision {
191		return authz.PreparedQueryWrite(query, entCtx)
192	})
193}
194
195// ServiceRead checks for permission to read a given service
196func (c *ChainedAuthorizer) ServiceRead(name string, entCtx *AuthorizerContext) EnforcementDecision {
197	return c.executeChain(func(authz Authorizer) EnforcementDecision {
198		return authz.ServiceRead(name, entCtx)
199	})
200}
201
202// ServiceWrite checks for permission to create or update a given
203// service
204func (c *ChainedAuthorizer) ServiceWrite(name string, entCtx *AuthorizerContext) EnforcementDecision {
205	return c.executeChain(func(authz Authorizer) EnforcementDecision {
206		return authz.ServiceWrite(name, entCtx)
207	})
208}
209
210// SessionRead checks for permission to read sessions for a given node.
211func (c *ChainedAuthorizer) SessionRead(node string, entCtx *AuthorizerContext) EnforcementDecision {
212	return c.executeChain(func(authz Authorizer) EnforcementDecision {
213		return authz.SessionRead(node, entCtx)
214	})
215}
216
217// SessionWrite checks for permission to create sessions for a given
218// node.
219func (c *ChainedAuthorizer) SessionWrite(node string, entCtx *AuthorizerContext) EnforcementDecision {
220	return c.executeChain(func(authz Authorizer) EnforcementDecision {
221		return authz.SessionWrite(node, entCtx)
222	})
223}
224
225// Snapshot checks for permission to take and restore snapshots.
226func (c *ChainedAuthorizer) Snapshot(entCtx *AuthorizerContext) EnforcementDecision {
227	return c.executeChain(func(authz Authorizer) EnforcementDecision {
228		return authz.Snapshot(entCtx)
229	})
230}
231