policy_machine 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +9 -0
- data/MIT-LICENSE +1 -1
- data/lib/policy_machine.rb +19 -0
- data/lib/policy_machine/association.rb +1 -1
- data/lib/policy_machine/policy_element.rb +4 -0
- data/lib/policy_machine_storage_adapters/active_record.rb +34 -0
- data/lib/policy_machine_storage_adapters/template.rb +8 -0
- data/policy_machine.gemspec +2 -1
- data/spec/spec_helper.rb +3 -2
- data/spec/support/policy_machine_helpers.rb +14 -0
- data/spec/support/{shared_examples_policy_machine_spec.rb → shared_examples_policy_machine.rb} +6 -0
- data/spec/support/{shared_examples_policy_machine_storage_adapter_spec.rb → shared_examples_shared_examples_policy_machine_storage_adapter.rb} +0 -0
- data/test/test_helper.rb +0 -1
- metadata +9 -7
data/CHANGELOG.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# 0.0.2
|
2
|
+
|
3
|
+
* Fix: Operation sets now silently remove duplicates
|
4
|
+
* Transactional rollback available in active_record and in_memory
|
5
|
+
* Can now generate a list of all privileges a user has on an object with `#scoped_privileges`
|
6
|
+
|
7
|
+
# 0.0.1
|
8
|
+
|
9
|
+
* Initial open source release.
|
data/MIT-LICENSE
CHANGED
data/lib/policy_machine.rb
CHANGED
@@ -147,6 +147,25 @@ class PolicyMachine
|
|
147
147
|
privileges
|
148
148
|
end
|
149
149
|
|
150
|
+
##
|
151
|
+
# Returns an array of all privileges encoded in this
|
152
|
+
# policy machine for the given user (attribute) on the given
|
153
|
+
# object (attribute).
|
154
|
+
#
|
155
|
+
# TODO: might make privilege a class of its own
|
156
|
+
def scoped_privileges(user_or_attribute, object_or_attribute)
|
157
|
+
if policy_machine_storage_adapter.respond_to?(:scoped_privileges)
|
158
|
+
policy_machine_storage_adapter.scoped_privileges(user_or_attribute.stored_pe, object_or_attribute.stored_pe).map do |op|
|
159
|
+
operation = PM::Operation.convert_stored_pe_to_pe(op, policy_machine_storage_adapter, PM::Operation)
|
160
|
+
[user_or_attribute, operation, object_or_attribute]
|
161
|
+
end
|
162
|
+
else
|
163
|
+
operations.grep(->operation{is_privilege?(user_or_attribute, operation, object_or_attribute)}) do |op|
|
164
|
+
[user_or_attribute, op, object_or_attribute]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
150
169
|
##
|
151
170
|
# Returns an array of all user_attributes a PM::User is assigned to,
|
152
171
|
# directly or indirectly.
|
@@ -106,6 +106,10 @@ module PM
|
|
106
106
|
stored_pe.respond_to?(meth, include_private) || super
|
107
107
|
end
|
108
108
|
|
109
|
+
def inspect
|
110
|
+
"#<#{self.class} #{unique_identifier}>"
|
111
|
+
end
|
112
|
+
|
109
113
|
protected
|
110
114
|
def allowed_assignee_classes
|
111
115
|
raise "Must override this method in a subclass"
|
@@ -21,7 +21,9 @@ module PolicyMachineStorageAdapter
|
|
21
21
|
has_many :assignments, foreign_key: :parent_id, dependent: :destroy
|
22
22
|
has_many :children, through: :assignments, dependent: :destroy #this doesn't actually destroy the children, just the assignment
|
23
23
|
has_many :transitive_closure, foreign_key: :ancestor_id
|
24
|
+
has_many :inverse_transitive_closure, class_name: :"PolicyMachineStorageAdapter::ActiveRecord::TransitiveClosure", foreign_key: :descendant_id
|
24
25
|
has_many :descendants, through: :transitive_closure
|
26
|
+
has_many :ancestors, through: :inverse_transitive_closure
|
25
27
|
attr_accessible :unique_identifier, :policy_machine_uuid, :extra_attributes
|
26
28
|
attr_accessor :extra_attributes_hash
|
27
29
|
before_save :serialize_extra_attributes_hash
|
@@ -294,8 +296,40 @@ module PolicyMachineStorageAdapter
|
|
294
296
|
PolicyElement.transaction(&block)
|
295
297
|
end
|
296
298
|
|
299
|
+
## Optimized version of PolicyMachine#scoped_privileges
|
300
|
+
# Returns all operations the user has on the object
|
301
|
+
def scoped_privileges(user_or_attribute, object_or_attribute)
|
302
|
+
policy_classes_containing_object = policy_classes_for_object_attribute(object_or_attribute)
|
303
|
+
if policy_classes_containing_object.count < 2
|
304
|
+
scoped_privileges_single_policy_class(user_or_attribute, object_or_attribute)
|
305
|
+
else
|
306
|
+
scoped_privileges_multiple_policy_classes(user_or_attribute, object_or_attribute, policy_classes_containing_object)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
297
310
|
private
|
298
311
|
|
312
|
+
def scoped_privileges_single_policy_class(user_or_attribute, object_or_attribute)
|
313
|
+
associations = class_for_type('policy_element_association').where(
|
314
|
+
object_attribute_id: object_or_attribute.descendants | [object_or_attribute],
|
315
|
+
user_attribute_id: user_or_attribute.descendants | [user_or_attribute]
|
316
|
+
).includes(:operations)
|
317
|
+
|
318
|
+
associations.flat_map(&:operations).uniq
|
319
|
+
end
|
320
|
+
|
321
|
+
def scoped_privileges_multiple_policy_classes(user_or_attribute, object_or_attribute, policy_classes_containing_object)
|
322
|
+
base_scope = class_for_type('policy_element_association').where(
|
323
|
+
object_attribute_id: object_or_attribute.descendants | [object_or_attribute],
|
324
|
+
user_attribute_id: user_or_attribute.descendants | [user_or_attribute]
|
325
|
+
)
|
326
|
+
operations_for_policy_classes = policy_classes_containing_object.map do |pc|
|
327
|
+
associations = base_scope.where(object_attribute_id: pc.ancestors).includes(:operations)
|
328
|
+
associations.flat_map(&:operations)
|
329
|
+
end
|
330
|
+
operations_for_policy_classes.inject(:&) || []
|
331
|
+
end
|
332
|
+
|
299
333
|
def assert_persisted_policy_element(*arguments)
|
300
334
|
arguments.each do |argument|
|
301
335
|
raise ArgumentError, "expected policy elements, got #{argument}" unless argument.is_a?(PolicyElement)
|
@@ -163,6 +163,14 @@ module PolicyMachineStorageAdapter
|
|
163
163
|
# all the block's changes to be rolled back. Should raise NotImplementedError if the
|
164
164
|
# persistence layer does not support this.
|
165
165
|
def transaction
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
## Optimized version of PolicyMachine#scoped_privileges
|
170
|
+
# Return all operations the user has on the object
|
171
|
+
# Optional: only add this method if you can do it better than policy_machine.rb
|
172
|
+
def scoped_privileges(user_or_attribute, object_or_attribute)
|
173
|
+
|
166
174
|
end
|
167
175
|
|
168
176
|
end
|
data/policy_machine.gemspec
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "policy_machine"
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.2"
|
4
4
|
s.summary = "Policy Machine!"
|
5
5
|
s.description = "A ruby implementation of the Policy Machine authorization formalism."
|
6
6
|
s.authors = ['Matthew Szenher', 'Aaron Weiner']
|
7
7
|
s.email = s.authors.map{|name|name.sub(/(.).* (.*)/,'\1\2@mdsol.com')}
|
8
8
|
s.homepage = 'https://github.com/mdsol/the_policy_machine'
|
9
|
+
s.license = 'MIT'
|
9
10
|
s.files = `git ls-files`.split("\n")
|
10
11
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
11
12
|
s.require_paths = ["lib"]
|
data/spec/spec_helper.rb
CHANGED
@@ -19,4 +19,18 @@ def assert_pm_privilege_expectations(actual_privileges, expected_privileges)
|
|
19
19
|
end
|
20
20
|
|
21
21
|
actual_privileges.count.should == expected_privileges.size
|
22
|
+
assert_pm_scoped_privilege_expectations
|
23
|
+
end
|
24
|
+
|
25
|
+
# Make sure all scoped_privileges calls behave as expected
|
26
|
+
def assert_pm_scoped_privilege_expectations
|
27
|
+
users_or_attributes = policy_machine.users | policy_machine.user_attributes
|
28
|
+
objects_or_attributes = policy_machine.objects | policy_machine.object_attributes
|
29
|
+
users_or_attributes.product(objects_or_attributes) do |u, o|
|
30
|
+
expected_scoped_privileges = policy_machine.operations.grep(->op{policy_machine.is_privilege?(u, op, o)}) do |op|
|
31
|
+
[u, op, o]
|
32
|
+
end
|
33
|
+
policy_machine.scoped_privileges(u,o).should =~ expected_scoped_privileges
|
34
|
+
end
|
35
|
+
|
22
36
|
end
|
data/spec/support/{shared_examples_policy_machine_spec.rb → shared_examples_policy_machine.rb}
RENAMED
@@ -187,6 +187,12 @@ shared_examples "a policy machine" do
|
|
187
187
|
it 'allows an association to be made between an existing user_attribute, operation set and object attribute (returns true)' do
|
188
188
|
policy_machine.add_association(@user_attribute, @operation_set, @object_attribute).should be_true
|
189
189
|
end
|
190
|
+
|
191
|
+
it 'handles non-unique operation sets' do
|
192
|
+
@operation_set << @operation1.dup
|
193
|
+
policy_machine.add_association(@user_attribute, @operation_set, @object_attribute).should be_true
|
194
|
+
end
|
195
|
+
|
190
196
|
end
|
191
197
|
end
|
192
198
|
|
File without changes
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: policy_machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-11-01 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -148,6 +148,7 @@ executables: []
|
|
148
148
|
extensions: []
|
149
149
|
extra_rdoc_files: []
|
150
150
|
files:
|
151
|
+
- CHANGELOG.md
|
151
152
|
- CONTRIBUTING.md
|
152
153
|
- Gemfile
|
153
154
|
- MIT-LICENSE
|
@@ -174,8 +175,8 @@ files:
|
|
174
175
|
- spec/spec_helper.rb
|
175
176
|
- spec/support/neography_helpers.rb
|
176
177
|
- spec/support/policy_machine_helpers.rb
|
177
|
-
- spec/support/
|
178
|
-
- spec/support/
|
178
|
+
- spec/support/shared_examples_policy_machine.rb
|
179
|
+
- spec/support/shared_examples_shared_examples_policy_machine_storage_adapter.rb
|
179
180
|
- spec/support/shared_examples_storage_adapter_public_methods.rb
|
180
181
|
- spec/support/storage_adapter_helpers.rb
|
181
182
|
- test/dummy/Rakefile
|
@@ -204,7 +205,8 @@ files:
|
|
204
205
|
- test/policy_machine_test.rb
|
205
206
|
- test/test_helper.rb
|
206
207
|
homepage: https://github.com/mdsol/the_policy_machine
|
207
|
-
licenses:
|
208
|
+
licenses:
|
209
|
+
- MIT
|
208
210
|
post_install_message:
|
209
211
|
rdoc_options: []
|
210
212
|
require_paths:
|
@@ -238,8 +240,8 @@ test_files:
|
|
238
240
|
- spec/spec_helper.rb
|
239
241
|
- spec/support/neography_helpers.rb
|
240
242
|
- spec/support/policy_machine_helpers.rb
|
241
|
-
- spec/support/
|
242
|
-
- spec/support/
|
243
|
+
- spec/support/shared_examples_policy_machine.rb
|
244
|
+
- spec/support/shared_examples_shared_examples_policy_machine_storage_adapter.rb
|
243
245
|
- spec/support/shared_examples_storage_adapter_public_methods.rb
|
244
246
|
- spec/support/storage_adapter_helpers.rb
|
245
247
|
- test/dummy/Rakefile
|