makandra-aegis 1.1.1 → 1.1.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/README.rdoc +107 -2
- data/VERSION +1 -1
- data/aegis.gemspec +2 -2
- data/lib/aegis/permissions.rb +12 -15
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -1,8 +1,19 @@
|
|
1
1
|
= Aegis - role-based permissions for your user models
|
2
2
|
|
3
|
-
Aegis allows you to
|
3
|
+
Aegis allows you to manage fine-grained, complex permission for user accounts in a central place.
|
4
4
|
|
5
|
-
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
Add the following to your <tt>Initializer.run</tt> block in your <tt>environment.rb</tt>:
|
8
|
+
config.gem 'makandra-aegis', :lib => 'aegis', :source => 'http://gems.github.com'
|
9
|
+
Then do a
|
10
|
+
sudo rake gems:install
|
11
|
+
|
12
|
+
Alternatively, use
|
13
|
+
sudo gem sources -a http://gems.github.com
|
14
|
+
sudo gem install makandra-aegis
|
15
|
+
|
16
|
+
== Example
|
6
17
|
|
7
18
|
First, let's define some roles:
|
8
19
|
|
@@ -64,3 +75,97 @@ These permissions may be used in views and controllers:
|
|
64
75
|
end
|
65
76
|
|
66
77
|
end
|
78
|
+
|
79
|
+
== Details
|
80
|
+
|
81
|
+
=== Roles
|
82
|
+
|
83
|
+
To equip a (user) model with any permissions, you simply call *has_role* within
|
84
|
+
the model:
|
85
|
+
class User < ActiveRecord::Base
|
86
|
+
has_role
|
87
|
+
end
|
88
|
+
Aegis assumes that the corresponding database table has a string-valued column
|
89
|
+
called +role_name+. You may override the name with the <tt>:name_accessor =>
|
90
|
+
:my_role_column</tt> option.
|
91
|
+
|
92
|
+
The roles and permissions themselves are defined in a class inheriting from
|
93
|
+
<b>Aegis::Permissions</b>. To define roles you create a model <tt>permissions.rb</tt>
|
94
|
+
and use the *role* method:
|
95
|
+
class Permissions < Aegis::Permissions
|
96
|
+
role 'role_name'
|
97
|
+
end
|
98
|
+
|
99
|
+
By default, users belonging to this role are not permitted anything. You may
|
100
|
+
override this with <tt>:default_permission => :allow</tt>, e.g.
|
101
|
+
role 'admin', :default_permission => :allow
|
102
|
+
|
103
|
+
=== Permissions
|
104
|
+
|
105
|
+
Permissions are specified with the *permission* method and *allow* and *deny*
|
106
|
+
permission :do_something do
|
107
|
+
allow :role_a, :role_b
|
108
|
+
deny :role_c
|
109
|
+
end
|
110
|
+
|
111
|
+
Your user model just received two methods called <b>User#may_do_something?</b>
|
112
|
+
and <b>User#may_do_something!</b>. The first one with the ? returns true for users with
|
113
|
+
+role_a+ and +role_b+, and false for users with +role_c+. The second one with the ! raises an
|
114
|
+
Aegis::PermissionError for +role_c+.
|
115
|
+
|
116
|
+
=== Normalization
|
117
|
+
|
118
|
+
Aegis will perform some normalization. For example, the permissions
|
119
|
+
+edit_something+ and +update_something+ will be the same, each granting both
|
120
|
+
<tt>may_edit_something?</tt> and <tt>may_update_something?</tt>. The following normalizations
|
121
|
+
are active:
|
122
|
+
* edit = update
|
123
|
+
* show = list = view = read
|
124
|
+
* delete = remove = destroy
|
125
|
+
|
126
|
+
=== Complex permissions (with parameters)
|
127
|
+
|
128
|
+
*allow* and *deny* can also take a block that may return +true+ or +false+
|
129
|
+
indicating if this really applies. So
|
130
|
+
permission :pull_april_fools_prank do
|
131
|
+
allow :everyone do
|
132
|
+
Date.today.month == 4 and Date.today.day == 1
|
133
|
+
end
|
134
|
+
end
|
135
|
+
will generate a <tt>may_pull_april_fools_prank?</tt> method that only returns true on
|
136
|
+
April 1.
|
137
|
+
|
138
|
+
This becomes more useful if you pass parameters to a <tt>may_...?</tt> method, which
|
139
|
+
are passed through to the permission block (together with the user object). This
|
140
|
+
way you can define more complex permissions like
|
141
|
+
permission :edit_post do |current_user, post|
|
142
|
+
allow :registered_user do
|
143
|
+
post.owner == current_user
|
144
|
+
end
|
145
|
+
allow :admin
|
146
|
+
end
|
147
|
+
which will permit admins and post owners to edit posts.
|
148
|
+
|
149
|
+
=== For your convenience
|
150
|
+
|
151
|
+
As a convenience, if you create a permission ending in a plural 's', this
|
152
|
+
automatically includes the singular form. That is, after
|
153
|
+
permission :read_posts do
|
154
|
+
allow :everyone
|
155
|
+
end
|
156
|
+
<tt>.may_read_post? @post</tt> will return true, as well.
|
157
|
+
|
158
|
+
If you want to grant +create_something+, +read_something+, +update_something+
|
159
|
+
and +destroy_something+ permissions all at once, just use
|
160
|
+
permission :crud_something do
|
161
|
+
allow :admin
|
162
|
+
end
|
163
|
+
|
164
|
+
If several permission blocks (or several allow and denies) apply to a certain
|
165
|
+
role, the later one always wins. That is
|
166
|
+
permission :do_something do
|
167
|
+
deny :everyone
|
168
|
+
allow :admin
|
169
|
+
end
|
170
|
+
will work as expected.
|
171
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.3
|
data/aegis.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{aegis}
|
5
|
-
s.version = "1.1.
|
5
|
+
s.version = "1.1.2"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Henning Koch"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-06-25}
|
10
10
|
s.description = %q{Aegis is a role-based permission system, where all users are given a role. It is possible to define detailed and complex permissions for each role very easily.}
|
11
11
|
s.email = %q{github@makandra.de}
|
12
12
|
s.extra_rdoc_files = [
|
data/lib/aegis/permissions.rb
CHANGED
@@ -3,30 +3,27 @@ module Aegis
|
|
3
3
|
|
4
4
|
def self.inherited(base)
|
5
5
|
base.class_eval do
|
6
|
+
@roles_by_name = {}
|
7
|
+
@permission_blocks = Hash.new { |hash, key| hash[key] = [] }
|
6
8
|
extend ClassMethods
|
7
9
|
end
|
8
10
|
end
|
9
11
|
|
10
12
|
module ClassMethods
|
11
13
|
|
12
|
-
@@roles_by_name = {}
|
13
|
-
|
14
|
-
# Example: @@permission_blocks[:update_users] =
|
15
|
-
# [proc { allow :admin; deny :guest }, proc { deny :student }]
|
16
|
-
@@permission_blocks = Hash.new { |hash, key| hash[key] = [] }
|
17
14
|
|
18
15
|
def role(role_name, options = {})
|
19
16
|
role_name = role_name.to_sym
|
20
17
|
role_name != Aegis::Constants::EVERYONE_ROLE_NAME or raise "Cannot define a role named: #{Aegis::Constants::EVERYONE_ROLE_NAME}"
|
21
|
-
|
18
|
+
@roles_by_name[role_name] = Aegis::Role.new(role_name, self, options)
|
22
19
|
end
|
23
20
|
|
24
21
|
def find_all_role_names
|
25
|
-
|
22
|
+
@roles_by_name.keys
|
26
23
|
end
|
27
24
|
|
28
25
|
def find_all_roles
|
29
|
-
|
26
|
+
@roles_by_name.values.sort
|
30
27
|
end
|
31
28
|
|
32
29
|
def find_role_by_name(name)
|
@@ -34,7 +31,7 @@ module Aegis
|
|
34
31
|
if name.blank?
|
35
32
|
nil
|
36
33
|
else
|
37
|
-
|
34
|
+
@roles_by_name[name.to_sym]
|
38
35
|
end
|
39
36
|
end
|
40
37
|
|
@@ -51,13 +48,13 @@ module Aegis
|
|
51
48
|
|
52
49
|
def may?(role_or_role_name, permission, *args)
|
53
50
|
role = role_or_role_name.is_a?(Aegis::Role) ? role_or_role_name : find_role_by_name(role_or_role_name)
|
54
|
-
blocks =
|
51
|
+
blocks = @permission_blocks[permission.to_sym]
|
55
52
|
evaluate_permission_blocks(role, blocks, *args)
|
56
53
|
end
|
57
54
|
|
58
55
|
def evaluate_permission_blocks(role, blocks, *args)
|
59
|
-
|
60
|
-
|
56
|
+
evaluator = Aegis::PermissionEvaluator.new(role)
|
57
|
+
evaluator.evaluate(blocks, args)
|
61
58
|
end
|
62
59
|
|
63
60
|
def denied?(*args)
|
@@ -89,8 +86,8 @@ module Aegis
|
|
89
86
|
singular_target = target.singularize
|
90
87
|
if singular_target.length < target.length
|
91
88
|
singular_block = lambda do |*args|
|
92
|
-
|
93
|
-
|
89
|
+
args.delete_at 1
|
90
|
+
instance_exec(*args, &block)
|
94
91
|
end
|
95
92
|
singular_permission_name = "#{verb}_#{singular_target}"
|
96
93
|
add_permission(singular_permission_name, &singular_block)
|
@@ -101,7 +98,7 @@ module Aegis
|
|
101
98
|
|
102
99
|
def add_permission(permission_name, &block)
|
103
100
|
permission_name = permission_name.to_sym
|
104
|
-
|
101
|
+
@permission_blocks[permission_name] << block
|
105
102
|
end
|
106
103
|
|
107
104
|
end # module ClassMethods
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: makandra-aegis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henning Koch
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-25 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|