policy_machine 0.0.1 → 0.0.2
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/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
|