policy_machine 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CONTRIBUTING.md +35 -0
  2. data/Gemfile +2 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +98 -0
  5. data/lib/generators/policy_machine/policy_machine_generator.rb +13 -0
  6. data/lib/generators/policy_machine/templates/migration.rb +40 -0
  7. data/lib/policy_machine.rb +236 -0
  8. data/lib/policy_machine/association.rb +73 -0
  9. data/lib/policy_machine/policy_element.rb +269 -0
  10. data/lib/policy_machine/version.rb +3 -0
  11. data/lib/policy_machine_storage_adapters/active_record.rb +306 -0
  12. data/lib/policy_machine_storage_adapters/in_memory.rb +266 -0
  13. data/lib/policy_machine_storage_adapters/neography.rb +236 -0
  14. data/lib/policy_machine_storage_adapters/template.rb +169 -0
  15. data/lib/tasks/policy_machine_tasks.rake +4 -0
  16. data/policy_machine.gemspec +23 -0
  17. data/spec/policy_machine/association_spec.rb +61 -0
  18. data/spec/policy_machine/policy_element_spec.rb +20 -0
  19. data/spec/policy_machine_spec.rb +7 -0
  20. data/spec/policy_machine_storage_adapters/active_record_spec.rb +54 -0
  21. data/spec/policy_machine_storage_adapters/in_memory_spec.rb +13 -0
  22. data/spec/policy_machine_storage_adapters/neography_spec.rb +42 -0
  23. data/spec/policy_machine_storage_adapters/template_spec.rb +6 -0
  24. data/spec/spec_helper.rb +24 -0
  25. data/spec/support/neography_helpers.rb +39 -0
  26. data/spec/support/policy_machine_helpers.rb +22 -0
  27. data/spec/support/shared_examples_policy_machine_spec.rb +697 -0
  28. data/spec/support/shared_examples_policy_machine_storage_adapter_spec.rb +278 -0
  29. data/spec/support/shared_examples_storage_adapter_public_methods.rb +20 -0
  30. data/spec/support/storage_adapter_helpers.rb +7 -0
  31. data/test/dummy/Rakefile +7 -0
  32. data/test/dummy/app/controllers/application_controller.rb +3 -0
  33. data/test/dummy/app/helpers/application_helper.rb +2 -0
  34. data/test/dummy/app/models/.gitkeep +0 -0
  35. data/test/dummy/config.ru +4 -0
  36. data/test/dummy/config/application.rb +65 -0
  37. data/test/dummy/config/boot.rb +10 -0
  38. data/test/dummy/config/database.yml +42 -0
  39. data/test/dummy/config/environment.rb +5 -0
  40. data/test/dummy/config/environments/development.rb +37 -0
  41. data/test/dummy/config/environments/test.rb +37 -0
  42. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  43. data/test/dummy/config/initializers/inflections.rb +15 -0
  44. data/test/dummy/config/initializers/mime_types.rb +5 -0
  45. data/test/dummy/config/initializers/secret_token.rb +7 -0
  46. data/test/dummy/config/initializers/session_store.rb +8 -0
  47. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  48. data/test/dummy/config/routes.rb +58 -0
  49. data/test/dummy/db/migrate/20131015214828_generate_policy_machine.rb +40 -0
  50. data/test/dummy/db/migrate/20131021221759_add_color_to_policy_element.rb +5 -0
  51. data/test/dummy/db/schema.rb +57 -0
  52. data/test/dummy/lib/assets/.gitkeep +0 -0
  53. data/test/dummy/script/rails +6 -0
  54. data/test/policy_machine_test.rb +7 -0
  55. data/test/test_helper.rb +15 -0
  56. metadata +270 -0
@@ -0,0 +1,22 @@
1
+ # This file contains helper methods to test assertions on policy machines
2
+
3
+ # Make sure each expected privilege has been returned
4
+ def assert_pm_privilege_expectations(actual_privileges, expected_privileges)
5
+ expected_privileges.each do |ep|
6
+ u_id = ep[0].unique_identifier
7
+ op_id = ep[1].unique_identifier
8
+ obj_id = ep[2].unique_identifier
9
+
10
+ found_actual_priv = actual_privileges.find do |priv|
11
+ priv[0].unique_identifier == u_id &&
12
+ priv[1].unique_identifier == op_id &&
13
+ priv[2].unique_identifier == obj_id
14
+ end
15
+
16
+ pp("expected to find #{[u_id, op_id, obj_id]}") if found_actual_priv.nil?
17
+
18
+ found_actual_priv.should_not be_nil
19
+ end
20
+
21
+ actual_privileges.count.should == expected_privileges.size
22
+ end
@@ -0,0 +1,697 @@
1
+ require 'spec_helper'
2
+ require_relative 'storage_adapter_helpers.rb'
3
+
4
+ policy_element_types = ::PolicyMachine::POLICY_ELEMENT_TYPES
5
+
6
+ shared_examples "a policy machine" do
7
+ describe 'instantiation' do
8
+ it 'has a default name' do
9
+ PolicyMachine.new.name.length.should_not == 0
10
+ end
11
+
12
+ it 'can be named' do
13
+ ['name', :name].each do |key|
14
+ PolicyMachine.new(key => 'my name').name.should == 'my name'
15
+ end
16
+ end
17
+
18
+ it 'sets the uuid if not specified' do
19
+ PolicyMachine.new.uuid.length.should_not == 0
20
+ end
21
+
22
+ it 'allows uuid to be specified' do
23
+ ['uuid', :uuid].each do |key|
24
+ PolicyMachine.new(key => 'my uuid').uuid.should == 'my uuid'
25
+ end
26
+ end
27
+
28
+ it 'raises when uuid is blank' do
29
+ ['', ' '].each do |blank_value|
30
+ expect{ PolicyMachine.new(:uuid => blank_value) }.
31
+ to raise_error(ArgumentError, 'uuid cannot be blank')
32
+ end
33
+ end
34
+
35
+ it 'defaults to in-memory storage adapter' do
36
+ PolicyMachine.new.policy_machine_storage_adapter.should be_a(::PolicyMachineStorageAdapter::InMemory)
37
+ end
38
+
39
+ it 'allows user to set storage adapter' do
40
+ ['storage_adapter', :storage_adapter].each do |key|
41
+ PolicyMachine.new(key => ::PolicyMachineStorageAdapter::Neography).policy_machine_storage_adapter.
42
+ should be_a(::PolicyMachineStorageAdapter::Neography)
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ describe 'Assignments' do
49
+ allowed_assignments = [
50
+ ['object', 'object'],
51
+ ['object', 'object_attribute'],
52
+ ['object_attribute', 'object_attribute'],
53
+ ['object_attribute', 'object'],
54
+ ['user', 'user_attribute'],
55
+ ['user_attribute', 'user_attribute'],
56
+ ['user_attribute', 'policy_class'],
57
+ ['object_attribute', 'policy_class']
58
+ ]
59
+
60
+ # Add an assignment e.g. o -> oa or oa -> oa or u -> ua or ua -> ua.
61
+ describe 'Adding' do
62
+ allowed_assignments.each do |allowed_assignment|
63
+ it "allows a #{allowed_assignment[0]} to be assigned a #{allowed_assignment[1]} (returns true)" do
64
+ pe0 = policy_machine.send("create_#{allowed_assignment[0]}", SecureRandom.uuid)
65
+ pe1 = policy_machine.send("create_#{allowed_assignment[1]}", SecureRandom.uuid)
66
+
67
+ policy_machine.add_assignment(pe0, pe1).should be_true
68
+ end
69
+ end
70
+
71
+ disallowed_assignments = policy_element_types.product(policy_element_types) - allowed_assignments
72
+ disallowed_assignments.each do |disallowed_assignment|
73
+ it "does not allow a #{disallowed_assignment[0]} to be assigned a #{disallowed_assignment[1]} (raises)" do
74
+ pe0 = policy_machine.send("create_#{disallowed_assignment[0]}", SecureRandom.uuid)
75
+ pe1 = policy_machine.send("create_#{disallowed_assignment[1]}", SecureRandom.uuid)
76
+
77
+ expect{ policy_machine.add_assignment(pe0, pe1) }.to raise_error(ArgumentError)
78
+ end
79
+ end
80
+
81
+ it 'raises when first argument is not a policy element' do
82
+ pe = policy_machine.create_user_attribute(SecureRandom.uuid)
83
+ expect{ policy_machine.add_assignment(1, pe) }.
84
+ to raise_error(ArgumentError, "arg must each be a kind of PolicyElement; got Fixnum instead")
85
+ end
86
+
87
+ it 'raises when first argument is not in policy machine' do
88
+ pm2 = PolicyMachine.new
89
+ pe0 = pm2.create_user_attribute(SecureRandom.uuid)
90
+ pe1 = policy_machine.create_user_attribute(SecureRandom.uuid)
91
+ expect{ policy_machine.add_assignment(pe0, pe1) }.
92
+ to raise_error(ArgumentError, "#{pe0.unique_identifier} is not in policy machine with uuid #{policy_machine.uuid}")
93
+ end
94
+
95
+ it 'raises when second argument is not a policy element' do
96
+ pe = policy_machine.create_user_attribute(SecureRandom.uuid)
97
+ expect{ policy_machine.add_assignment(pe, "hello") }.
98
+ to raise_error(ArgumentError, "arg must each be a kind of PolicyElement; got String instead")
99
+ end
100
+
101
+ it 'raises when second argument is not in policy machine' do
102
+ pm2 = PolicyMachine.new
103
+ pe0 = policy_machine.create_user_attribute(SecureRandom.uuid)
104
+ pe1 = pm2.create_user_attribute(SecureRandom.uuid)
105
+ expect{ policy_machine.add_assignment(pe0, pe1) }.
106
+ to raise_error(ArgumentError, "#{pe1.unique_identifier} is not in policy machine with uuid #{policy_machine.uuid}")
107
+ end
108
+ end
109
+
110
+ describe 'Removing' do
111
+ before do
112
+ @pe0 = policy_machine.create_user(SecureRandom.uuid)
113
+ @pe1 = policy_machine.create_user_attribute(SecureRandom.uuid)
114
+ end
115
+
116
+ it 'removes an existing assignment (returns true)' do
117
+ policy_machine.add_assignment(@pe0, @pe1)
118
+ policy_machine.remove_assignment(@pe0, @pe1).should be_true
119
+ end
120
+
121
+ it 'does not remove a non-existant assignment (returns false)' do
122
+ policy_machine.remove_assignment(@pe0, @pe1).should be_false
123
+ end
124
+
125
+ it 'raises when first argument is not a policy element' do
126
+ expect{ policy_machine.add_assignment(1, @pe1) }.
127
+ to raise_error(ArgumentError, "arg must each be a kind of PolicyElement; got Fixnum instead")
128
+ end
129
+
130
+ it 'raises when first argument is not in policy machine' do
131
+ pm2 = PolicyMachine.new
132
+ pe0 = pm2.create_user_attribute(SecureRandom.uuid)
133
+ pe1 = policy_machine.create_user_attribute(SecureRandom.uuid)
134
+ expect{ policy_machine.remove_assignment(pe0, pe1) }.
135
+ to raise_error(ArgumentError, "#{pe0.unique_identifier} is not in policy machine with uuid #{policy_machine.uuid}")
136
+ end
137
+
138
+ it 'raises when second argument is not a policy element' do
139
+ expect{ policy_machine.add_assignment(@pe0, "hello") }.
140
+ to raise_error(ArgumentError, "arg must each be a kind of PolicyElement; got String instead")
141
+ end
142
+
143
+ it 'raises when second argument is not in policy machine' do
144
+ pm2 = PolicyMachine.new
145
+ pe0 = policy_machine.create_user_attribute(SecureRandom.uuid)
146
+ pe1 = pm2.create_user_attribute(SecureRandom.uuid)
147
+ expect{ policy_machine.remove_assignment(pe0, pe1) }.
148
+ to raise_error(ArgumentError, "#{pe1.unique_identifier} is not in policy machine with uuid #{policy_machine.uuid}")
149
+ end
150
+ end
151
+ end
152
+
153
+ describe 'Associations' do
154
+ describe 'Adding' do
155
+ before do
156
+ @object_attribute = policy_machine.create_object_attribute('OA name')
157
+ @operation1 = policy_machine.create_operation('read')
158
+ @operation2 = policy_machine.create_operation('write')
159
+ @operation_set = Set.new [@operation1, @operation2]
160
+ @user_attribute = policy_machine.create_user_attribute('UA name')
161
+ end
162
+
163
+ it 'raises when first argument is not a PolicyElement' do
164
+ expect{ policy_machine.add_association("234", @operation_set, @object_attribute) }
165
+ .to raise_error(ArgumentError, "arg must each be a kind of PolicyElement; got String instead")
166
+ end
167
+
168
+ it 'raises when first argument is not in policy machine' do
169
+ pm2 = PolicyMachine.new
170
+ ua = pm2.create_user_attribute(SecureRandom.uuid)
171
+ expect{ policy_machine.add_association(ua, @operation_set, @object_attribute) }.
172
+ to raise_error(ArgumentError, "#{ua.unique_identifier} is not in policy machine with uuid #{policy_machine.uuid}")
173
+ end
174
+
175
+ it 'raises when third argument is not a PolicyElement' do
176
+ expect{ policy_machine.add_association(@user_attribute, @operation_set, 3) }
177
+ .to raise_error(ArgumentError, "arg must each be a kind of PolicyElement; got Fixnum instead")
178
+ end
179
+
180
+ it 'raises when third argument is not in policy machine' do
181
+ pm2 = PolicyMachine.new
182
+ oa = pm2.create_object_attribute(SecureRandom.uuid)
183
+ expect{ policy_machine.add_association(@user_attribute, @operation_set, oa) }.
184
+ to raise_error(ArgumentError, "#{oa.unique_identifier} is not in policy machine with uuid #{policy_machine.uuid}")
185
+ end
186
+
187
+ it 'allows an association to be made between an existing user_attribute, operation set and object attribute (returns true)' do
188
+ policy_machine.add_association(@user_attribute, @operation_set, @object_attribute).should be_true
189
+ end
190
+ end
191
+ end
192
+
193
+ describe 'All methods for policy elements' do
194
+ (PolicyMachine::POLICY_ELEMENT_TYPES - %w(policy_class)).each do |pe_type|
195
+ it "returns an array of all #{pe_type.to_s.pluralize}" do
196
+ pe = policy_machine.send("create_#{pe_type}", 'some name')
197
+ policy_machine.send(pe_type.to_s.pluralize).should == [pe]
198
+ end
199
+
200
+ it "scopes by policy machine when finding an array of #{pe_type.to_s.pluralize}" do
201
+ pe = policy_machine.send("create_#{pe_type}", 'some name')
202
+ other_pm = PolicyMachine.new
203
+ pe_in_other_machine = other_pm.send("create_#{pe_type}", 'some name')
204
+ policy_machine.send(pe_type.to_s.pluralize).should == [pe]
205
+ end
206
+ end
207
+
208
+ (PolicyMachine::POLICY_ELEMENT_TYPES - %w(user user_attribute object object_attribute operation)).each do |pe_type|
209
+ it "raises when calling #{pe_type.to_s.pluralize}" do
210
+ pe = policy_machine.send("create_#{pe_type}", 'some name')
211
+ expect{ policy_machine.send(pe_type.to_s.pluralize) }.
212
+ to raise_error(NoMethodError)
213
+ end
214
+ end
215
+ end
216
+
217
+ describe 'User Attributes' do
218
+
219
+ describe '#extra_attributes' do
220
+
221
+ it 'accepts and persists arbitrary extra attributes' do
222
+ @ua = policy_machine.create_user_attribute('ua1', foo: 'bar')
223
+ @ua.foo.should == 'bar'
224
+ policy_machine.user_attributes.last.foo.should == 'bar'
225
+ end
226
+
227
+ end
228
+
229
+ describe '#delete' do
230
+
231
+ it 'successfully deletes itself' do
232
+ @ua = policy_machine.create_user_attribute('ua1')
233
+ @ua.delete
234
+ policy_machine.user_attributes.should_not include(@ua)
235
+ end
236
+
237
+ end
238
+
239
+ end
240
+
241
+ describe 'Users' do
242
+
243
+ describe '#extra_attributes' do
244
+
245
+ it 'accepts and persists arbitrary extra attributes' do
246
+ @u = policy_machine.create_user('u1', foo: 'bar')
247
+ @u.foo.should == 'bar'
248
+ policy_machine.users.last.foo.should == 'bar'
249
+ end
250
+
251
+ it 'updates persisted extra attributes' do
252
+ @u = policy_machine.create_user('u1', foo: 'bar')
253
+ @u.update(foo: 'baz')
254
+ @u.foo.should == 'baz'
255
+ policy_machine.users.last.foo.should == 'baz'
256
+ end
257
+
258
+ it 'does not remove old attributes when adding new ones' do
259
+ @u = policy_machine.create_user('u1', foo: 'bar')
260
+ @u.update(deleted: true)
261
+ @u.foo.should == 'bar'
262
+ policy_machine.users.last.foo.should == 'bar'
263
+ end
264
+
265
+ it 'allows searching on any extra attribute keys' do
266
+ policy_machine.create_user('u1', foo: 'bar')
267
+ policy_machine.create_user('u2', foo: nil, attitude: 'sassy')
268
+ silence_warnings do
269
+ policy_machine.users(foo: 'bar').should be_one
270
+ policy_machine.users(foo: nil).should be_one
271
+ policy_machine.users(foo: 'baz').should be_none
272
+ policy_machine.users(foo: 'bar', attitude: 'sassy').should be_none
273
+ end
274
+ end
275
+
276
+ end
277
+
278
+ end
279
+
280
+ describe '#is_privilege?' do
281
+ before do
282
+ # Define policy elements
283
+ @u1 = policy_machine.create_user('u1')
284
+ @o1 = policy_machine.create_object('o1')
285
+ @o2 = policy_machine.create_object('o2')
286
+ @group1 = policy_machine.create_user_attribute('Group1')
287
+ @project1 = policy_machine.create_object_attribute('Project1')
288
+ @w = policy_machine.create_operation('write')
289
+
290
+ # Assignments
291
+ policy_machine.add_assignment(@u1, @group1)
292
+ policy_machine.add_assignment(@o1, @project1)
293
+
294
+ # Associations
295
+ policy_machine.add_association(@group1, Set.new([@w]), @project1)
296
+ end
297
+
298
+ it 'raises when the first argument is not a user or user_attribute' do
299
+ expect{ policy_machine.is_privilege?(@o1, @w, @o1)}.
300
+ to raise_error(ArgumentError, "user_attribute_pe must be a User or UserAttribute.")
301
+ end
302
+
303
+ it 'raises when the second argument is not an operation' do
304
+ expect{ policy_machine.is_privilege?(@u1, @u1, @o1)}.
305
+ to raise_error(ArgumentError, "operation must be an Operation.")
306
+ end
307
+
308
+ it 'raises when the third argument is not an object or object_attribute' do
309
+ expect{ policy_machine.is_privilege?(@u1, @w, @u1)}.
310
+ to raise_error(ArgumentError, "object_or_attribute must either be an Object or ObjectAttribute.")
311
+ end
312
+
313
+ it 'returns true if privilege can be inferred from user, operation and object' do
314
+ policy_machine.is_privilege?(@u1, @w, @o1).should be_true
315
+ end
316
+
317
+ it 'returns true if privilege can be inferred from user_attribute, operation and object' do
318
+ policy_machine.is_privilege?(@group1, @w, @o1).should be_true
319
+ end
320
+
321
+ it 'returns true if privilege can be inferred from user, operation and object_attribute' do
322
+ policy_machine.is_privilege?(@u1, @w, @project1).should be_true
323
+ end
324
+
325
+ it 'returns false if privilege cannot be inferred from arguments' do
326
+ policy_machine.is_privilege?(@u1, @w, @o2).should be_false
327
+ end
328
+
329
+ it 'does not infer privileges from deleted attributes' do
330
+ @group1.delete
331
+ policy_machine.is_privilege?(@u1, @w, @o1).should be_false
332
+ end
333
+
334
+ describe 'options' do
335
+ describe 'associations' do
336
+ it 'raises unless options[:associations] is an Array' do
337
+ expect{ policy_machine.is_privilege?(@u1, @w, @o2, :associations => 4) }.
338
+ to raise_error(ArgumentError, "expected options[:associations] to be an Array; got Fixnum")
339
+ end
340
+
341
+ it 'raises if options[:associations] is an empty array' do
342
+ expect{ policy_machine.is_privilege?(@u1, @w, @o2, :associations => []) }.
343
+ to raise_error(ArgumentError, "options[:associations] cannot be empty")
344
+ end
345
+
346
+ it 'raises unless every element of options[:associations] is a PM::Association' do
347
+ expect{ policy_machine.is_privilege?(@u1, @w, @o2, :associations => [4]) }.
348
+ to raise_error(ArgumentError, "expected each element of options[:associations] to be a PM::Association")
349
+ end
350
+
351
+ it 'raises if no element of options[:associations] contains the given operation' do
352
+ e = policy_machine.create_operation('execute')
353
+ policy_machine.add_association(@group1, Set.new([e]), @project1)
354
+ policy_machine.is_privilege?(@u1, @w, @o2, :associations => e.associations).should be_false
355
+ end
356
+
357
+ it 'accepts associations in options[:associations]' do
358
+ policy_machine.is_privilege?(@u1, @w, @o1, :associations => @w.associations).should be_true
359
+ end
360
+
361
+ it "accepts associations in options['associations']" do
362
+ policy_machine.is_privilege?(@u1, @w, @o1, 'associations' => @w.associations).should be_true
363
+ end
364
+
365
+ it 'returns true when given association is part of the granting of a given privilege' do
366
+ policy_machine.is_privilege?(@u1, @w, @o1, 'associations' => @w.associations).should be_true
367
+ end
368
+
369
+ it 'returns false when given association is not part of the granting of a given privilege' do
370
+ group2 = policy_machine.create_user_attribute('Group2')
371
+
372
+ policy_machine.add_association(group2, Set.new([@w]), @project1)
373
+ policy_machine.is_privilege?(@u1, @w, @o1, 'associations' => [@w.associations.last]).should be_false
374
+ end
375
+ end
376
+
377
+ describe 'in_user_attribute' do
378
+ it 'raises unless options[:in_user_attribute] is a PM::UserAttribute' do
379
+ expect{ policy_machine.is_privilege?(@u1, @w, @o2, :in_user_attribute => 4) }.
380
+ to raise_error(ArgumentError, 'expected options[:in_user_attribute] to be a PM::UserAttribute; got Fixnum')
381
+ end
382
+
383
+ it 'accepts in_user_attribute in options[:in_user_attribute]' do
384
+ policy_machine.is_privilege?(@u1, @w, @o1, :in_user_attribute => @group1).should be_true
385
+ end
386
+
387
+ it "accepts in_user_attribute in options['in_user_attribute']" do
388
+ policy_machine.is_privilege?(@group1, @w, @o1, 'in_user_attribute' => @group1).should be_true
389
+ end
390
+
391
+ it 'returns false if given user is not in given in_user_attribute' do
392
+ group2 = policy_machine.create_user_attribute('Group2')
393
+ policy_machine.is_privilege?(@u1, @w, @o1, 'in_user_attribute' => group2).should be_false
394
+ end
395
+ end
396
+
397
+ describe 'in_object_attribute' do
398
+ it 'raises unless options[:in_object_attribute] is a PM::ObjectAttribute' do
399
+ expect{ policy_machine.is_privilege?(@u1, @w, @o2, :in_object_attribute => 4) }.
400
+ to raise_error(ArgumentError, 'expected options[:in_object_attribute] to be a PM::ObjectAttribute; got Fixnum')
401
+ end
402
+
403
+ it 'accepts in_object_attribute in options[:in_object_attribute]' do
404
+ policy_machine.is_privilege?(@u1, @w, @o1, :in_object_attribute => @project1).should be_true
405
+ end
406
+
407
+ it "accepts in_object_attribute in options['in_object_attribute']" do
408
+ policy_machine.is_privilege?(@u1, @w, @project1, 'in_object_attribute' => @project1).should be_true
409
+ end
410
+
411
+ it 'returns false if given user is not in given in_object_attribute' do
412
+ project2 = policy_machine.create_object_attribute('Project2')
413
+ policy_machine.is_privilege?(@u1, @w, @o1, 'in_object_attribute' => project2).should be_false
414
+ end
415
+
416
+ it 'accepts both in_user_attribute and in_object_attribute' do
417
+ project2 = policy_machine.create_object_attribute('Project2')
418
+ policy_machine.is_privilege?(@u1, @w, @o1, 'in_user_attribute' => @group1, 'in_object_attribute' => project2).
419
+ should be_false
420
+ end
421
+
422
+ end
423
+
424
+ end
425
+ end
426
+
427
+ describe '#list_user_attributes' do
428
+ before do
429
+ # Define policy elements
430
+ @u1 = policy_machine.create_user('u1')
431
+ @u2 = policy_machine.create_user('u2')
432
+ @group1 = policy_machine.create_user_attribute('Group1')
433
+ @group2 = policy_machine.create_user_attribute('Group2')
434
+ @subgroup1a = policy_machine.create_user_attribute('Subgroup1a')
435
+
436
+ # Assignments
437
+ policy_machine.add_assignment(@u1, @subgroup1a)
438
+ policy_machine.add_assignment(@subgroup1a, @group1)
439
+ policy_machine.add_assignment(@u2, @group2)
440
+ end
441
+
442
+ it 'lists the user attributes for a user' do
443
+ policy_machine.list_user_attributes(@u2).should == [@group2]
444
+ end
445
+
446
+ it 'searches multiple hops deep' do
447
+ policy_machine.list_user_attributes(@u1).should =~ [@group1, @subgroup1a]
448
+ end
449
+
450
+ end
451
+
452
+ describe '#transaction' do
453
+ it 'executes the block' do
454
+ if_implements(policy_machine.policy_machine_storage_adapter, :transaction){}
455
+ policy_machine.transaction do
456
+ @oa = policy_machine.create_object_attribute('some_oa')
457
+ end
458
+ policy_machine.object_attributes.should == [@oa]
459
+ end
460
+
461
+ it 'rolls back the block on error' do
462
+ if_implements(policy_machine.policy_machine_storage_adapter, :transaction){}
463
+ @oa1 = policy_machine.create_object_attribute('some_oa')
464
+ expect do
465
+ policy_machine.transaction do
466
+ @oa2 = policy_machine.create_object_attribute('some_other_oa')
467
+ policy_machine.add_assignment(@oa2, :invalid_policy_class)
468
+ end
469
+ end.to raise_error(ArgumentError)
470
+ policy_machine.object_attributes.should == [@oa1]
471
+ end
472
+ end
473
+
474
+ describe '#privileges' do
475
+
476
+ # This PM is taken from the policy machine spec, Figure 4. (pg. 19)
477
+ describe 'Simple Example: Figure 4. (pg. 19)' do
478
+ before do
479
+ # Users
480
+ @u1 = policy_machine.create_user('u1')
481
+ @u2 = policy_machine.create_user('u2')
482
+ @u3 = policy_machine.create_user('u3')
483
+
484
+ # Objects
485
+ @o1 = policy_machine.create_object('o1')
486
+ @o2 = policy_machine.create_object('o2')
487
+ @o3 = policy_machine.create_object('o3')
488
+
489
+ # User Attributes
490
+ @group1 = policy_machine.create_user_attribute('Group1')
491
+ @group2 = policy_machine.create_user_attribute('Group2')
492
+ @division = policy_machine.create_user_attribute('Division')
493
+
494
+ # Object Attributes
495
+ @project1 = policy_machine.create_object_attribute('Project1')
496
+ @project2 = policy_machine.create_object_attribute('Project2')
497
+ @projects = policy_machine.create_object_attribute('Projects')
498
+
499
+ # Operations
500
+ @r = policy_machine.create_operation('read')
501
+ @w = policy_machine.create_operation('write')
502
+
503
+ # Policy Classes
504
+ @ou = policy_machine.create_policy_class("OU")
505
+
506
+ # Assignments
507
+ policy_machine.add_assignment(@u1, @group1)
508
+ policy_machine.add_assignment(@u2, @group2)
509
+ policy_machine.add_assignment(@u3, @division)
510
+ policy_machine.add_assignment(@group1, @division)
511
+ policy_machine.add_assignment(@group2, @division)
512
+ policy_machine.add_assignment(@o1, @project1)
513
+ policy_machine.add_assignment(@o2, @project1)
514
+ policy_machine.add_assignment(@o3, @project2)
515
+ policy_machine.add_assignment(@project1, @projects)
516
+ policy_machine.add_assignment(@project2, @projects)
517
+ policy_machine.add_assignment(@division, @ou)
518
+ policy_machine.add_assignment(@projects, @ou)
519
+
520
+ # Associations
521
+ policy_machine.add_association(@group1, Set.new([@w]), @project1)
522
+ policy_machine.add_association(@group2, Set.new([@w]), @project2)
523
+ policy_machine.add_association(@division, Set.new([@r]), @projects)
524
+ end
525
+
526
+ it 'returns all and only these privileges encoded by the policy machine' do
527
+ expected_privileges = [
528
+ [@u1, @w, @o1], [@u1, @w, @o2], [@u1, @r, @o1], [@u1, @r, @o2], [@u1, @r, @o3],
529
+ [@u2, @w, @o3], [@u2, @r, @o1], [@u2, @r, @o2], [@u2, @r, @o3],
530
+ [@u3, @r, @o1], [@u3, @r, @o2], [@u3, @r, @o3]
531
+ ]
532
+
533
+ assert_pm_privilege_expectations(policy_machine.privileges, expected_privileges)
534
+ end
535
+ end
536
+ end
537
+
538
+ describe 'The Mail System: Figure 8. (pg. 43)' do
539
+ before do
540
+ # Users
541
+ @u2 = policy_machine.create_user('u2')
542
+
543
+ # Objects
544
+ @in_u2 = policy_machine.create_object('In u2')
545
+ @out_u2 = policy_machine.create_object('Out u2')
546
+ @draft_u2 = policy_machine.create_object('Draft u2')
547
+ @trash_u2 = policy_machine.create_object('Trash u2')
548
+
549
+ # User Attributes
550
+ @id_u2 = policy_machine.create_user_attribute('ID u2')
551
+ @users = policy_machine.create_user_attribute('Users')
552
+
553
+ # Object Attributes
554
+ @inboxes = policy_machine.create_object_attribute('Inboxes')
555
+ @outboxes = policy_machine.create_object_attribute('Outboxes')
556
+ @other_u2 = policy_machine.create_object_attribute('Other u2')
557
+ @objects = policy_machine.create_object_attribute('Objects')
558
+
559
+ # Operations
560
+ @r = policy_machine.create_operation('read')
561
+ @w = policy_machine.create_operation('write')
562
+
563
+ # Policy Classes
564
+ @mail_system = policy_machine.create_policy_class('Mail System')
565
+
566
+ # Assignments
567
+ policy_machine.add_assignment(@u2, @id_u2)
568
+ policy_machine.add_assignment(@id_u2, @users)
569
+ policy_machine.add_assignment(@in_u2, @inboxes)
570
+ policy_machine.add_assignment(@out_u2, @outboxes)
571
+ policy_machine.add_assignment(@draft_u2, @other_u2)
572
+ policy_machine.add_assignment(@trash_u2, @other_u2)
573
+ policy_machine.add_assignment(@inboxes, @objects)
574
+ policy_machine.add_assignment(@outboxes, @objects)
575
+ policy_machine.add_assignment(@users, @mail_system)
576
+ policy_machine.add_assignment(@objects, @mail_system)
577
+
578
+ # Associations
579
+ policy_machine.add_association(@id_u2, Set.new([@r]), @in_u2)
580
+ policy_machine.add_association(@id_u2, Set.new([@r, @w]), @out_u2)
581
+ policy_machine.add_association(@id_u2, Set.new([@w]), @inboxes)
582
+ policy_machine.add_association(@id_u2, Set.new([@r, @w]), @other_u2)
583
+ end
584
+
585
+ it 'returns all and only these privileges encoded by the policy machine' do
586
+ expected_privileges = [
587
+ [@u2, @r, @in_u2], [@u2, @r, @out_u2], [@u2, @w, @out_u2], [@u2, @r, @draft_u2],
588
+ [@u2, @w, @draft_u2], [@u2, @r, @trash_u2], [@u2, @w, @trash_u2]
589
+ ]
590
+
591
+ # TODO: remove the expected privilege below once prohibitions are put in place.
592
+ # In the example, @u2 is prohibited from writing to @in_u2
593
+ expected_privileges << [@u2, @w, @in_u2]
594
+
595
+ assert_pm_privilege_expectations(policy_machine.privileges, expected_privileges)
596
+ end
597
+ end
598
+
599
+ describe 'The DAC Operating System: Figure 11. (pg. 47)' do
600
+ before do
601
+ # Users
602
+ @u1 = policy_machine.create_user('u1')
603
+ @u2 = policy_machine.create_user('u2')
604
+
605
+ # Objects
606
+ @o11 = policy_machine.create_object('o11')
607
+ @o12 = policy_machine.create_object('o12')
608
+
609
+ # User Attributes
610
+ @id_u1 = policy_machine.create_user_attribute('ID u1')
611
+ @id_u2 = policy_machine.create_user_attribute('ID u2')
612
+ @users = policy_machine.create_user_attribute('Users')
613
+
614
+ # Object Attributes
615
+ @home_u1 = policy_machine.create_object_attribute('Home u1')
616
+ @home_u2 = policy_machine.create_object_attribute('Home u2')
617
+ @objects = policy_machine.create_object_attribute('Objects')
618
+
619
+ # Operations
620
+ @r = policy_machine.create_operation('read')
621
+ @w = policy_machine.create_operation('write')
622
+ @e = policy_machine.create_operation('execute')
623
+
624
+ # Policy Classes
625
+ @dac = policy_machine.create_policy_class('DAC')
626
+
627
+ # Assignments
628
+ policy_machine.add_assignment(@u1, @id_u1)
629
+ policy_machine.add_assignment(@u2, @id_u2)
630
+ policy_machine.add_assignment(@id_u1, @users)
631
+ policy_machine.add_assignment(@id_u2, @users)
632
+ policy_machine.add_assignment(@o11, @home_u1)
633
+ policy_machine.add_assignment(@o12, @home_u1)
634
+ policy_machine.add_assignment(@home_u1, @objects)
635
+ policy_machine.add_assignment(@home_u2, @objects)
636
+ policy_machine.add_assignment(@users, @dac)
637
+ policy_machine.add_assignment(@objects, @dac)
638
+
639
+ # Associations
640
+ policy_machine.add_association(@id_u1, Set.new([@r, @w, @e]), @home_u1)
641
+ policy_machine.add_association(@id_u2, Set.new([@r, @w, @e]), @home_u2)
642
+ end
643
+
644
+ it 'returns all and only these privileges encoded by the policy machine' do
645
+ expected_privileges = [
646
+ [@u1, @r, @o11], [@u1, @w, @o11], [@u1, @e, @o11],
647
+ [@u1, @r, @o12], [@u1, @w, @o12], [@u1, @e, @o12],
648
+ ]
649
+
650
+ assert_pm_privilege_expectations(policy_machine.privileges, expected_privileges)
651
+ end
652
+ end
653
+
654
+ describe 'simple multiple policy class machine' do
655
+ before do
656
+ # Users
657
+ @u1 = policy_machine.create_user('u1')
658
+
659
+ # Objects
660
+ @o1 = policy_machine.create_object('o1')
661
+
662
+ # User Attributes
663
+ @ua = policy_machine.create_user_attribute('UA')
664
+
665
+ # Object Attributes
666
+ @oa1 = policy_machine.create_object_attribute('OA1')
667
+ @oa2 = policy_machine.create_object_attribute('OA2')
668
+
669
+ # Operations
670
+ @r = policy_machine.create_operation('read')
671
+ @w = policy_machine.create_operation('write')
672
+
673
+ # Policy Classes
674
+ @pc1 = policy_machine.create_policy_class('pc1')
675
+ @pc2 = policy_machine.create_policy_class('pc2')
676
+
677
+ # Assignments
678
+ policy_machine.add_assignment(@u1, @ua)
679
+ policy_machine.add_assignment(@o1, @oa1)
680
+ policy_machine.add_assignment(@o1, @oa2)
681
+ policy_machine.add_assignment(@oa1, @pc1)
682
+ policy_machine.add_assignment(@oa2, @pc2)
683
+
684
+ # Associations
685
+ policy_machine.add_association(@ua, Set.new([@r]), @oa1)
686
+ policy_machine.add_association(@ua, Set.new([@r, @w]), @oa2)
687
+ end
688
+
689
+ it 'returns all and only these privileges encoded by the policy machine' do
690
+ expected_privileges = [
691
+ [@u1, @r, @o1]
692
+ ]
693
+ assert_pm_privilege_expectations(policy_machine.privileges, expected_privileges)
694
+ end
695
+ end
696
+
697
+ end