cannibal 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.mdown ADDED
@@ -0,0 +1,114 @@
1
+ Cannibal
2
+ ========
3
+
4
+ A simple permissions system for declaring and querying permissions between Ruby objects.
5
+
6
+ Background
7
+ ----------
8
+
9
+ Cannibal is based around defining interactions between Actors and Subjects.
10
+
11
+ An Actor participates in your system as an agent that "does" things. Cannibal lets you declare what
12
+ each Actor can do, and Actors are queried to determine whether or not they are permitted to perform
13
+ a particular action.
14
+
15
+ You can turn any class into an Actor by including Cannibal::Actor within it.
16
+
17
+ A Subject participates in your system as something that is acted upon. You declare for each Subject
18
+ the conditions under which each Actor may or may not interact with it.
19
+
20
+ You can turn any class into a Subject by including Cannibal::Actor within it.
21
+
22
+ If for example you are using Cannibal in a Rails application, an example of an Actor might be a
23
+ User model. An example of a Subject might be a Task model. You may want all Users in the system to
24
+ be able to view all of the available Tasks, but you may want to restrict tasks to only be editable
25
+ by their creators.
26
+
27
+ Permissions can be set at various levels, starting at the Class level and getting finer grained
28
+ right down to the field or method level of your models.
29
+
30
+ In addition, you can specify static permissions (no User may modify a Task) or dynamic permissions
31
+ that are evaluated at query time (ie. a specific user may or may not be able to modify a specific
32
+ task, based on whatever rules you put forth).
33
+
34
+ Sample Scenarios
35
+ ----------------
36
+
37
+ Class-level permissions:
38
+
39
+ class User
40
+ include Cannibal::Actor
41
+ end
42
+
43
+ class Thing
44
+ include Cannibal::Subject
45
+ allow User, :edit
46
+ end
47
+
48
+ @user = User.new
49
+ @thing = Thing.new
50
+
51
+ puts "Yay!" if @user.can? :edit, @thing
52
+
53
+ Actor object-level permissions:
54
+
55
+ class User
56
+ include Cannibal::Actor
57
+ attr_accessor :role
58
+ end
59
+
60
+ class Thing
61
+ include Cannibal::Subject
62
+ permission({
63
+ :actor => User,
64
+ :verb => :edit,
65
+ :actor_proc => Proc.new { |user|
66
+ if user.role == 'administrator'
67
+ true
68
+ else
69
+ false
70
+ end
71
+ }
72
+ })
73
+ end
74
+
75
+ @user = User.new; @user.role = 'user'
76
+ @admin = User.new; @user.role = 'administrator'
77
+ @thing = Thing.new
78
+
79
+ puts "Back off!" unless @user.can? :edit, @thing
80
+ puts "Yay!" if @admin.can? :edit, @thing
81
+
82
+ Actor and subject object-to-object level permissions:
83
+
84
+ class User
85
+ include Cannibal::Actor
86
+ attr_accessor :role
87
+ end
88
+
89
+ class Thing
90
+ include Cannibal::Subject
91
+ attr_accessor :owner
92
+ permission({
93
+ :actor => User,
94
+ :verb => :edit,
95
+ :proc => Proc.new { |user, thing|
96
+ if user.role == 'administrator' or user == thing.owner
97
+ true
98
+ else
99
+ false
100
+ end
101
+ }
102
+ })
103
+ end
104
+
105
+ @user_a = User.new; @user.role = 'user'
106
+ @user_b = User.new; @user.role = 'user'
107
+ @admin = User.new; @user.role = 'administrator'
108
+
109
+ @thing = Thing.new; @thing.owner = @user_a
110
+
111
+ puts "Back off!" unless @user_b.can? :edit, @thing
112
+ puts "Yay!" if @user_a.can? :edit, @thing
113
+ puts "Yay!" if @admin.can? :edit, @thing
114
+
@@ -0,0 +1,24 @@
1
+ module Cannibal
2
+ module Actor
3
+
4
+ module ClassMethods
5
+ def can?(verb, subject, attribute=nil)
6
+ permissions.allowed?(self, subject, verb, attribute)
7
+ end
8
+
9
+ def permissions
10
+ @@registry = Cannibal::PermissionRegistry.instance
11
+ end
12
+ end
13
+
14
+ def self.included(klass)
15
+ klass.extend ClassMethods
16
+ end
17
+
18
+ def can?(verb, subject, attribute=nil)
19
+ self.class.permissions.allowed?(self, subject, verb, attribute)
20
+ end
21
+
22
+ end
23
+ end
24
+
@@ -0,0 +1,135 @@
1
+ require 'singleton'
2
+
3
+ module Cannibal
4
+ class PermissionRegistry
5
+ include Singleton
6
+
7
+ def set(options)
8
+ actor = options[:actor]
9
+ verb = options[:verb]
10
+ subject = options[:subject]
11
+
12
+ if actor.is_a? Class
13
+ actor_class = actor
14
+ else
15
+ actor_class = actor.class
16
+ end
17
+
18
+ if subject.is_a? Class
19
+ subject_class = subject
20
+ else
21
+ subject_class = subject.class
22
+ end
23
+
24
+ actor_proc = options[:actor_proc]
25
+ gproc = options[:proc]
26
+
27
+ perm = options[:perm]
28
+ attributes = options[:attribute]
29
+ if attributes.nil?
30
+ # Set class-wide perms if no attributes specified
31
+ verb_hash(actor_class, subject_class, verb)[:perm] = perm unless perm.nil?
32
+ verb_hash(actor_class, subject_class, verb)[:actor_proc] = actor_proc unless actor_proc.nil?
33
+ verb_hash(actor_class, subject_class, verb)[:proc] = gproc unless gproc.nil?
34
+ else
35
+ attributes = [ attributes ] unless attributes.is_a? Array
36
+ attributes.each do |attribute|
37
+ attribute_hash(actor_class, subject_class, verb)[attribute] = {}
38
+ attribute_hash(actor_class, subject_class, verb)[attribute][:perm] = perm unless perm.nil?
39
+ attribute_hash(actor_class, subject_class, verb)[attribute][:actor_proc] = actor_proc unless actor_proc.nil?
40
+ attribute_hash(actor_class, subject_class, verb)[attribute][:proc] = gproc unless gproc.nil?
41
+ end
42
+ end
43
+ end
44
+
45
+ def allowed?(actor, subject, verb, attribute=nil)
46
+ ok = false
47
+
48
+ if actor.is_a? Class
49
+ actor_class = actor
50
+ else
51
+ actor_class = actor.class
52
+ end
53
+ if subject.is_a? Class
54
+ subject_class = subject
55
+ else
56
+ subject_class = subject.class
57
+ end
58
+
59
+ ph = verb_hash(actor_class, subject_class, verb)
60
+ #puts "\n########### PERM HASH FOR #{actor_class} #{subject_class} #{verb} #{attribute}"
61
+ #puts "#{ph.inspect}\n\n"
62
+
63
+ # Check class perms first
64
+ if ph.has_key? :perm
65
+ ok = ph[:perm]
66
+ end
67
+
68
+ unless actor.is_a? Class
69
+ # Allow object perms to override
70
+ if ph.has_key? :actor_proc
71
+ ok = ph[:actor_proc].call actor
72
+ end
73
+ end
74
+
75
+ unless subject.is_a? Class
76
+ # Allow object-to-object perms to override
77
+ if ph.has_key? :proc
78
+ ok = ph[:proc].call actor, subject
79
+ end
80
+ end
81
+
82
+ unless attribute.nil?
83
+ # puts "Evaluating attribute #{attribute}"
84
+ ah = attribute_hash(actor_class, subject_class, verb)
85
+ # puts ah.inspect
86
+ if ah.has_key? attribute
87
+ # puts "Found key #{attribute}"
88
+
89
+ if ah[attribute].has_key? :perm
90
+ # puts "Setting from perm"
91
+ ok = ah[attribute][:perm]
92
+ end
93
+
94
+ unless actor.is_a? Class or ah[attribute][:actor_proc].nil?
95
+ # puts "Setting from actor_proc"
96
+ ok = ah[attribute][:actor_proc].call actor
97
+ end
98
+
99
+ unless subject.is_a? Class or ah[attribute][:proc].nil?
100
+ # puts "Setting from proc"
101
+ ok = ah[attribute][:proc].call actor, subject
102
+ end
103
+ end
104
+ # puts "Found #{ok}"
105
+ end
106
+
107
+ ok
108
+ end
109
+
110
+ def permstore
111
+ @perms ||= {}
112
+ end
113
+
114
+ def reset
115
+ @perms = {}
116
+ end
117
+
118
+ def verb_hash(actor, subject, verb)
119
+ actor_hash = hash_or_init permstore, actor
120
+ subject_hash = hash_or_init actor_hash, subject
121
+ hash_or_init subject_hash, verb
122
+ end
123
+
124
+ def attribute_hash(actor, subject, verb)
125
+ hash_or_init verb_hash(actor, subject, verb), :attributes
126
+ end
127
+
128
+ def hash_or_init(hash, key)
129
+ unless hash.include? key
130
+ hash[key] = {}
131
+ end
132
+ hash[key]
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,44 @@
1
+ module Cannibal
2
+
3
+ module Subject
4
+
5
+ module ClassMethods
6
+
7
+ def allow(actor, verb, attribute=nil)
8
+ permissions.set(
9
+ :actor => actor,
10
+ :verb => verb,
11
+ :subject => self,
12
+ :attribute => attribute,
13
+ :perm => true
14
+ )
15
+ end
16
+
17
+ def deny(actor, verb, attribute=nil)
18
+ permissions.set(
19
+ :actor => actor,
20
+ :verb => verb,
21
+ :subject => self,
22
+ :attribute => attribute,
23
+ :perm => false
24
+ )
25
+ end
26
+
27
+ def permission(options)
28
+ options[:subject] = self
29
+ permissions.set(options)
30
+ end
31
+
32
+ def permissions
33
+ @registry ||= Cannibal::PermissionRegistry.instance
34
+ end
35
+
36
+ end
37
+
38
+ def self.included(klass)
39
+ klass.extend ClassMethods
40
+ end
41
+
42
+ end
43
+ end
44
+
data/lib/cannibal.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'cannibal/permission_registry'
2
+ require 'cannibal/actor'
3
+ require 'cannibal/subject'
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cannibal
3
+ version: !ruby/object:Gem::Version
4
+ hash: 11
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 0
10
+ version: 0.5.0
11
+ platform: ruby
12
+ authors:
13
+ - Three Wise Men
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-17 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Use this library in a Ruby application to provide permission declaration and querying capabilities between Ruby objects.
23
+ email: info @nospam@ threewisemen.ca
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.mdown
30
+ files:
31
+ - lib/cannibal.rb
32
+ - lib/cannibal/actor.rb
33
+ - lib/cannibal/permission_registry.rb
34
+ - lib/cannibal/subject.rb
35
+ - README.mdown
36
+ has_rdoc: true
37
+ homepage:
38
+ licenses: []
39
+
40
+ post_install_message:
41
+ rdoc_options: []
42
+
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ hash: 3
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.7
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Permission framework for Ruby objects
70
+ test_files: []
71
+