forest_liana 5.2.3 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/forest_liana/actions_controller.rb +95 -0
- data/app/controllers/forest_liana/resources_controller.rb +14 -17
- data/app/controllers/forest_liana/smart_actions_controller.rb +10 -5
- data/app/helpers/forest_liana/is_same_data_structure_helper.rb +44 -0
- data/app/helpers/forest_liana/widgets_helper.rb +59 -0
- data/app/models/forest_liana/model/action.rb +2 -1
- data/app/services/forest_liana/apimap_sorter.rb +1 -0
- data/app/services/forest_liana/permissions_checker.rb +118 -56
- data/app/services/forest_liana/permissions_formatter.rb +52 -0
- data/app/services/forest_liana/permissions_getter.rb +52 -17
- data/app/services/forest_liana/resources_getter.rb +3 -3
- data/app/services/forest_liana/scope_validator.rb +8 -7
- data/app/services/forest_liana/utils/beta_schema_utils.rb +13 -0
- data/config/routes.rb +2 -0
- data/lib/forest_liana/bootstrapper.rb +19 -0
- data/lib/forest_liana/schema_file_updater.rb +1 -0
- data/lib/forest_liana/version.rb +1 -1
- data/spec/helpers/forest_liana/is_same_data_structure_helper_spec.rb +87 -0
- data/spec/requests/actions_controller_spec.rb +174 -0
- data/spec/services/forest_liana/apimap_sorter_spec.rb +6 -4
- data/spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb +711 -0
- data/spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb +831 -0
- data/spec/services/forest_liana/permissions_formatter_spec.rb +222 -0
- data/spec/services/forest_liana/permissions_getter_spec.rb +82 -0
- data/spec/services/forest_liana/schema_adapter_spec.rb +1 -1
- data/spec/spec_helper.rb +3 -0
- metadata +18 -2
@@ -0,0 +1,831 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
describe PermissionsChecker do
|
3
|
+
before(:each) do
|
4
|
+
described_class.empty_cache
|
5
|
+
end
|
6
|
+
|
7
|
+
let(:user_id) { 1 }
|
8
|
+
let(:schema) {
|
9
|
+
[
|
10
|
+
ForestLiana::Model::Collection.new({
|
11
|
+
name: 'all_rights_collection_boolean',
|
12
|
+
fields: [],
|
13
|
+
actions: [
|
14
|
+
ForestLiana::Model::Action.new({
|
15
|
+
name: 'Test',
|
16
|
+
endpoint: 'forest/actions/Test',
|
17
|
+
http_method: 'POST'
|
18
|
+
})
|
19
|
+
]
|
20
|
+
}), ForestLiana::Model::Collection.new({
|
21
|
+
name: 'no_rights_collection_boolean',
|
22
|
+
fields: [],
|
23
|
+
actions: [
|
24
|
+
ForestLiana::Model::Action.new({
|
25
|
+
name: 'Test',
|
26
|
+
endpoint: 'forest/actions/Test',
|
27
|
+
http_method: 'POST'
|
28
|
+
})
|
29
|
+
]
|
30
|
+
}), ForestLiana::Model::Collection.new({
|
31
|
+
name: 'all_rights_collection_user_list',
|
32
|
+
fields: [],
|
33
|
+
actions: [
|
34
|
+
ForestLiana::Model::Action.new({
|
35
|
+
name: 'Test',
|
36
|
+
endpoint: 'forest/actions/Test',
|
37
|
+
http_method: 'POST'
|
38
|
+
})
|
39
|
+
]
|
40
|
+
}), ForestLiana::Model::Collection.new({
|
41
|
+
name: 'no_rights_collection_user_list',
|
42
|
+
fields: [],
|
43
|
+
actions: [
|
44
|
+
ForestLiana::Model::Action.new({
|
45
|
+
name: 'Test',
|
46
|
+
endpoint: 'forest/actions/Test',
|
47
|
+
http_method: 'POST'
|
48
|
+
})
|
49
|
+
]
|
50
|
+
})
|
51
|
+
]
|
52
|
+
}
|
53
|
+
let(:scope_permissions) { nil }
|
54
|
+
let(:default_api_permissions) {
|
55
|
+
{
|
56
|
+
"data" => {
|
57
|
+
'collections' => {
|
58
|
+
"all_rights_collection_boolean" => {
|
59
|
+
"collection" => {
|
60
|
+
"browseEnabled" => true,
|
61
|
+
"readEnabled" => true,
|
62
|
+
"editEnabled" => true,
|
63
|
+
"addEnabled" => true,
|
64
|
+
"deleteEnabled" => true,
|
65
|
+
"exportEnabled" => true
|
66
|
+
},
|
67
|
+
"actions" => {
|
68
|
+
"Test" => {
|
69
|
+
"triggerEnabled" => true
|
70
|
+
},
|
71
|
+
}
|
72
|
+
},
|
73
|
+
"all_rights_collection_user_list" => {
|
74
|
+
"collection" => {
|
75
|
+
"browseEnabled" => [1],
|
76
|
+
"readEnabled" => [1],
|
77
|
+
"editEnabled" => [1],
|
78
|
+
"addEnabled" => [1],
|
79
|
+
"deleteEnabled" => [1],
|
80
|
+
"exportEnabled" => [1]
|
81
|
+
},
|
82
|
+
"actions" => {
|
83
|
+
"Test" => {
|
84
|
+
"triggerEnabled" => [1]
|
85
|
+
},
|
86
|
+
}
|
87
|
+
},
|
88
|
+
"no_rights_collection_boolean" => {
|
89
|
+
"collection" => {
|
90
|
+
"browseEnabled" => false,
|
91
|
+
"readEnabled" => false,
|
92
|
+
"editEnabled" => false,
|
93
|
+
"addEnabled" => false,
|
94
|
+
"deleteEnabled" => false,
|
95
|
+
"exportEnabled" => false
|
96
|
+
},
|
97
|
+
"actions" => {
|
98
|
+
"Test" => {
|
99
|
+
"triggerEnabled" => false
|
100
|
+
},
|
101
|
+
}
|
102
|
+
},
|
103
|
+
"no_rights_collection_user_list" => {
|
104
|
+
"collection" => {
|
105
|
+
"browseEnabled" => [],
|
106
|
+
"readEnabled" => [],
|
107
|
+
"editEnabled" => [],
|
108
|
+
"addEnabled" => [],
|
109
|
+
"deleteEnabled" => [],
|
110
|
+
"exportEnabled" => []
|
111
|
+
},
|
112
|
+
"actions" => {
|
113
|
+
"Test" => {
|
114
|
+
"triggerEnabled" => []
|
115
|
+
},
|
116
|
+
}
|
117
|
+
},
|
118
|
+
},
|
119
|
+
'renderings' => scope_permissions
|
120
|
+
},
|
121
|
+
"meta" => {
|
122
|
+
"rolesACLActivated" => true
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
let(:default_rendering_id) { 1 }
|
127
|
+
|
128
|
+
before do
|
129
|
+
allow(ForestLiana).to receive(:apimap).and_return(schema)
|
130
|
+
allow(ForestLiana).to receive(:name_for).and_return(collection_name)
|
131
|
+
end
|
132
|
+
|
133
|
+
describe 'handling cache' do
|
134
|
+
let(:collection_name) { 'all_rights_collection_boolean' }
|
135
|
+
let(:fake_ressource) { nil }
|
136
|
+
let(:default_rendering_id) { 1 }
|
137
|
+
|
138
|
+
context 'collections cache' do
|
139
|
+
context 'when calling twice the same permissions' do
|
140
|
+
before do
|
141
|
+
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).and_return(default_api_permissions)
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'after expiration time' do
|
145
|
+
before do
|
146
|
+
allow(ENV).to receive(:[]).with('FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS').and_return('-1')
|
147
|
+
# Needed to enforce ENV stub
|
148
|
+
described_class.empty_cache
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should call the API twice' do
|
152
|
+
described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id).is_authorized?
|
153
|
+
described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id).is_authorized?
|
154
|
+
|
155
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).twice
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'before expiration time' do
|
160
|
+
it 'should call the API only once' do
|
161
|
+
described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id).is_authorized?
|
162
|
+
described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id).is_authorized?
|
163
|
+
|
164
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).once
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'with permissions coming from 2 different renderings' do
|
170
|
+
before do
|
171
|
+
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering)
|
172
|
+
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(1).and_return(api_permissions_rendering_1)
|
173
|
+
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(2).and_return(api_permissions_rendering_2)
|
174
|
+
end
|
175
|
+
|
176
|
+
let(:collection_name) { 'custom' }
|
177
|
+
let(:scope_permissions) { { default_rendering_id => { 'custom' => nil }, 2 => { 'custom' => nil } } }
|
178
|
+
let(:api_permissions_rendering_1) {
|
179
|
+
{
|
180
|
+
"data" => {
|
181
|
+
'collections' => {
|
182
|
+
"custom" => {
|
183
|
+
"collection" => {
|
184
|
+
"browseEnabled" => false,
|
185
|
+
"readEnabled" => true,
|
186
|
+
"editEnabled" => true,
|
187
|
+
"addEnabled" => true,
|
188
|
+
"deleteEnabled" => true,
|
189
|
+
"exportEnabled" => true
|
190
|
+
},
|
191
|
+
"actions" => { }
|
192
|
+
},
|
193
|
+
},
|
194
|
+
'renderings' => scope_permissions
|
195
|
+
},
|
196
|
+
"meta" => {
|
197
|
+
"rolesACLActivated" => true
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}
|
201
|
+
let(:api_permissions_rendering_2) {
|
202
|
+
api_permissions_rendering_2 = api_permissions_rendering_1.deep_dup
|
203
|
+
api_permissions_rendering_2['data']['collections']['custom']['collection']['exportEnabled'] = false
|
204
|
+
api_permissions_rendering_2['data']['collections']['custom']['collection']['browseEnabled'] = true
|
205
|
+
api_permissions_rendering_2
|
206
|
+
}
|
207
|
+
|
208
|
+
context 'when the first call is authorized' do
|
209
|
+
let(:authorized_to_export_rendering_1) { described_class.new(fake_ressource, 'exportEnabled', 1, user_id: user_id).is_authorized? }
|
210
|
+
let(:authorized_to_export_rendering_2) { described_class.new(fake_ressource, 'exportEnabled', 2, user_id: user_id).is_authorized? }
|
211
|
+
|
212
|
+
# Even if the value are different, the permissions are cross rendering thus another call
|
213
|
+
# to the api wont be made until the permission expires
|
214
|
+
it 'should return the same value' do
|
215
|
+
expect(authorized_to_export_rendering_1).to eq true
|
216
|
+
expect(authorized_to_export_rendering_2).to eq true
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'should call the API only once' do
|
220
|
+
authorized_to_export_rendering_1
|
221
|
+
authorized_to_export_rendering_2
|
222
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).once
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# If not authorized the cached version is not used
|
227
|
+
context 'when the first call is not authorized' do
|
228
|
+
let(:authorized_to_export_rendering_1) { described_class.new(fake_ressource, 'browseEnabled', 1, user_id: user_id).is_authorized? }
|
229
|
+
let(:authorized_to_export_rendering_2) { described_class.new(fake_ressource, 'browseEnabled', 2, user_id: user_id).is_authorized? }
|
230
|
+
|
231
|
+
it 'should return different value' do
|
232
|
+
expect(authorized_to_export_rendering_1).to eq false
|
233
|
+
expect(authorized_to_export_rendering_2).to eq true
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'should call the API twice' do
|
237
|
+
authorized_to_export_rendering_1
|
238
|
+
authorized_to_export_rendering_2
|
239
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).twice
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
context 'scopes cache' do
|
246
|
+
let(:rendering_id) { 1 }
|
247
|
+
let(:collection_name) { 'custom' }
|
248
|
+
let(:scope_permissions) { { rendering_id => { 'custom' => nil } } }
|
249
|
+
let(:api_permissions) {
|
250
|
+
{
|
251
|
+
"data" => {
|
252
|
+
'collections' => {
|
253
|
+
"custom" => {
|
254
|
+
"collection" => {
|
255
|
+
"browseEnabled" => true,
|
256
|
+
"readEnabled" => true,
|
257
|
+
"editEnabled" => true,
|
258
|
+
"addEnabled" => true,
|
259
|
+
"deleteEnabled" => true,
|
260
|
+
"exportEnabled" => true
|
261
|
+
},
|
262
|
+
"actions" => { }
|
263
|
+
},
|
264
|
+
},
|
265
|
+
'renderings' => scope_permissions
|
266
|
+
},
|
267
|
+
"meta" => {
|
268
|
+
"rolesACLActivated" => true
|
269
|
+
}
|
270
|
+
}
|
271
|
+
}
|
272
|
+
let(:api_permissions_scope_only) {
|
273
|
+
{
|
274
|
+
"data" => {
|
275
|
+
'collections' => { },
|
276
|
+
'renderings' => scope_permissions
|
277
|
+
},
|
278
|
+
"meta" => {
|
279
|
+
"rolesACLActivated" => true
|
280
|
+
}
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
before do
|
285
|
+
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(rendering_id).and_return(api_permissions)
|
286
|
+
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true).and_return(api_permissions_scope_only)
|
287
|
+
end
|
288
|
+
|
289
|
+
context 'when checking once for authorization' do
|
290
|
+
context 'when checking browseEnabled' do
|
291
|
+
context 'when expiration value is set to its default' do
|
292
|
+
it 'should not call the API to refresh the scopes cache' do
|
293
|
+
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
294
|
+
|
295
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
|
296
|
+
expect(ForestLiana::PermissionsGetter).not_to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
context 'when expiration value is set in the past' do
|
301
|
+
before do
|
302
|
+
allow(ENV).to receive(:[]).with('FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS').and_return('-1')
|
303
|
+
# Needed to enforce ENV stub
|
304
|
+
described_class.empty_cache
|
305
|
+
end
|
306
|
+
|
307
|
+
it 'should call the API to refresh the scopes cache' do
|
308
|
+
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
309
|
+
|
310
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
|
311
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true).once
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
# Only browse permission requires scopes
|
317
|
+
context 'when checking exportEnabled' do
|
318
|
+
context 'when expiration value is set in the past' do
|
319
|
+
before do
|
320
|
+
allow(ENV).to receive(:[]).with('FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS').and_return('-1')
|
321
|
+
# Needed to enforce ENV stub
|
322
|
+
described_class.empty_cache
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'should NOT call the API to refresh the scopes cache' do
|
327
|
+
described_class.new(fake_ressource, 'exportEnabled', rendering_id, user_id: user_id).is_authorized?
|
328
|
+
|
329
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
|
330
|
+
expect(ForestLiana::PermissionsGetter).not_to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
context 'when checking twice for authorization' do
|
336
|
+
context 'on the same rendering' do
|
337
|
+
context 'when scopes permission has NOT expired' do
|
338
|
+
it 'should NOT call the API to refresh the scopes permissions' do
|
339
|
+
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
340
|
+
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
341
|
+
|
342
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
|
343
|
+
expect(ForestLiana::PermissionsGetter).not_to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
context 'when scopes permission has expired' do
|
348
|
+
before do
|
349
|
+
allow(ENV).to receive(:[]).with('FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS').and_return('-1')
|
350
|
+
# Needed to enforce ENV stub
|
351
|
+
described_class.empty_cache
|
352
|
+
end
|
353
|
+
|
354
|
+
it 'should call the API to refresh the scopes permissions' do
|
355
|
+
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
356
|
+
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
357
|
+
|
358
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).twice
|
359
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true).twice
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
context 'on two different renderings' do
|
365
|
+
let(:other_rendering_id) { 2 }
|
366
|
+
let(:api_permissions_scope_only) {
|
367
|
+
{
|
368
|
+
"data" => {
|
369
|
+
'collections' => { },
|
370
|
+
'renderings' => {
|
371
|
+
'2' => { 'custom' => nil }
|
372
|
+
}
|
373
|
+
},
|
374
|
+
"meta" => {
|
375
|
+
"rolesACLActivated" => true
|
376
|
+
}
|
377
|
+
}
|
378
|
+
}
|
379
|
+
|
380
|
+
before do
|
381
|
+
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(other_rendering_id, rendering_specific_only: true).and_return(api_permissions_scope_only)
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'should call the API to refresh the scopes permissions' do
|
385
|
+
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
386
|
+
described_class.new(fake_ressource, 'browseEnabled', other_rendering_id, user_id: user_id).is_authorized?
|
387
|
+
|
388
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
|
389
|
+
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(other_rendering_id, rendering_specific_only: true).once
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
describe '#is_authorized?' do
|
397
|
+
# Resource is only used to retrieve the collection name as it's stub it does not
|
398
|
+
# need to be defined
|
399
|
+
let(:fake_ressource) { nil }
|
400
|
+
let(:default_rendering_id) { nil }
|
401
|
+
let(:api_permissions) { default_api_permissions }
|
402
|
+
|
403
|
+
before do
|
404
|
+
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).and_return(api_permissions)
|
405
|
+
end
|
406
|
+
|
407
|
+
context 'when permissions have rolesACLActivated' do
|
408
|
+
context 'with true/false permission values' do
|
409
|
+
let(:collection_name) { 'all_rights_collection_boolean' }
|
410
|
+
|
411
|
+
describe 'exportEnabled permission' do
|
412
|
+
subject { described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id) }
|
413
|
+
|
414
|
+
context 'when user has the required permission' do
|
415
|
+
it 'should be authorized' do
|
416
|
+
expect(subject.is_authorized?).to be true
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
context 'when user has not the required permission' do
|
421
|
+
let(:collection_name) { 'no_rights_collection_boolean' }
|
422
|
+
|
423
|
+
it 'should NOT be authorized' do
|
424
|
+
expect(subject.is_authorized?).to be false
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
describe 'browseEnbled permission' do
|
430
|
+
let(:collection_list_parameters) { { :user_id => "1", :filters => nil } }
|
431
|
+
subject {
|
432
|
+
described_class.new(
|
433
|
+
fake_ressource,
|
434
|
+
'browseEnabled',
|
435
|
+
default_rendering_id,
|
436
|
+
user_id: user_id,
|
437
|
+
collection_list_parameters: collection_list_parameters
|
438
|
+
)
|
439
|
+
}
|
440
|
+
|
441
|
+
context 'when user has the required permission' do
|
442
|
+
it 'should be authorized' do
|
443
|
+
expect(subject.is_authorized?).to be true
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
context 'when user has not the required permission' do
|
448
|
+
let(:collection_name) { 'no_rights_collection_boolean' }
|
449
|
+
|
450
|
+
it 'should NOT be authorized' do
|
451
|
+
expect(subject.is_authorized?).to be false
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
context 'when scopes are defined' do
|
456
|
+
let(:default_rendering_id) { 1 }
|
457
|
+
let(:scope_permissions) {
|
458
|
+
{
|
459
|
+
default_rendering_id => {
|
460
|
+
collection_name => {
|
461
|
+
'scope' => {
|
462
|
+
'dynamicScopesValues' => {},
|
463
|
+
'filter' => { 'aggregator' => 'and', 'conditions' => [condition] }
|
464
|
+
}
|
465
|
+
}
|
466
|
+
}
|
467
|
+
}
|
468
|
+
}
|
469
|
+
let(:collection_list_parameters) { { :user_id => "1", :filters => JSON.generate(condition) } }
|
470
|
+
|
471
|
+
context 'when scopes are passing validation' do
|
472
|
+
context 'when scope value is a string' do
|
473
|
+
let(:condition) { { 'field' => 'field_1', 'operator' => 'equal', 'value' => true } }
|
474
|
+
|
475
|
+
it 'should return true' do
|
476
|
+
expect(subject.is_authorized?).to be true
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
context 'when scope value is a boolean' do
|
481
|
+
let(:condition) { { 'field' => 'field_1', 'operator' => 'equal', 'value' => 'true' } }
|
482
|
+
|
483
|
+
it 'should return true' do
|
484
|
+
expect(subject.is_authorized?).to be true
|
485
|
+
end
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
context 'when scopes are NOT passing validation' do
|
490
|
+
let(:condition) { { 'field' => 'field_1', 'operator' => 'equal', 'value' => true } }
|
491
|
+
let(:other_condition) {
|
492
|
+
{
|
493
|
+
aggregator: 'and',
|
494
|
+
conditions: [
|
495
|
+
{ field: 'name', value: 'john', operator: 'equal' },
|
496
|
+
{ field: 'price', value: '2500', operator: 'equal' }
|
497
|
+
]
|
498
|
+
}
|
499
|
+
}
|
500
|
+
let(:collection_list_parameters) {
|
501
|
+
{
|
502
|
+
:user_id => "1",
|
503
|
+
:filters => JSON.generate(other_condition)
|
504
|
+
}
|
505
|
+
}
|
506
|
+
|
507
|
+
it 'should return false' do
|
508
|
+
expect(subject.is_authorized?).to be false
|
509
|
+
end
|
510
|
+
end
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
describe 'readEnabled permission' do
|
515
|
+
subject { described_class.new(fake_ressource, 'readEnabled', default_rendering_id, user_id: user_id) }
|
516
|
+
|
517
|
+
context 'when user has the required permission' do
|
518
|
+
it 'should be authorized' do
|
519
|
+
expect(subject.is_authorized?).to be true
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
context 'when user has not the required permission' do
|
524
|
+
let(:collection_name) { 'no_rights_collection_boolean' }
|
525
|
+
|
526
|
+
it 'should NOT be authorized' do
|
527
|
+
expect(subject.is_authorized?).to be false
|
528
|
+
end
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
describe 'addEnabled permission' do
|
533
|
+
subject { described_class.new(fake_ressource, 'addEnabled', default_rendering_id, user_id: user_id) }
|
534
|
+
|
535
|
+
context 'when user has the required permission' do
|
536
|
+
it 'should be authorized' do
|
537
|
+
expect(subject.is_authorized?).to be true
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
context 'when user has not the required permission' do
|
542
|
+
let(:collection_name) { 'no_rights_collection_boolean' }
|
543
|
+
|
544
|
+
it 'should NOT be authorized' do
|
545
|
+
expect(subject.is_authorized?).to be false
|
546
|
+
end
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
describe 'editEnabled permission' do
|
551
|
+
subject { described_class.new(fake_ressource, 'editEnabled', default_rendering_id, user_id: user_id) }
|
552
|
+
|
553
|
+
context 'when user has the required permission' do
|
554
|
+
it 'should be authorized' do
|
555
|
+
expect(subject.is_authorized?).to be true
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
context 'when user has not the required permission' do
|
560
|
+
let(:collection_name) { 'no_rights_collection_boolean' }
|
561
|
+
|
562
|
+
it 'should NOT be authorized' do
|
563
|
+
expect(subject.is_authorized?).to be false
|
564
|
+
end
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
describe 'deleteEnabled permission' do
|
569
|
+
subject { described_class.new(fake_ressource, 'deleteEnabled', default_rendering_id, user_id: user_id) }
|
570
|
+
|
571
|
+
context 'when user has the required permission' do
|
572
|
+
it 'should be authorized' do
|
573
|
+
expect(subject.is_authorized?).to be true
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
context 'when user has not the required permission' do
|
578
|
+
let(:collection_name) { 'no_rights_collection_boolean' }
|
579
|
+
|
580
|
+
it 'should NOT be authorized' do
|
581
|
+
expect(subject.is_authorized?).to be false
|
582
|
+
end
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
describe 'actions permission' do
|
587
|
+
let(:smart_action_request_info) { { endpoint: 'forest/actions/Test', http_method: 'POST' } }
|
588
|
+
subject {
|
589
|
+
described_class.new(
|
590
|
+
fake_ressource,
|
591
|
+
'actions',
|
592
|
+
default_rendering_id,
|
593
|
+
user_id: user_id,
|
594
|
+
smart_action_request_info: smart_action_request_info
|
595
|
+
)
|
596
|
+
}
|
597
|
+
|
598
|
+
context 'when user has the required permission' do
|
599
|
+
it 'should be authorized' do
|
600
|
+
expect(subject.is_authorized?).to be true
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
context 'when user has not the required permission' do
|
605
|
+
let(:collection_name) { 'no_rights_collection_boolean' }
|
606
|
+
|
607
|
+
it 'should NOT be authorized' do
|
608
|
+
expect(subject.is_authorized?).to be false
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
context 'when endpoint is missing from smart action parameters' do
|
613
|
+
let(:smart_action_request_info) { { http_method: 'POST' } }
|
614
|
+
|
615
|
+
it 'user should NOT be authorized' do
|
616
|
+
expect(subject.is_authorized?).to be false
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
context 'when http_method is missing from smart action parameters' do
|
621
|
+
let(:smart_action_request_info) { { endpoint: 'forest/actions/Test' } }
|
622
|
+
|
623
|
+
it 'user should NOT be authorized' do
|
624
|
+
expect(subject.is_authorized?).to be false
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
context 'when the provided endpoint is not part of the schema' do
|
629
|
+
let(:smart_action_request_info) { { endpoint: 'forest/actions/Test', http_method: 'DELETE' } }
|
630
|
+
|
631
|
+
it 'user should NOT be authorized' do
|
632
|
+
expect(subject.is_authorized?).to be false
|
633
|
+
end
|
634
|
+
end
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
context 'with userId list permission values' do
|
639
|
+
let(:collection_name) { 'all_rights_collection_user_list' }
|
640
|
+
|
641
|
+
describe 'exportEnabled permission' do
|
642
|
+
subject { described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id) }
|
643
|
+
|
644
|
+
context 'when user has the required permission' do
|
645
|
+
it 'should be authorized' do
|
646
|
+
expect(subject.is_authorized?).to be true
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
context 'when user has not the required permission' do
|
651
|
+
let(:collection_name) { 'no_rights_collection_user_list' }
|
652
|
+
|
653
|
+
it 'should NOT be authorized' do
|
654
|
+
expect(subject.is_authorized?).to be false
|
655
|
+
end
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
describe 'browseEnabled permission' do
|
660
|
+
let(:collection_list_parameters) { { :user_id => "1", :filters => nil } }
|
661
|
+
subject {
|
662
|
+
described_class.new(
|
663
|
+
fake_ressource,
|
664
|
+
'browseEnabled',
|
665
|
+
default_rendering_id,
|
666
|
+
user_id: user_id,
|
667
|
+
collection_list_parameters: collection_list_parameters
|
668
|
+
)
|
669
|
+
}
|
670
|
+
|
671
|
+
context 'when user has the required permission' do
|
672
|
+
it 'should be authorized' do
|
673
|
+
expect(subject.is_authorized?).to be true
|
674
|
+
end
|
675
|
+
end
|
676
|
+
|
677
|
+
context 'when user has not the required permission' do
|
678
|
+
let(:collection_name) { 'no_rights_collection_user_list' }
|
679
|
+
|
680
|
+
it 'should NOT be authorized' do
|
681
|
+
expect(subject.is_authorized?).to be false
|
682
|
+
end
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
686
|
+
describe 'readEnabled permission' do
|
687
|
+
subject { described_class.new(fake_ressource, 'readEnabled', default_rendering_id, user_id: user_id) }
|
688
|
+
|
689
|
+
context 'when user has the required permission' do
|
690
|
+
it 'should be authorized' do
|
691
|
+
expect(subject.is_authorized?).to be true
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
context 'when user has not the required permission' do
|
696
|
+
let(:collection_name) { 'no_rights_collection_user_list' }
|
697
|
+
|
698
|
+
it 'should NOT be authorized' do
|
699
|
+
expect(subject.is_authorized?).to be false
|
700
|
+
end
|
701
|
+
end
|
702
|
+
end
|
703
|
+
|
704
|
+
describe 'addEnabled permission' do
|
705
|
+
subject { described_class.new(fake_ressource, 'addEnabled', default_rendering_id, user_id: user_id) }
|
706
|
+
|
707
|
+
context 'when user has the required permission' do
|
708
|
+
it 'should be authorized' do
|
709
|
+
expect(subject.is_authorized?).to be true
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
context 'when user has not the required permission' do
|
714
|
+
let(:collection_name) { 'no_rights_collection_user_list' }
|
715
|
+
|
716
|
+
it 'should NOT be authorized' do
|
717
|
+
expect(subject.is_authorized?).to be false
|
718
|
+
end
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
722
|
+
describe 'editEnabled permission' do
|
723
|
+
subject { described_class.new(fake_ressource, 'editEnabled', default_rendering_id, user_id: user_id) }
|
724
|
+
|
725
|
+
context 'when user has the required permission' do
|
726
|
+
it 'should be authorized' do
|
727
|
+
expect(subject.is_authorized?).to be true
|
728
|
+
end
|
729
|
+
end
|
730
|
+
|
731
|
+
context 'when user has not the required permission' do
|
732
|
+
let(:collection_name) { 'no_rights_collection_user_list' }
|
733
|
+
|
734
|
+
it 'should NOT be authorized' do
|
735
|
+
expect(subject.is_authorized?).to be false
|
736
|
+
end
|
737
|
+
end
|
738
|
+
end
|
739
|
+
|
740
|
+
describe 'deleteEnabled permission' do
|
741
|
+
subject { described_class.new(fake_ressource, 'deleteEnabled', default_rendering_id, user_id: user_id) }
|
742
|
+
|
743
|
+
context 'when user has the required permission' do
|
744
|
+
it 'should be authorized' do
|
745
|
+
expect(subject.is_authorized?).to be true
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
context 'when user has not the required permission' do
|
750
|
+
let(:collection_name) { 'no_rights_collection_user_list' }
|
751
|
+
|
752
|
+
it 'should NOT be authorized' do
|
753
|
+
expect(subject.is_authorized?).to be false
|
754
|
+
end
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
758
|
+
describe 'actions permission' do
|
759
|
+
let(:smart_action_request_info) { { endpoint: 'forest/actions/Test', http_method: 'POST' } }
|
760
|
+
subject {
|
761
|
+
described_class.new(
|
762
|
+
fake_ressource,
|
763
|
+
'actions',
|
764
|
+
default_rendering_id,
|
765
|
+
user_id: user_id,
|
766
|
+
smart_action_request_info: smart_action_request_info
|
767
|
+
)
|
768
|
+
}
|
769
|
+
|
770
|
+
context 'when user has the required permission' do
|
771
|
+
it 'should be authorized' do
|
772
|
+
expect(subject.is_authorized?).to be true
|
773
|
+
end
|
774
|
+
end
|
775
|
+
|
776
|
+
context 'when user has not the required permission' do
|
777
|
+
let(:collection_name) { 'no_rights_collection_user_list' }
|
778
|
+
|
779
|
+
it 'should NOT be authorized' do
|
780
|
+
expect(subject.is_authorized?).to be false
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
784
|
+
context 'when endpoint is missing from smart action parameters' do
|
785
|
+
let(:smart_action_request_info) { { http_method: 'POST' } }
|
786
|
+
|
787
|
+
it 'user should NOT be authorized' do
|
788
|
+
expect(subject.is_authorized?).to be false
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
792
|
+
context 'when http_method is missing from smart action parameters' do
|
793
|
+
let(:smart_action_request_info) { { endpoint: 'forest/actions/Test' } }
|
794
|
+
|
795
|
+
it 'user should NOT be authorized' do
|
796
|
+
expect(subject.is_authorized?).to be false
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
context 'when the provided endpoint is not part of the schema' do
|
801
|
+
let(:smart_action_request_info) { { endpoint: 'forest/actions/Test', http_method: 'DELETE' } }
|
802
|
+
|
803
|
+
it 'user should NOT be authorized' do
|
804
|
+
expect(subject.is_authorized?).to be false
|
805
|
+
end
|
806
|
+
end
|
807
|
+
end
|
808
|
+
|
809
|
+
# searchToEdit permission checker should not be called anymore once rolesAcl activated
|
810
|
+
describe 'searchToEdit permission' do
|
811
|
+
subject { described_class.new(fake_ressource, 'searchToEdit', default_rendering_id, user_id: user_id) }
|
812
|
+
|
813
|
+
context 'when user has all permissions' do
|
814
|
+
it 'should NOT be authorized' do
|
815
|
+
expect(subject.is_authorized?).to be false
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
819
|
+
context 'when user has no permissions' do
|
820
|
+
let(:collection_name) { 'no_rights_collection_user_list' }
|
821
|
+
|
822
|
+
it 'should NOT be authorized' do
|
823
|
+
expect(subject.is_authorized?).to be false
|
824
|
+
end
|
825
|
+
end
|
826
|
+
end
|
827
|
+
end
|
828
|
+
end
|
829
|
+
end
|
830
|
+
end
|
831
|
+
end
|