xref: /5.5.2/ns_server/src/menelaus_roles.erl (revision 542f6c62)
1%% @author Couchbase <info@couchbase.com>
2%% @copyright 2016-2018 Couchbase, Inc.
3%%
4%% Licensed under the Apache License, Version 2.0 (the "License");
5%% you may not use this file except in compliance with the License.
6%% You may obtain a copy of the License at
7%%
8%%      http://www.apache.org/licenses/LICENSE-2.0
9%%
10%% Unless required by applicable law or agreed to in writing, software
11%% distributed under the License is distributed on an "AS IS" BASIS,
12%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13%% See the License for the specific language governing permissions and
14%% limitations under the License.
15%%
16%% 1. Permission is defined as a pair {object, operation}
17%% 2. Objects are organized in the tree structure with common root []
18%% 3. One vertex of this tree can be parametrized: {bucket, bucket_name},
19%%    wildcard all can be used in place of bucket_name
20%% 4. Permission pattern is a pair {Object pattern, Allowed operations}
21%% 5. Allowed operations can be list of operations, all or none
22%% 6. Object pattern is a list of vertices that define a certain subtree of the objects tree
23%% 7. Object pattern vertex {bucket, bucket_name} always matches object vertex {bucket, any},
24%%    object pattern vertex {bucket, any} matches {bucket, bucket_name} with any bucket_name
25%%    otherwise vertices match if they are equal
26%% 8. Object matches the object pattern if all the vertices of object pattern match
27%%    corresponding vertices of the object.
28%% 9. Each role is defined as a list of permission patterns.
29%% 10.To find which operations are allowed for certain object in certain role we look for the
30%%    first permission pattern with matching object pattern in the permission pattern list of
31%%    the role.
32%% 11.The permission is allowed by the role if its operation is among the allowed operations
33%%    for its object.
34%% 12.Each user can have multiple roles assigned
35%% 13.Certain permission is allowed to the user if it is allowed at least by one of the roles
36%%    assigned to user.
37
38%% @doc roles and permissions implementation
39
40-module(menelaus_roles).
41
42-include("ns_common.hrl").
43-include("ns_config.hrl").
44-include("rbac.hrl").
45-include("pipes.hrl").
46
47-include_lib("eunit/include/eunit.hrl").
48
49-export([get_definitions/0,
50         get_definitions/1,
51         roles_45/0,
52         is_allowed/2,
53         get_roles/1,
54         get_compiled_roles/1,
55         compile_roles/3,
56         validate_roles/2,
57         calculate_possible_param_values/1,
58         filter_out_invalid_roles/3,
59         produce_roles_by_permission/3,
60         get_security_roles/0]).
61
62-export([start_compiled_roles_cache/0]).
63
64%% for RPC from ns_couchdb node
65-export([build_compiled_roles/1]).
66
67-spec roles_45() -> [rbac_role_def(), ...].
68roles_45() ->
69    [{admin, [],
70      [{name, <<"Admin">>},
71       {desc, <<"Can manage ALL cluster features including security.">>}],
72      [{[], all}]},
73     {ro_admin, [],
74      [{name, <<"Read Only Admin">>},
75       {desc, <<"Can view ALL cluster features.">>}],
76      [{[{bucket, any}, password], none},
77       {[{bucket, any}, data], none},
78       {[admin, security], [read]},
79       {[admin], none},
80       {[], [read]}]},
81     {cluster_admin, [],
82      [{name, <<"Cluster Admin">>},
83       {desc, <<"Can manage all cluster features EXCEPT security.">>}],
84      [{[admin], none},
85       {[n1ql, curl], none},
86       {[], all}]},
87     {bucket_admin, [bucket_name],
88      [{name, <<"Bucket Admin">>},
89       {desc, <<"Can manage ALL bucket features for specified buckets (incl. start/stop XDCR)">>}],
90      [{[{bucket, bucket_name}, xdcr], [read, execute]},
91       {[{bucket, bucket_name}], all},
92       {[{bucket, any}, settings], [read]},
93       {[{bucket, any}], none},
94       {[xdcr], none},
95       {[admin], none},
96       {[], [read]}]},
97     {bucket_full_access, [bucket_name],
98      [],
99      [{[{bucket, bucket_name}, data], all},
100       {[{bucket, bucket_name}, views], all},
101       {[{bucket, bucket_name}, n1ql, index], all},
102       {[{bucket, bucket_name}, n1ql], [execute]},
103       {[{bucket, bucket_name}], [read, flush]},
104       {[{bucket, bucket_name}, settings], [read]},
105       {[pools], [read]}]},
106     {views_admin, [bucket_name],
107      [{name, <<"Views Admin">>},
108       {desc, <<"Can manage views for specified buckets">>}],
109      [{[{bucket, bucket_name}, views], all},
110       {[{bucket, bucket_name}, data], [read]},
111       {[{bucket, any}, settings], [read]},
112       {[{bucket, any}], none},
113       {[{bucket, bucket_name}, n1ql], [execute]},
114       {[xdcr], none},
115       {[admin], none},
116       {[], [read]}]},
117     {replication_admin, [],
118      [{name, <<"Replication Admin">>},
119       {desc, <<"Can manage ONLY XDCR features (cluster AND bucket level)">>}],
120      [{[{bucket, any}, xdcr], all},
121       {[{bucket, any}, data], [read]},
122       {[{bucket, any}, settings], [read]},
123       {[{bucket, any}], none},
124       {[xdcr], all},
125       {[admin], none},
126       {[], [read]}]}].
127
128-spec roles_50() -> [rbac_role_def(), ...].
129roles_50() ->
130    [{admin, [],
131      [{name, <<"Admin">>},
132       {desc, <<"Can manage ALL cluster features including security.">>},
133       {ce, true}],
134      [{[], all}]},
135     {ro_admin, [],
136      [{name, <<"Read Only Admin">>},
137       {desc, <<"Can view ALL cluster features.">>},
138       {ce, true}],
139      [{[{bucket, any}, password], none},
140       {[{bucket, any}, data], none},
141       {[admin, security], [read]},
142       {[admin], none},
143       {[], [read, list]}]},
144     {cluster_admin, [],
145      [{name, <<"Cluster Admin">>},
146       {desc, <<"Can manage all cluster features EXCEPT security.">>}],
147      [{[admin, internal], none},
148       {[admin, security], none},
149       {[admin, diag], read},
150       {[n1ql, curl], none},
151       {[], all}]},
152     {bucket_admin, [bucket_name],
153      [{name, <<"Bucket Admin">>},
154       {desc, <<"Can manage ALL bucket features for specified buckets (incl. start/stop XDCR)">>}],
155      [{[{bucket, bucket_name}, xdcr], [read, execute]},
156       {[{bucket, bucket_name}], all},
157       {[{bucket, any}, settings], [read]},
158       {[{bucket, any}], none},
159       {[xdcr], none},
160       {[admin], none},
161       {[], [read]}]},
162     {bucket_full_access, [bucket_name],
163      [{name, <<"Bucket Full Access">>},
164       {desc, <<"Full access to bucket data">>},
165       {ce, true}],
166      [{[{bucket, bucket_name}, data], all},
167       {[{bucket, bucket_name}, views], all},
168       {[{bucket, bucket_name}, n1ql, index], all},
169       {[{bucket, bucket_name}, n1ql], [execute]},
170       {[{bucket, bucket_name}], [read, flush]},
171       {[{bucket, bucket_name}, settings], [read]},
172       {[pools], [read]}]},
173     {views_admin, [bucket_name],
174      [{name, <<"Views Admin">>},
175       {desc, <<"Can manage views for specified buckets">>}],
176      [{[{bucket, bucket_name}, views], all},
177       {[{bucket, bucket_name}, data], [read]},
178       {[{bucket, any}, settings], [read]},
179       {[{bucket, any}], none},
180       {[{bucket, bucket_name}, n1ql], [execute]},
181       {[xdcr], none},
182       {[admin], none},
183       {[], [read]}]},
184     {views_reader, [bucket_name],
185      [{name, <<"Views Reader">>},
186       {desc, <<"Can read data from the views of specified bucket">>}],
187      [{[{bucket, bucket_name}, views], [read]},
188       {[{bucket, bucket_name}, data, docs], [read]},
189       {[pools], [read]}]},
190     {replication_admin, [],
191      [{name, <<"Replication Admin">>},
192       {desc, <<"Can manage ONLY XDCR features (cluster AND bucket level)">>}],
193      [{[{bucket, any}, xdcr], all},
194       {[{bucket, any}, data], [read]},
195       {[{bucket, any}, settings], [read]},
196       {[{bucket, any}], none},
197       {[xdcr], all},
198       {[admin], none},
199       {[], [read]}]},
200     {data_reader, [bucket_name],
201      [{name, <<"Data Reader">>},
202       {desc, <<"Can read information from specified bucket">>}],
203      [{[{bucket, bucket_name}, data, docs], [read]},
204       {[{bucket, bucket_name}, data, meta], [read]},
205       {[{bucket, bucket_name}, data, xattr], [read]},
206       {[{bucket, bucket_name}, settings], [read]},
207       {[pools], [read]}]},
208     {data_writer, [bucket_name],
209      [{name, <<"Data Writer">>},
210       {desc, <<"Can write information from/to specified bucket">>}],
211      [{[{bucket, bucket_name}, data, docs], [insert, upsert, delete]},
212       {[{bucket, bucket_name}, data, xattr], [write]},
213       {[{bucket, bucket_name}, settings], [read]},
214       {[pools], [read]}]},
215     {data_dcp_reader, [bucket_name],
216      [{name, <<"Data DCP Reader">>},
217       {desc, <<"Can read DCP data streams">>}],
218      [{[{bucket, bucket_name}, data, docs], [read]},
219       {[{bucket, bucket_name}, data, meta], [read]},
220       {[{bucket, bucket_name}, data, dcp], [read]},
221       {[{bucket, bucket_name}, data, sxattr], [read]},
222       {[{bucket, bucket_name}, data, xattr], [read]},
223       {[{bucket, bucket_name}, settings], [read]},
224       {[admin, memcached, idle], [write]},
225       {[pools], [read]}]},
226     {data_backup, [bucket_name],
227      [{name, <<"Data Backup">>},
228       {desc, <<"Can backup and restore bucket data">>}],
229      [{[{bucket, bucket_name}, data], all},
230       {[{bucket, bucket_name}, views], [read, write]},
231       {[{bucket, bucket_name}, fts], [read, write, manage]},
232       {[{bucket, bucket_name}, stats], [read]},
233       {[{bucket, bucket_name}, settings], [read]},
234       {[{bucket, bucket_name}, n1ql, index], [create, list, build]},
235       {[pools], [read]}]},
236     {data_monitoring, [bucket_name],
237      [{name, <<"Data Monitoring">>},
238       {desc, <<"Can read full bucket stats">>}],
239      [{[{bucket, bucket_name}, stats], [read]},
240       {[{bucket, bucket_name}, settings], [read]},
241       {[pools], [read]}]},
242     {fts_admin, [bucket_name],
243      [{name, <<"FTS Admin">>},
244       {desc, <<"Can administer all FTS features">>}],
245      [{[{bucket, bucket_name}, fts], [read, write, manage]},
246       {[settings, fts], [read, write, manage]},
247       {[ui], [read]},
248       {[pools], [read]},
249       {[{bucket, bucket_name}, settings], [read]}]},
250     {fts_searcher, [bucket_name],
251      [{name, <<"FTS Searcher">>},
252       {desc, <<"Can query FTS indexes if they have bucket permissions">>}],
253      [{[{bucket, bucket_name}, fts], [read]},
254       {[settings, fts], [read]},
255       {[ui], [read]},
256       {[pools], [read]},
257       {[{bucket, bucket_name}, settings], [read]}]},
258     {query_select, [bucket_name],
259      [{name, <<"Query Select">>},
260       {desc, <<"Can execute SELECT statement on bucket to retrieve data">>}],
261      [{[{bucket, bucket_name}, n1ql, select], [execute]},
262       {[{bucket, bucket_name}, data, docs], [read]},
263       {[{bucket, bucket_name}, settings], [read]},
264       {[ui], [read]},
265       {[pools], [read]}]},
266     {query_update, [bucket_name],
267      [{name, <<"Query Update">>},
268       {desc, <<"Can execute UPDATE statement on bucket to update data">>}],
269      [{[{bucket, bucket_name}, n1ql, update], [execute]},
270       {[{bucket, bucket_name}, data, docs], [upsert]},
271       {[{bucket, bucket_name}, settings], [read]},
272       {[ui], [read]},
273       {[pools], [read]}]},
274     {query_insert, [bucket_name],
275      [{name, <<"Query Insert">>},
276       {desc, <<"Can execute INSERT statement on bucket to add data">>}],
277      [{[{bucket, bucket_name}, n1ql, insert], [execute]},
278       {[{bucket, bucket_name}, data, docs], [insert]},
279       {[{bucket, bucket_name}, settings], [read]},
280       {[ui], [read]},
281       {[pools], [read]}]},
282     {query_delete, [bucket_name],
283      [{name, <<"Query Delete">>},
284       {desc, <<"Can execute DELETE statement on bucket to delete data">>}],
285      [{[{bucket, bucket_name}, n1ql, delete], [execute]},
286       {[{bucket, bucket_name}, data, docs], [delete]},
287       {[{bucket, bucket_name}, settings], [read]},
288       {[ui], [read]},
289       {[pools], [read]}]},
290     {query_manage_index, [bucket_name],
291      [{name, <<"Query Manage Index">>},
292       {desc, <<"Can manage indexes for the bucket">>}],
293      [{[{bucket, bucket_name}, n1ql, index], all},
294       {[{bucket, bucket_name}, settings], [read]},
295       {[ui], [read]},
296       {[pools], [read]}]},
297     {query_system_catalog, [],
298      [{name, <<"Query System Catalog">>},
299       {desc, <<"Can lookup system catalog information">>}],
300      [{[{bucket, any}, n1ql, index], [list]},
301       {[{bucket, any}, settings], [read]},
302       {[n1ql, meta], [read]},
303       {[ui], [read]},
304       {[pools], [read]}]},
305     {query_external_access, [],
306      [{name, <<"Query External Access">>},
307       {desc, <<"Can execute CURL statement">>}],
308      [{[n1ql, curl], [execute]},
309       {[{bucket, any}, settings], [read]},
310       {[ui], [read]},
311       {[pools], [read]}]},
312     {replication_target, [bucket_name],
313      [{name, <<"Replication Target">>},
314       {desc, <<"XDC replication target for bucket">>}],
315      [{[{bucket, bucket_name}, settings], [read]},
316       {[{bucket, bucket_name}, data, meta], [read, write]},
317       {[{bucket, bucket_name}, stats], [read]},
318       {[pools], [read]}]}].
319
320-spec roles_55() -> [rbac_role_def(), ...].
321roles_55() ->
322    [{admin, [],
323      [{name, <<"Full Admin">>},
324       {desc, <<"Can manage all cluster features (including security). "
325                "This user can access the web console. This user can read and "
326                "write all data.">>},
327       {ce, true}],
328      [{[], all}]},
329     {ro_admin, [],
330      [{name, <<"Read-Only Admin">>},
331       {desc, <<"Can view all cluster statistics. This user can access the "
332                "web console. This user can read some data.">>},
333       {ce, true}],
334      [{[{bucket, any}, password], none},
335       {[{bucket, any}, data], none},
336       {[{bucket, any}, fts], none},
337       {[admin, security], [read]},
338       {[admin], none},
339       {[eventing], none},
340       {[], [read, list]}]},
341     {security_admin, [],
342      [{name, <<"Security Admin">>},
343       {desc, <<"Can view all cluster statistics and manage user roles, but "
344                "not grant Full Admin or Security Admin roles to other users "
345                "or alter their own role. This user can access the web "
346                "console. This user cannot read data.">>}],
347      [{[admin, security, admin], none},
348       {[admin, security], all},
349       {[admin, logs], none},
350       {[{bucket, any}, data], none},
351       {[{bucket, any}, views], none},
352       {[{bucket, any}, n1ql], none},
353       {[{bucket, any}, fts], none},
354       {[{bucket, any}, password], none},
355       {[{bucket, any}], [read]},
356       {[], [read, list]}]},
357     {cluster_admin, [],
358      [{name, <<"Cluster Admin">>},
359       {desc, <<"Can manage all cluster features except security. This user "
360                "can access the web console. This user cannot read data.">>}],
361      [{[admin, internal], none},
362       {[admin, security], none},
363       {[admin, diag], read},
364       {[{bucket, any}, data], none},
365       {[{bucket, any}, views], none},
366       {[{bucket, any}, n1ql], none},
367       {[{bucket, any}, fts], none},
368       {[{bucket, any}, password], none},
369       {[n1ql, curl], none},
370       {[eventing], none},
371       {[], all}]},
372     {bucket_admin, [bucket_name],
373      [{name, <<"Bucket Admin">>},
374       {desc, <<"Can manage ALL bucket features for a given bucket (including "
375                "start/stop XDCR). This user can access the web console. This "
376                "user cannot read data.">>}],
377      [{[{bucket, bucket_name}, xdcr], [read, execute]},
378       {[{bucket, bucket_name}, data], none},
379       {[{bucket, bucket_name}, views], none},
380       {[{bucket, bucket_name}, n1ql], none},
381       {[{bucket, bucket_name}, password], none},
382       {[{bucket, bucket_name}, fts], none},
383       {[{bucket, bucket_name}], all},
384       {[{bucket, any}, settings], [read]},
385       {[{bucket, any}], none},
386       {[xdcr], none},
387       {[admin], none},
388       {[eventing], none},
389       {[], [read]}]},
390     {bucket_full_access, [bucket_name],
391      [{name, <<"Application Access">>},
392       {desc, <<"Full access to bucket data. This user cannot access the web "
393                "console and is intended only for application access. This "
394                "user can read and write data.">>},
395       {ce, true}],
396      [{[{bucket, bucket_name}, data], all},
397       {[{bucket, bucket_name}, views], all},
398       {[{bucket, bucket_name}, n1ql, index], all},
399       {[{bucket, bucket_name}, n1ql], [execute]},
400       {[{bucket, bucket_name}], [read, flush]},
401       {[{bucket, bucket_name}, settings], [read]},
402       {[pools], [read]}]},
403     {views_admin, [bucket_name],
404      [{name, <<"Views Admin">>},
405       {desc, <<"Can create and manage views of a given bucket. This user can "
406                "access the web console. This user can read some data.">>}],
407      [{[{bucket, bucket_name}, views], all},
408       {[{bucket, bucket_name}, data], [read]},
409       {[{bucket, any}, settings], [read]},
410       {[{bucket, any}], none},
411       {[{bucket, bucket_name}, n1ql], [execute]},
412       {[xdcr], none},
413       {[admin], none},
414       {[eventing], none},
415       {[], [read]}]},
416     {views_reader, [bucket_name],
417      [{name, <<"Views Reader">>},
418       {desc, <<"Can read data from the views of a given bucket. This user "
419                "cannot access the web console and is intended only for "
420                "application access. This user can read some data.">>}],
421      [{[{bucket, bucket_name}, views], [read]},
422       {[{bucket, bucket_name}, data, docs], [read]},
423       {[pools], [read]}]},
424     {replication_admin, [],
425      [{name, <<"XDCR Admin">>},
426       {desc, <<"Can administer XDCR features to create cluster references and "
427                "replication streams out of this cluster. This user can "
428                "access the web console. This user can read some data.">>}],
429      [{[{bucket, any}, xdcr], all},
430       {[{bucket, any}, data], [read]},
431       {[{bucket, any}, settings], [read]},
432       {[{bucket, any}], none},
433       {[xdcr], all},
434       {[admin], none},
435       {[eventing], none},
436       {[], [read]}]},
437     {data_reader, [bucket_name],
438      [{name, <<"Data Reader">>},
439       {desc, <<"Can read data from a given bucket. This user cannot access "
440                "the web console and is intended only for application access. "
441                "This user can read data, but cannot write it.">>}],
442      [{[{bucket, bucket_name}, data, docs], [read]},
443       {[{bucket, bucket_name}, data, meta], [read]},
444       {[{bucket, bucket_name}, data, xattr], [read]},
445       {[{bucket, bucket_name}, settings], [read]},
446       {[pools], [read]}]},
447     {data_writer, [bucket_name],
448      [{name, <<"Data Writer">>},
449       {desc, <<"Can write data to a given bucket. This user cannot access the "
450                "web console and is intended only for application access. This "
451                "user can write data, but cannot read it.">>}],
452      [{[{bucket, bucket_name}, data, docs], [insert, upsert, delete]},
453       {[{bucket, bucket_name}, data, xattr], [write]},
454       {[{bucket, bucket_name}, settings], [read]},
455       {[pools], [read]}]},
456     {data_dcp_reader, [bucket_name],
457      [{name, <<"Data DCP Reader">>},
458       {desc, <<"Can initiate DCP streams for a given bucket. This user cannot "
459                "access the web console and is intended only for application "
460                "access. This user can read data.">>}],
461      [{[{bucket, bucket_name}, data, docs], [read]},
462       {[{bucket, bucket_name}, data, meta], [read]},
463       {[{bucket, bucket_name}, data, dcp], [read]},
464       {[{bucket, bucket_name}, data, sxattr], [read]},
465       {[{bucket, bucket_name}, data, xattr], [read]},
466       {[{bucket, bucket_name}, settings], [read]},
467       {[admin, memcached, idle], [write]},
468       {[pools], [read]}]},
469     {data_backup, [bucket_name],
470      [{name, <<"Data Backup & Restore">>},
471       {desc, <<"Can backup and restore a given bucket’s data. This user "
472                "cannot access the web console and is intended only for "
473                "application access. This user can read data.">>}],
474      [{[{bucket, bucket_name}, data], all},
475       {[{bucket, bucket_name}, views], [read, write]},
476       {[{bucket, bucket_name}, fts], [read, write, manage]},
477       {[{bucket, bucket_name}, stats], [read]},
478       {[{bucket, bucket_name}, settings], [read]},
479       {[{bucket, bucket_name}, n1ql, index], [create, list, build]},
480       {[pools], [read]}]},
481     {data_monitoring, [bucket_name],
482      [{name, <<"Data Monitor">>},
483       {desc, <<"Can read statistics for a given bucket. This user cannot "
484                "access the web console and is intended only for application "
485                "access. This user cannot read data.">>}],
486      [{[{bucket, bucket_name}, stats], [read]},
487       {[{bucket, bucket_name}, settings], [read]},
488       {[tasks], [read]},
489       {[pools], [read]}]},
490     {fts_admin, [bucket_name],
491      [{name, <<"Search Admin">>},
492       {desc, <<"Can administer all Full Text Search features. This user can "
493                "access the web console. This user can read some data.">>}],
494      [{[{bucket, bucket_name}, fts], [read, write, manage]},
495       {[settings, fts], [read, write, manage]},
496       {[ui], [read]},
497       {[pools], [read]},
498       {[{bucket, bucket_name}, settings], [read]}]},
499     {fts_searcher, [bucket_name],
500      [{name, <<"Search Reader">>},
501       {desc, <<"Can query Full Text Search indexes for a given bucket. This "
502                "user can access the web console. This user can read some "
503                "data.">>}],
504      [{[{bucket, bucket_name}, fts], [read]},
505       {[settings, fts], [read]},
506       {[ui], [read]},
507       {[pools], [read]},
508       {[{bucket, bucket_name}, settings], [read]}]},
509     {query_select, [bucket_name],
510      [{name, <<"Query Select">>},
511       {desc, <<"Can execute a SELECT statement on a given bucket to retrieve "
512                "data. This user can access the web console and can read data, "
513                "but not write it.">>}],
514      [{[{bucket, bucket_name}, n1ql, select], [execute]},
515       {[{bucket, bucket_name}, data, docs], [read]},
516       {[{bucket, bucket_name}, settings], [read]},
517       {[ui], [read]},
518       {[pools], [read]}]},
519     {query_update, [bucket_name],
520      [{name, <<"Query Update">>},
521       {desc, <<"Can execute an UPDATE statement on a given bucket to update "
522                "data. This user can access the web console and write data, "
523                "but cannot read it.">>}],
524      [{[{bucket, bucket_name}, n1ql, update], [execute]},
525       {[{bucket, bucket_name}, data, docs], [upsert]},
526       {[{bucket, bucket_name}, settings], [read]},
527       {[ui], [read]},
528       {[pools], [read]}]},
529     {query_insert, [bucket_name],
530      [{name, <<"Query Insert">>},
531       {desc, <<"Can execute an INSERT statement on a given bucket to add "
532                "data. This user can access the web console and insert data, "
533                "but cannot read it.">>}],
534      [{[{bucket, bucket_name}, n1ql, insert], [execute]},
535       {[{bucket, bucket_name}, data, docs], [insert]},
536       {[{bucket, bucket_name}, settings], [read]},
537       {[ui], [read]},
538       {[pools], [read]}]},
539     {query_delete, [bucket_name],
540      [{name, <<"Query Delete">>},
541       {desc, <<"Can execute a DELETE statement on a given bucket to delete "
542                "data. This user can access the web console, but cannot read "
543                "data. This user can delete data.">>}],
544      [{[{bucket, bucket_name}, n1ql, delete], [execute]},
545       {[{bucket, bucket_name}, data, docs], [delete]},
546       {[{bucket, bucket_name}, settings], [read]},
547       {[ui], [read]},
548       {[pools], [read]}]},
549     {query_manage_index, [bucket_name],
550      [{name, <<"Query Manage Index">>},
551       {desc, <<"Can manage indexes for a given bucket. This user can access "
552                "the web console, but cannot read data.">>}],
553      [{[{bucket, bucket_name}, n1ql, index], all},
554       {[{bucket, bucket_name}, settings], [read]},
555       {[ui], [read]},
556       {[pools], [read]}]},
557     {query_system_catalog, [],
558      [{name, <<"Query System Catalog">>},
559       {desc, <<"Can look up system catalog information via N1QL. This user "
560                "can access the web console, but cannot read user data.">>}],
561      [{[{bucket, any}, n1ql, index], [list]},
562       {[{bucket, any}, settings], [read]},
563       {[n1ql, meta], [read]},
564       {[ui], [read]},
565       {[pools], [read]}]},
566     {query_external_access, [],
567      [{name, <<"Query CURL Access">>},
568       {desc, <<"Can execute the CURL statement from within N1QL. This user "
569                "can access the web console, but cannot read data (within "
570                "Couchbase).">>}],
571      [{[n1ql, curl], [execute]},
572       {[{bucket, any}, settings], [read]},
573       {[ui], [read]},
574       {[pools], [read]}]},
575     {replication_target, [bucket_name],
576      [{name, <<"XDCR Inbound">>},
577       {desc, <<"Can create XDCR streams into a given bucket. This user cannot "
578                "access the web console or read any data.">>}],
579      [{[{bucket, bucket_name}, settings], [read]},
580       {[{bucket, bucket_name}, data, meta], [read, write]},
581       {[{bucket, bucket_name}, stats], [read]},
582       {[pools], [read]}]},
583     {analytics_manager, [bucket_name],
584      [{name, <<"Analytics Manager">>},
585       {desc, <<"Can manage Analytics buckets and shadow datasets on which "
586                "they also have bucket data read permission. This user can "
587                "access the web console and read some data.">>}],
588      [{[{bucket, bucket_name}, analytics], [manage]},
589       {[analytics], [select]},
590       {[ui], [read]},
591       {[pools], [read]}]},
592     {analytics_reader, [],
593      [{name, <<"Analytics Reader">>},
594       {desc, <<"Can query shadow datasets. This is a global role as shadow "
595                "datasets may be created on different buckets. This "
596                "user can access the web console and read some data.">>}],
597      [{[analytics], [select]},
598       {[ui], [read]},
599       {[pools], [read]}]}].
600
601-spec get_definitions() -> [rbac_role_def(), ...].
602get_definitions() ->
603    get_definitions(ns_config:latest()).
604
605-spec get_definitions(ns_config()) -> [rbac_role_def(), ...].
606get_definitions(Config) ->
607    case cluster_compat_mode:is_cluster_50(Config) of
608        true ->
609            case cluster_compat_mode:is_cluster_55(Config) of
610                true ->
611                    roles_55();
612                false ->
613                    roles_50()
614            end;
615        false ->
616            roles_45()
617    end.
618
619-spec object_match(rbac_permission_object(), rbac_permission_pattern_object()) ->
620                          boolean().
621object_match(_, []) ->
622    true;
623object_match([], [_|_]) ->
624    false;
625object_match([{_Same, _} | RestOfObject], [{_Same, any} | RestOfObjectPattern]) ->
626    object_match(RestOfObject, RestOfObjectPattern);
627object_match([{_Same, any} | RestOfObject], [{_Same, _} | RestOfObjectPattern]) ->
628    object_match(RestOfObject, RestOfObjectPattern);
629object_match([_Same | RestOfObject], [_Same | RestOfObjectPattern]) ->
630    object_match(RestOfObject, RestOfObjectPattern);
631object_match(_, _) ->
632    false.
633
634-spec get_allowed_operations(rbac_permission_object(), [rbac_permission_pattern()]) ->
635                                    rbac_permission_pattern_operations().
636get_allowed_operations(_Object, []) ->
637    none;
638get_allowed_operations(Object, [{ObjectPattern, AllowedOperations} | Rest]) ->
639    case object_match(Object, ObjectPattern) of
640        true ->
641            AllowedOperations;
642        false ->
643            get_allowed_operations(Object, Rest)
644    end.
645
646-spec operation_allowed(rbac_operation(), rbac_permission_pattern_operations()) ->
647                               boolean().
648operation_allowed(_, all) ->
649    true;
650operation_allowed(_, none) ->
651    false;
652operation_allowed(any, _) ->
653    true;
654operation_allowed(Operation, AllowedOperations) ->
655    lists:member(Operation, AllowedOperations).
656
657-spec is_allowed(rbac_permission(), rbac_identity() | [rbac_compiled_role()]) -> boolean().
658is_allowed(Permission, {_, _} = Identity) ->
659    Roles = get_compiled_roles(Identity),
660    is_allowed(Permission, Roles);
661is_allowed({Object, Operation}, Roles) ->
662    lists:any(fun (Role) ->
663                      Operations = get_allowed_operations(Object, Role),
664                      operation_allowed(Operation, Operations)
665              end, Roles).
666
667-spec substitute_params([string()], [atom()], [rbac_permission_pattern_raw()]) ->
668                               [rbac_permission_pattern()].
669substitute_params([], [], Permissions) ->
670    Permissions;
671substitute_params(Params, ParamDefinitions, Permissions) ->
672    ParamPairs = lists:zip(ParamDefinitions, Params),
673    lists:map(fun ({ObjectPattern, AllowedOperations}) ->
674                      {lists:map(fun ({Name, any}) ->
675                                         {Name, any};
676                                     ({Name, Param}) ->
677                                         {Param, Subst} = lists:keyfind(Param, 1, ParamPairs),
678                                         {Name, Subst};
679                                     (Vertex) ->
680                                         Vertex
681                                 end, ObjectPattern), AllowedOperations}
682              end, Permissions).
683
684-spec compile_params([atom()], [rbac_role_param()], rbac_all_param_values()) ->
685                            false | [[rbac_role_param()]].
686compile_params(ParamDefs, Params, AllParamValues) ->
687    PossibleValues = get_possible_param_values(ParamDefs, AllParamValues),
688    case find_matching_value(ParamDefs, Params, PossibleValues) of
689        false ->
690            false;
691        Values ->
692            Values
693    end.
694
695compile_roles(CompileRole, Roles, Definitions, AllParamValues) ->
696    lists:filtermap(fun (Name) when is_atom(Name) ->
697                            case lists:keyfind(Name, 1, Definitions) of
698                                {Name, [], _Props, Permissions} ->
699                                    {true, CompileRole(Name, [], [], Permissions)};
700                                false ->
701                                    false
702                            end;
703                        ({Name, Params}) ->
704                            case lists:keyfind(Name, 1, Definitions) of
705                                {Name, ParamDefs, _Props, Permissions} ->
706                                    case compile_params(ParamDefs, Params, AllParamValues) of
707                                        false ->
708                                            false;
709                                        NewParams ->
710                                            {true, CompileRole(Name, NewParams, ParamDefs, Permissions)}
711                                    end;
712                                false ->
713                                    false
714                            end
715                    end, Roles).
716
717-spec compile_roles([rbac_role()], [rbac_role_def()] | undefined, rbac_all_param_values()) ->
718                           [rbac_compiled_role()].
719compile_roles(_Roles, undefined, _AllParamValues) ->
720    %% can happen briefly after node joins the cluster on pre 5.0 clusters
721    [];
722compile_roles(Roles, Definitions, AllParamValues) ->
723    compile_roles(
724      fun (_Name, Params, ParamDefs, Permissions) ->
725              substitute_params(strip_ids(ParamDefs, Params),
726                                ParamDefs, Permissions)
727      end, Roles, Definitions, AllParamValues).
728
729-spec get_roles(rbac_identity()) -> [rbac_role()].
730get_roles({"", wrong_token}) ->
731    case ns_config_auth:is_system_provisioned() of
732        false ->
733            [admin];
734        true ->
735            []
736    end;
737get_roles({"", anonymous}) ->
738    case ns_config_auth:is_system_provisioned() of
739        false ->
740            [admin];
741        true ->
742            [{bucket_full_access, [BucketName]} ||
743                BucketName <- ns_config_auth:get_no_auth_buckets(ns_config:latest())]
744    end;
745get_roles({_, admin}) ->
746    [admin];
747get_roles({_, ro_admin}) ->
748    [ro_admin];
749get_roles({BucketName, bucket}) ->
750    [{bucket_full_access, [BucketName]}];
751get_roles({User, external} = Identity) ->
752    case cluster_compat_mode:is_cluster_45() of
753        true ->
754            menelaus_users:get_roles(Identity);
755        false ->
756            case saslauthd_auth:get_role_pre_45(User) of
757                admin ->
758                    [admin];
759                ro_admin ->
760                    [ro_admin];
761                false ->
762                    []
763            end
764    end;
765get_roles({_User, local} = Identity) ->
766    menelaus_users:get_roles(Identity).
767
768compiled_roles_cache_name() ->
769    compiled_roles_cache.
770
771start_compiled_roles_cache() ->
772    UsersFilter =
773        fun ({user_version, _V}) ->
774                true;
775            (_) ->
776                false
777        end,
778    ConfigFilter =
779        fun ({buckets, _}) ->
780                true;
781            ({cluster_compat_version, _}) ->
782                true;
783            ({rest_creds, _}) ->
784                true;
785            (_) ->
786                false
787        end,
788    GetVersion =
789        fun () ->
790                {cluster_compat_mode:get_compat_version(ns_config:latest()),
791                 menelaus_users:get_users_version(),
792                 ns_config_auth:is_system_provisioned(),
793                 [{Name, proplists:get_value(uuid, BucketConfig)} ||
794                     {Name, BucketConfig} <- ns_bucket:get_buckets(ns_config:latest())]}
795        end,
796    GetEvents =
797        case ns_node_disco:couchdb_node() == node() of
798            true ->
799                fun () ->
800                        dist_manager:wait_for_node(fun ns_node_disco:ns_server_node/0),
801                        [{{user_storage_events, ns_node_disco:ns_server_node()}, UsersFilter},
802                         {ns_config_events, ConfigFilter}]
803                end;
804            false ->
805                fun () ->
806                        [{user_storage_events, UsersFilter},
807                         {ns_config_events, ConfigFilter}]
808                end
809        end,
810
811    versioned_cache:start_link(
812      compiled_roles_cache_name(), 200, fun build_compiled_roles/1,
813      GetEvents, GetVersion).
814
815-spec get_compiled_roles(rbac_identity()) -> [rbac_compiled_role()].
816get_compiled_roles(Identity) ->
817    versioned_cache:get(compiled_roles_cache_name(), Identity).
818
819build_compiled_roles(Identity) ->
820    case ns_node_disco:couchdb_node() == node() of
821        false ->
822            ?log_debug("Compile roles for user ~p",
823                       [ns_config_log:tag_user_data(Identity)]),
824            Definitions = get_definitions(),
825            AllPossibleValues = calculate_possible_param_values(ns_bucket:get_buckets()),
826            compile_roles(get_roles(Identity), Definitions, AllPossibleValues);
827        true ->
828            ?log_debug("Retrieve compiled roles for user ~p from ns_server "
829                       "node", [ns_config_log:tag_user_data(Identity)]),
830            rpc:call(ns_node_disco:ns_server_node(), ?MODULE, build_compiled_roles, [Identity])
831    end.
832
833filter_out_invalid_roles(Roles, Definitions, AllPossibleValues) ->
834    compile_roles(fun (Name, [], _, _) ->
835                          Name;
836                      (Name, Params, _, _) ->
837                          {Name, Params}
838                  end, Roles, Definitions, AllPossibleValues).
839
840calculate_possible_param_values(_Buckets, []) ->
841    [[]];
842calculate_possible_param_values(Buckets, [bucket_name]) ->
843    [[any] | [[{Name, proplists:get_value(uuid, Props)}] || {Name, Props} <- Buckets]].
844
845all_params_combinations() ->
846    [[], [bucket_name]].
847
848-spec calculate_possible_param_values(list()) -> rbac_all_param_values().
849calculate_possible_param_values(Buckets) ->
850    [{Combination, calculate_possible_param_values(Buckets, Combination)} ||
851        Combination <- all_params_combinations()].
852
853-spec get_possible_param_values([atom()], rbac_all_param_values()) -> [[rbac_role_param()]].
854get_possible_param_values(ParamDefs, AllValues) ->
855    {ParamDefs, Values} = lists:keyfind(ParamDefs, 1, AllValues),
856    Values.
857
858visible_roles_filter() ->
859    case cluster_compat_mode:is_enterprise() of
860        true ->
861            pipes:filter(fun ({_, _, Props, _}) -> Props =/= [] end);
862        false ->
863            pipes:filter(fun ({_, _, Props, _}) ->
864                                 proplists:get_value(ce, Props, false)
865                         end)
866    end.
867
868expand_params(AllPossibleValues) ->
869    ?make_transducer(
870       pipes:foreach(
871         ?producer(),
872         fun ({Role, [], Props, _}) ->
873                 ?yield({Role, Props});
874             ({Role, ParamDefs, Props, _}) ->
875                 lists:foreach(
876                   fun (Values) ->
877                           ?yield({{Role, Values}, Props})
878                   end, get_possible_param_values(ParamDefs, AllPossibleValues))
879         end)).
880
881filter_by_permission(undefined, _ParamValues, _Definitions) ->
882    pipes:filter(fun (_) -> true end);
883filter_by_permission(Permission, ParamValues, Definitions) ->
884    pipes:filter(
885      fun ({Role, _}) ->
886              menelaus_roles:is_allowed(
887                Permission, compile_roles([Role], Definitions, ParamValues))
888      end).
889
890-spec produce_roles_by_permission(rbac_permission(), ns_config(), list()) ->
891                                         pipes:producer(rbac_role()).
892produce_roles_by_permission(Permission, Config, Buckets) ->
893    AllValues = calculate_possible_param_values(Buckets),
894    Definitions = get_definitions(Config),
895    pipes:compose(
896      [pipes:stream_list(Definitions),
897       visible_roles_filter(),
898       expand_params(AllValues),
899       filter_by_permission(Permission, AllValues, Definitions)]).
900
901strip_id(bucket_name, {P, _Id}) ->
902    P;
903strip_id(bucket_name, P) ->
904    P.
905
906strip_ids(ParamDefs, Params) ->
907    [strip_id(ParamDef, Param) || {ParamDef, Param} <- lists:zip(ParamDefs, Params)].
908
909match_param(bucket_name, P, P) ->
910    true;
911match_param(bucket_name, P, {P, _Id}) ->
912    true;
913match_param(bucket_name, _, _) ->
914    false.
915
916match_params([], [], []) ->
917    true;
918match_params(ParamDefs, Params, Values) ->
919    case lists:dropwhile(
920           fun ({ParamDef, Param, Value}) ->
921                   match_param(ParamDef, Param, Value)
922           end, lists:zip3(ParamDefs, Params, Values)) of
923        [] ->
924            true;
925        _ ->
926            false
927    end.
928
929-spec find_matching_value([atom()], [rbac_role_param()], [[rbac_role_param()]]) ->
930                                 false | [rbac_role_param()].
931find_matching_value(ParamDefs, Params, PossibleValues) ->
932    case lists:dropwhile(
933           fun (Values) ->
934                   not match_params(ParamDefs, Params, Values)
935           end, PossibleValues) of
936        [] ->
937            false;
938        [V | _] ->
939            V
940    end.
941
942-spec validate_role(rbac_role(), [rbac_role_def()], [[rbac_role_param()]]) ->
943                           false | {ok, rbac_role()}.
944validate_role(Role, Definitions, AllValues) when is_atom(Role) ->
945    validate_role(Role, [], Definitions, AllValues);
946validate_role({Role, Params}, Definitions, AllValues) ->
947    validate_role(Role, Params, Definitions, AllValues).
948
949validate_role(Role, Params, Definitions, AllValues) ->
950    case lists:keyfind(Role, 1, Definitions) of
951        {Role, ParamsDef, _, _} when length(Params) =:= length(ParamsDef) ->
952            PossibleValues = get_possible_param_values(ParamsDef, AllValues),
953            case find_matching_value(ParamsDef, Params, PossibleValues) of
954                false ->
955                    false;
956                [] ->
957                    {ok, Role};
958                Expanded ->
959                    {ok, {Role, Expanded}}
960            end;
961        _ ->
962            false
963    end.
964
965validate_roles(Roles, Config) ->
966    Definitions = pipes:run(pipes:stream_list(get_definitions(Config)),
967                            visible_roles_filter(),
968                            pipes:collect()),
969    AllValues = calculate_possible_param_values(ns_bucket:get_buckets(Config)),
970    lists:foldl(fun (Role, {Validated, Unknown}) ->
971                        case validate_role(Role, Definitions, AllValues) of
972                            false ->
973                                {Validated, [Role | Unknown]};
974                            {ok, R} ->
975                                {[R | Validated], Unknown}
976                        end
977                end, {[], []}, Roles).
978
979get_security_roles() ->
980    get_security_roles(ns_config:latest()).
981
982get_security_roles(Config) ->
983    pipes:run(produce_roles_by_permission({[admin, security], any}, Config, []),
984              pipes:collect()).
985
986filter_out_invalid_roles_test() ->
987    Roles = [{role1, [{"bucket1", <<"id1">>}]},
988             {role2, [{"bucket2", <<"id2">>}]}],
989    Definitions = [{role1, [bucket_name],
990                    [{name,<<"">>},{desc, <<"">>}],
991                    [{[{bucket,bucket_name},settings],[read]}]},
992                   {role2, [bucket_name],
993                    [{name,<<"">>},{desc, <<"">>}],
994                    [{[{bucket,bucket_name},n1ql,update],[execute]}]}],
995    PossibleValues = [{[],[[]]},
996                      {[bucket_name],
997                       [[any],
998                       [{"bucket1",<<"id1">>}]]}],
999    ?assertEqual([{role1, [{"bucket1", <<"id1">>}]}],
1000                 filter_out_invalid_roles(Roles, Definitions, PossibleValues)).
1001
1002%% assertEqual is used instead of assert and assertNot to avoid
1003%% dialyzer warnings
1004object_match_test() ->
1005    ?assertEqual(true, object_match([o1, o2], [o1, o2])),
1006    ?assertEqual(false, object_match([o1], [o1, o2])),
1007    ?assertEqual(true, object_match([o1, o2], [o1])),
1008    ?assertEqual(true, object_match([{b, "a"}], [{b, "a"}])),
1009    ?assertEqual(false, object_match([{b, "a"}], [{b, "b"}])),
1010    ?assertEqual(true, object_match([{b, any}], [{b, "b"}])),
1011    ?assertEqual(true, object_match([{b, "a"}], [{b, any}])),
1012    ?assertEqual(true, object_match([{b, any}], [{b, any}])).
1013
1014toy_config() ->
1015    [[{buckets,
1016       [{configs,
1017         [{"test", [{uuid, <<"test_id">>}]},
1018          {"default", [{uuid, <<"default_id">>}]}]}]}]].
1019
1020compile_roles(Roles, Definitions) ->
1021    AllPossibleValues = calculate_possible_param_values(ns_bucket:get_buckets(toy_config())),
1022    compile_roles(Roles, Definitions, AllPossibleValues).
1023
1024compile_roles_test() ->
1025    ?assertEqual([[{[{bucket, "test"}], none}]],
1026                 compile_roles([{test_role, ["test"]}],
1027                               [{test_role, [bucket_name], [], [{[{bucket, bucket_name}], none}]}])).
1028
1029admin_test() ->
1030    Roles = compile_roles([admin], roles_45()),
1031    ?assertEqual(true, is_allowed({[buckets], create}, Roles)),
1032    ?assertEqual(true, is_allowed({[something, something], anything}, Roles)).
1033
1034ro_admin_test() ->
1035    Roles = compile_roles([ro_admin], roles_45()),
1036    ?assertEqual(false, is_allowed({[{bucket, "test"}, password], read}, Roles)),
1037    ?assertEqual(false, is_allowed({[{bucket, "test"}, data], read}, Roles)),
1038    ?assertEqual(true, is_allowed({[{bucket, "test"}, something], read}, Roles)),
1039    ?assertEqual(false, is_allowed({[{bucket, "test"}, something], write}, Roles)),
1040    ?assertEqual(false, is_allowed({[admin, security], write}, Roles)),
1041    ?assertEqual(true, is_allowed({[admin, security], read}, Roles)),
1042    ?assertEqual(false, is_allowed({[admin, other], write}, Roles)),
1043    ?assertEqual(true, is_allowed({[anything], read}, Roles)),
1044    ?assertEqual(false, is_allowed({[anything], write}, Roles)).
1045
1046bucket_views_admin_check_global(Roles) ->
1047    ?assertEqual(false, is_allowed({[xdcr], read}, Roles)),
1048    ?assertEqual(false, is_allowed({[admin], read}, Roles)),
1049    ?assertEqual(true, is_allowed({[something], read}, Roles)),
1050    ?assertEqual(false, is_allowed({[something], write}, Roles)),
1051    ?assertEqual(false, is_allowed({[buckets], create}, Roles)).
1052
1053bucket_views_admin_check_another(Roles) ->
1054    ?assertEqual(false, is_allowed({[{bucket, "another"}, xdcr], read}, Roles)),
1055    ?assertEqual(false, is_allowed({[{bucket, "another"}, views], read}, Roles)),
1056    ?assertEqual(false, is_allowed({[{bucket, "another"}, data], read}, Roles)),
1057    ?assertEqual(true, is_allowed({[{bucket, "another"}, settings], read}, Roles)),
1058    ?assertEqual(false, is_allowed({[{bucket, "another"}, settings], write}, Roles)),
1059    ?assertEqual(false, is_allowed({[{bucket, "another"}], read}, Roles)),
1060    ?assertEqual(false, is_allowed({[buckets], create}, Roles)).
1061
1062bucket_admin_check_default(Roles) ->
1063    ?assertEqual(true, is_allowed({[{bucket, "default"}, xdcr], read}, Roles)),
1064    ?assertEqual(true, is_allowed({[{bucket, "default"}, xdcr], execute}, Roles)),
1065    ?assertEqual(true, is_allowed({[{bucket, "default"}, anything], anything}, Roles)),
1066    ?assertEqual(true, is_allowed({[{bucket, "default"}, anything], anything}, Roles)).
1067
1068bucket_admin_test() ->
1069    Roles = compile_roles([{bucket_admin, ["default"]}], roles_45()),
1070    bucket_admin_check_default(Roles),
1071    bucket_views_admin_check_another(Roles),
1072    bucket_views_admin_check_global(Roles).
1073
1074bucket_admin_wildcard_test() ->
1075    Roles = compile_roles([{bucket_admin, [any]}], roles_45()),
1076    bucket_admin_check_default(Roles),
1077    bucket_views_admin_check_global(Roles).
1078
1079views_admin_check_default(Roles) ->
1080    ?assertEqual(true, is_allowed({[{bucket, "default"}, views], anything}, Roles)),
1081    ?assertEqual(true, is_allowed({[{bucket, "default"}, data], read}, Roles)),
1082    ?assertEqual(false, is_allowed({[{bucket, "default"}, data], write}, Roles)),
1083    ?assertEqual(true, is_allowed({[{bucket, "default"}, settings], read}, Roles)),
1084    ?assertEqual(false, is_allowed({[{bucket, "default"}, settings], write}, Roles)),
1085    ?assertEqual(false, is_allowed({[{bucket, "default"}], read}, Roles)).
1086
1087views_admin_test() ->
1088    Roles = compile_roles([{views_admin, ["default"]}], roles_45()),
1089    views_admin_check_default(Roles),
1090    bucket_views_admin_check_another(Roles),
1091    bucket_views_admin_check_global(Roles).
1092
1093views_admin_wildcard_test() ->
1094    Roles = compile_roles([{views_admin, [any]}], roles_45()),
1095    views_admin_check_default(Roles),
1096    bucket_views_admin_check_global(Roles).
1097
1098bucket_full_access_check(Roles, Bucket, Allowed) ->
1099    ?assertEqual(Allowed, is_allowed({[{bucket, Bucket}, data], anything}, Roles)),
1100    ?assertEqual(Allowed, is_allowed({[{bucket, Bucket}], flush}, Roles)),
1101    ?assertEqual(Allowed, is_allowed({[{bucket, Bucket}], flush}, Roles)),
1102    ?assertEqual(false, is_allowed({[{bucket, Bucket}], write}, Roles)).
1103
1104bucket_full_access_test() ->
1105    Roles = compile_roles([{bucket_full_access, ["default"]}], roles_45()),
1106    bucket_full_access_check(Roles, "default", true),
1107    bucket_full_access_check(Roles, "another", false),
1108    ?assertEqual(true, is_allowed({[pools], read}, Roles)),
1109    ?assertEqual(false, is_allowed({[another], read}, Roles)).
1110
1111replication_admin_test() ->
1112    Roles = compile_roles([replication_admin], roles_45()),
1113    ?assertEqual(true, is_allowed({[{bucket, "default"}, xdcr], anything}, Roles)),
1114    ?assertEqual(false, is_allowed({[{bucket, "default"}, password], read}, Roles)),
1115    ?assertEqual(false, is_allowed({[{bucket, "default"}, views], read}, Roles)),
1116    ?assertEqual(true, is_allowed({[{bucket, "default"}, settings], read}, Roles)),
1117    ?assertEqual(false, is_allowed({[{bucket, "default"}, settings], write}, Roles)),
1118    ?assertEqual(true, is_allowed({[{bucket, "default"}, data], read}, Roles)),
1119    ?assertEqual(false, is_allowed({[{bucket, "default"}, data], write}, Roles)),
1120    ?assertEqual(true, is_allowed({[xdcr], anything}, Roles)),
1121    ?assertEqual(false, is_allowed({[admin], read}, Roles)),
1122    ?assertEqual(true, is_allowed({[other], read}, Roles)).
1123
1124validate_role_test() ->
1125    Config = toy_config(),
1126    Definitions = roles_45(),
1127    AllParamValues = calculate_possible_param_values(ns_bucket:get_buckets(Config)),
1128    ?assertEqual({ok, admin}, validate_role(admin, Definitions, AllParamValues)),
1129    ?assertEqual({ok, {bucket_admin, [{"test", <<"test_id">>}]}},
1130                 validate_role({bucket_admin, ["test"]}, Definitions, AllParamValues)),
1131    ?assertEqual({ok, {views_admin, [any]}},
1132                 validate_role({views_admin, [any]}, Definitions, AllParamValues)),
1133    ?assertEqual(false, validate_role(something, Definitions, AllParamValues)),
1134    ?assertEqual(false, validate_role({bucket_admin, ["something"]}, Definitions, AllParamValues)),
1135    ?assertEqual(false, validate_role({something, ["test"]}, Definitions, AllParamValues)),
1136    ?assertEqual(false, validate_role({admin, ["test"]}, Definitions, AllParamValues)),
1137    ?assertEqual(false, validate_role(bucket_admin, Definitions, AllParamValues)),
1138    ?assertEqual(false, validate_role({bucket_admin, ["test", "test"]}, Definitions, AllParamValues)).
1139