policy_machine 0.0.1
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.
- data/CONTRIBUTING.md +35 -0
- data/Gemfile +2 -0
- data/MIT-LICENSE +20 -0
- data/README.md +98 -0
- data/lib/generators/policy_machine/policy_machine_generator.rb +13 -0
- data/lib/generators/policy_machine/templates/migration.rb +40 -0
- data/lib/policy_machine.rb +236 -0
- data/lib/policy_machine/association.rb +73 -0
- data/lib/policy_machine/policy_element.rb +269 -0
- data/lib/policy_machine/version.rb +3 -0
- data/lib/policy_machine_storage_adapters/active_record.rb +306 -0
- data/lib/policy_machine_storage_adapters/in_memory.rb +266 -0
- data/lib/policy_machine_storage_adapters/neography.rb +236 -0
- data/lib/policy_machine_storage_adapters/template.rb +169 -0
- data/lib/tasks/policy_machine_tasks.rake +4 -0
- data/policy_machine.gemspec +23 -0
- data/spec/policy_machine/association_spec.rb +61 -0
- data/spec/policy_machine/policy_element_spec.rb +20 -0
- data/spec/policy_machine_spec.rb +7 -0
- data/spec/policy_machine_storage_adapters/active_record_spec.rb +54 -0
- data/spec/policy_machine_storage_adapters/in_memory_spec.rb +13 -0
- data/spec/policy_machine_storage_adapters/neography_spec.rb +42 -0
- data/spec/policy_machine_storage_adapters/template_spec.rb +6 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/neography_helpers.rb +39 -0
- data/spec/support/policy_machine_helpers.rb +22 -0
- data/spec/support/shared_examples_policy_machine_spec.rb +697 -0
- data/spec/support/shared_examples_policy_machine_storage_adapter_spec.rb +278 -0
- data/spec/support/shared_examples_storage_adapter_public_methods.rb +20 -0
- data/spec/support/storage_adapter_helpers.rb +7 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +65 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +42 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/db/migrate/20131015214828_generate_policy_machine.rb +40 -0
- data/test/dummy/db/migrate/20131021221759_add_color_to_policy_element.rb +5 -0
- data/test/dummy/db/schema.rb +57 -0
- data/test/dummy/lib/assets/.gitkeep +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/policy_machine_test.rb +7 -0
- data/test/test_helper.rb +15 -0
- 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
|