aegis 2.0.4 → 2.1.0
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 +13 -7
- data/VERSION +1 -1
- data/aegis.gemspec +4 -4
- data/lib/aegis/action.rb +12 -5
- data/lib/aegis/has_role.rb +17 -17
- data/lib/aegis/sieve.rb +1 -1
- data/spec/has_role_spec.rb +61 -49
- data/spec/permissions_spec.rb +35 -0
- data/spec/sieve_spec.rb +2 -2
- metadata +5 -5
data/README.rdoc
CHANGED
@@ -69,19 +69,25 @@ There is an awesome {documentation wiki}[http://wiki.github.com/makandra/aegis/]
|
|
69
69
|
|
70
70
|
== Installation
|
71
71
|
|
72
|
-
|
72
|
+
Aegis is a gem, which you can install with
|
73
|
+
sudo gem install aegis
|
74
|
+
|
75
|
+
In Rails 2, add the following to your <tt>environment.rb</tt>:
|
73
76
|
config.gem 'aegis'
|
74
|
-
Then do a
|
75
|
-
sudo rake gems:install
|
76
77
|
|
77
|
-
|
78
|
-
|
78
|
+
In Rails 3, add the following to your <tt>Gemfile</tt>:
|
79
|
+
gem 'aegis'
|
80
|
+
|
81
|
+
|
82
|
+
== Rails 3 compatibility
|
83
|
+
|
84
|
+
We cannot guarantee Rails 3 compatibility at this point, but we will upgrade the gem when Rails 3 is released.
|
79
85
|
|
80
86
|
|
81
87
|
== Credits
|
82
88
|
|
83
89
|
Henning Koch, Tobias Kraze
|
84
90
|
|
85
|
-
{
|
91
|
+
{makandra.com}[http://makandra.com/]
|
86
92
|
|
87
|
-
{
|
93
|
+
{gem-session.com}[http://gem-session.com/]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0
|
1
|
+
2.1.0
|
data/aegis.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{aegis}
|
8
|
-
s.version = "2.0
|
8
|
+
s.version = "2.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Henning Koch", "Tobias Kraze"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-07-25}
|
13
13
|
s.description = %q{Aegis is an authorization solution for Ruby on Rails that supports roles and a RESTish, resource-style declaration of permission rules.}
|
14
14
|
s.email = %q{henning.koch@makandra.de}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -92,10 +92,10 @@ Gem::Specification.new do |s|
|
|
92
92
|
"spec/app_root/lib/console_with_fixtures.rb",
|
93
93
|
"spec/action_controller_spec.rb",
|
94
94
|
"spec/controllers/reviews_controller_spec.rb",
|
95
|
-
"spec/has_role_spec.rb",
|
96
|
-
"spec/permissions_spec.rb",
|
97
95
|
"spec/spec_helper.rb",
|
98
96
|
"spec/loader_spec.rb",
|
97
|
+
"spec/has_role_spec.rb",
|
98
|
+
"spec/permissions_spec.rb",
|
99
99
|
"spec/sieve_spec.rb"
|
100
100
|
]
|
101
101
|
|
data/lib/aegis/action.rb
CHANGED
@@ -24,12 +24,9 @@ module Aegis
|
|
24
24
|
|
25
25
|
def may?(user, *args)
|
26
26
|
context = extract_context(user, args)
|
27
|
-
|
28
|
-
|
29
|
-
opinion = sieve.may?(context, *args)
|
30
|
-
may = opinion unless opinion.nil?
|
27
|
+
user.roles.any? do |role|
|
28
|
+
may_as_role?(role, context, *args)
|
31
29
|
end
|
32
|
-
may
|
33
30
|
end
|
34
31
|
|
35
32
|
def may!(user, *args)
|
@@ -82,6 +79,16 @@ module Aegis
|
|
82
79
|
|
83
80
|
private
|
84
81
|
|
82
|
+
def may_as_role?(role, context, *args)
|
83
|
+
context.role = role
|
84
|
+
may = role.may_by_default?
|
85
|
+
for sieve in sieves
|
86
|
+
opinion = sieve.may?(context, *args)
|
87
|
+
may = opinion unless opinion.nil?
|
88
|
+
end
|
89
|
+
may
|
90
|
+
end
|
91
|
+
|
85
92
|
# not *args so we can change the array reference
|
86
93
|
def extract_context(user, args)
|
87
94
|
context = {}
|
data/lib/aegis/has_role.rb
CHANGED
@@ -3,35 +3,35 @@ module Aegis
|
|
3
3
|
|
4
4
|
def has_role(options = {})
|
5
5
|
|
6
|
-
if options[:accessor]
|
7
|
-
options[:reader] = "#{options[:accessor]}"
|
8
|
-
options[:writer] = "#{options[:accessor]}="
|
9
|
-
options.delete(:accessor)
|
10
|
-
end
|
11
|
-
|
12
|
-
get_role_name = (options[:reader] || "role_name").to_sym
|
13
|
-
set_role_name = (options[:writer] || "role_name=").to_sym
|
14
|
-
|
15
6
|
permissions = lambda { Aegis::Permissions.app_permissions(options[:permissions]) }
|
16
7
|
|
17
8
|
may_pattern = /^may_(.+?)([\!\?])$/
|
18
9
|
|
10
|
+
send :define_method, :role_names do
|
11
|
+
(role_name || '').split(/\s*,\s*/)
|
12
|
+
end
|
13
|
+
|
14
|
+
send :define_method, :role_names= do |role_names|
|
15
|
+
self.role_name = role_names.join(',')
|
16
|
+
end
|
17
|
+
|
19
18
|
send :define_method, :role do
|
20
|
-
|
19
|
+
roles.first
|
21
20
|
end
|
22
21
|
|
23
|
-
send :define_method, :
|
24
|
-
|
22
|
+
send :define_method, :roles do
|
23
|
+
role_names.collect do |role_name|
|
24
|
+
permissions.call.find_role_by_name(role_name)
|
25
|
+
end.compact
|
25
26
|
end
|
26
27
|
|
27
28
|
metaclass.send :define_method, :validates_role do |*validate_options|
|
28
29
|
validate_options = validate_options[0] || {}
|
29
30
|
|
30
31
|
send :define_method, :validate_role do
|
31
|
-
|
32
|
-
unless role
|
32
|
+
unless role_names.size > 0 && role_names.size == roles.size
|
33
33
|
message = validate_options[:message] || I18n.translate('activerecord.errors.messages.inclusion')
|
34
|
-
errors.add
|
34
|
+
errors.add :role_name, message
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -46,8 +46,8 @@ module Aegis
|
|
46
46
|
end
|
47
47
|
|
48
48
|
send :define_method, :set_default_role_name do
|
49
|
-
if new_record? &&
|
50
|
-
|
49
|
+
if new_record? && role_name.blank?
|
50
|
+
self.role_name = options[:default]
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
data/lib/aegis/sieve.rb
CHANGED
@@ -9,7 +9,7 @@ module Aegis
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def may?(context, *args)
|
12
|
-
matches_role = @role_name == 'everyone' || @role_name == context.
|
12
|
+
matches_role = @role_name == 'everyone' || @role_name == context.role.name
|
13
13
|
if matches_role
|
14
14
|
if @block
|
15
15
|
block_result = context.instance_exec(*args, &@block)
|
data/spec/has_role_spec.rb
CHANGED
@@ -21,79 +21,85 @@ describe Aegis::HasRole do
|
|
21
21
|
it "should define accessors for the role association" do
|
22
22
|
user = @user_class.new
|
23
23
|
user.should respond_to(:role)
|
24
|
-
user.should respond_to(:
|
24
|
+
user.should respond_to(:roles)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should allow a default for new records" do
|
28
|
+
permissions_class = @permissions_class
|
29
|
+
@user_class.class_eval { has_role :permissions => permissions_class, :default => "admin" }
|
30
|
+
user = @user_class.new
|
31
|
+
user.role_name.should == 'admin'
|
25
32
|
end
|
26
33
|
|
27
34
|
end
|
28
35
|
|
29
36
|
describe 'role' do
|
30
37
|
|
31
|
-
it "should
|
38
|
+
it "should return the first role" do
|
32
39
|
user = @user_class.new
|
33
|
-
user.
|
40
|
+
user.should_receive(:roles).and_return(['first role', 'second role'])
|
41
|
+
user.role.should == 'first role'
|
34
42
|
end
|
35
43
|
|
36
|
-
it "should
|
37
|
-
user = @user_class.new
|
38
|
-
user.
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should be nil if the role_name doesn't match a known role" do
|
42
|
-
user = @user_class.new(:role_name => 'nonexisting_role_name')
|
44
|
+
it "should be nil if no roles are associated" do
|
45
|
+
user = @user_class.new
|
46
|
+
user.should_receive(:roles).and_return([])
|
43
47
|
user.role.should be_nil
|
44
48
|
end
|
45
49
|
|
46
|
-
|
47
|
-
permissions_class = @permissions_class
|
48
|
-
@user_class.class_eval { has_role :reader => "role_handle", :permissions => permissions_class }
|
49
|
-
user = @user_class.new
|
50
|
-
user.should_receive(:role_handle).and_return('admin')
|
51
|
-
user.role
|
52
|
-
end
|
50
|
+
end
|
53
51
|
|
54
|
-
|
55
|
-
|
56
|
-
|
52
|
+
describe 'roles' do
|
53
|
+
|
54
|
+
it "should return the corresponding role for each role name" do
|
57
55
|
user = @user_class.new
|
58
|
-
user.should_receive(:
|
59
|
-
user.
|
56
|
+
user.should_receive(:role_names).and_return(['admin', 'user'])
|
57
|
+
user.roles.collect(&:name).should == ['admin', 'user']
|
60
58
|
end
|
61
59
|
|
62
|
-
it "should
|
63
|
-
permissions_class = @permissions_class
|
64
|
-
@user_class.class_eval { has_role :default => "admin", :permissions => permissions_class }
|
60
|
+
it "should ignore unknown role names that doesn't match a known role" do
|
65
61
|
user = @user_class.new
|
66
|
-
user.
|
62
|
+
user.should_receive(:role_names).and_return(['unknown role', 'user'])
|
63
|
+
user.roles.collect(&:name).should == ['user']
|
67
64
|
end
|
68
65
|
|
69
66
|
end
|
70
67
|
|
71
|
-
describe '
|
68
|
+
describe 'role_names' do
|
72
69
|
|
73
|
-
|
74
|
-
|
70
|
+
it "should be empty if the role name is blank" do
|
71
|
+
user = @user_class.new(:role_name => '')
|
72
|
+
user.role_names.should be_empty
|
75
73
|
end
|
76
74
|
|
77
|
-
it "should
|
78
|
-
user = @user_class.new
|
79
|
-
user.
|
80
|
-
user.role = @admin_role
|
75
|
+
it "should be empty if the role_name is nil" do
|
76
|
+
user = @user_class.new(:role_name => nil)
|
77
|
+
user.role_names.should be_empty
|
81
78
|
end
|
82
79
|
|
83
|
-
it "should
|
84
|
-
|
85
|
-
|
86
|
-
user = @user_class.new
|
87
|
-
user.should_receive(:role_handle=).with('admin')
|
88
|
-
user.role = @admin_role
|
80
|
+
it "should deserialize a single role name into an array with a single element" do
|
81
|
+
user = @user_class.new(:role_name => 'admin')
|
82
|
+
user.role_names.should == ['admin']
|
89
83
|
end
|
90
84
|
|
91
|
-
it "should
|
92
|
-
|
93
|
-
|
85
|
+
it "should deserialize multiple, comma-separated role names into an array" do
|
86
|
+
user = @user_class.new(:role_name => 'admin,user')
|
87
|
+
user.role_names.should == ['admin', 'user']
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should ignore whitespace around the comma-separator" do
|
91
|
+
user = @user_class.new(:role_name => 'admin , user')
|
92
|
+
user.role_names.should == ['admin', 'user']
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
describe 'role_names=' do
|
98
|
+
|
99
|
+
it "should serialize the given array into a comma-separated string and store it into #role_name" do
|
94
100
|
user = @user_class.new
|
95
|
-
user.should_receive(:
|
96
|
-
user.
|
101
|
+
user.should_receive(:role_name=).with("first,second")
|
102
|
+
user.role_names = ['first', 'second']
|
97
103
|
end
|
98
104
|
|
99
105
|
end
|
@@ -147,20 +153,26 @@ describe Aegis::HasRole do
|
|
147
153
|
user.run_callbacks(:validate)
|
148
154
|
end
|
149
155
|
|
150
|
-
it "should add an inclusion error to the role name if the role name is
|
156
|
+
it "should add an inclusion error to the role name if the role name is nil" do
|
157
|
+
user = @user_class.new(:role_name => nil)
|
158
|
+
user.errors.should_receive(:add).with(:role_name, I18n.translate('activerecord.errors.messages.inclusion'))
|
159
|
+
user.send(:validate_role)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should add an inclusion error to the role name if the role name is an empty string" do
|
151
163
|
user = @user_class.new(:role_name => '')
|
152
164
|
user.errors.should_receive(:add).with(:role_name, I18n.translate('activerecord.errors.messages.inclusion'))
|
153
165
|
user.send(:validate_role)
|
154
166
|
end
|
155
167
|
|
156
|
-
it "should add an inclusion error to the role name if
|
157
|
-
user = @user_class.new(:role_name => 'nonexisting_role')
|
168
|
+
it "should add an inclusion error to the role name if a role name doesn't match a role" do
|
169
|
+
user = @user_class.new(:role_name => 'user,nonexisting_role')
|
158
170
|
user.errors.should_receive(:add).with(:role_name, I18n.translate('activerecord.errors.messages.inclusion'))
|
159
171
|
user.send(:validate_role)
|
160
172
|
end
|
161
173
|
|
162
|
-
it "should add no error if
|
163
|
-
user = @user_class.new(:role_name => 'admin')
|
174
|
+
it "should add no error if all role names matches a role" do
|
175
|
+
user = @user_class.new(:role_name => 'admin,user')
|
164
176
|
user.errors.should_not_receive(:add)
|
165
177
|
user.send(:validate_role)
|
166
178
|
end
|
data/spec/permissions_spec.rb
CHANGED
@@ -5,6 +5,7 @@ describe Aegis::Permissions do
|
|
5
5
|
before(:each) do
|
6
6
|
|
7
7
|
permissions = @permissions = Class.new(Aegis::Permissions) do
|
8
|
+
role :guest
|
8
9
|
role :user
|
9
10
|
role :moderator
|
10
11
|
role :admin, :default_permission => :allow
|
@@ -117,6 +118,40 @@ describe Aegis::Permissions do
|
|
117
118
|
|
118
119
|
end
|
119
120
|
|
121
|
+
describe 'multiple roles' do
|
122
|
+
|
123
|
+
before(:each) do
|
124
|
+
|
125
|
+
@permissions.class_eval do
|
126
|
+
action :update_news do
|
127
|
+
allow :moderator
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should allow a user with multiple roles access if at least one role passes, even if other roles don't" do
|
134
|
+
person = @user_class.new(:role_names => ['user', 'moderator'])
|
135
|
+
@permissions.may?(person, 'update_news').should be_true
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should deny a user with multiple roles access if no role passes" do
|
139
|
+
person = @user_class.new(:role_names => ['user', 'guest'])
|
140
|
+
@permissions.may?(person, 'update_news').should be_false
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should deny a user with no roles access" do
|
144
|
+
person = @user_class.new(:role_names => [])
|
145
|
+
@permissions.may?(person, 'update_news').should be_false
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should honor default permissions" do
|
149
|
+
person = @user_class.new(:role_names => ['admin'])
|
150
|
+
@permissions.may?(person, 'update_news').should be_true
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
120
155
|
it "should run sieves in a sequence, the result being the last matching sieve" do
|
121
156
|
|
122
157
|
@permissions.class_eval do
|
data/spec/sieve_spec.rb
CHANGED
@@ -4,8 +4,8 @@ describe Aegis::Sieve do
|
|
4
4
|
|
5
5
|
before(:each) do
|
6
6
|
@role = stub('role', :name => 'user')
|
7
|
-
|
8
|
-
@context = OpenStruct.new(:
|
7
|
+
# user = stub('user', :role => role)
|
8
|
+
@context = OpenStruct.new(:role => @role)
|
9
9
|
end
|
10
10
|
|
11
11
|
describe 'may? 'do
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 2
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 2.0.4
|
9
|
+
version: 2.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Henning Koch
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-07-25 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -128,8 +128,8 @@ test_files:
|
|
128
128
|
- spec/app_root/lib/console_with_fixtures.rb
|
129
129
|
- spec/action_controller_spec.rb
|
130
130
|
- spec/controllers/reviews_controller_spec.rb
|
131
|
-
- spec/has_role_spec.rb
|
132
|
-
- spec/permissions_spec.rb
|
133
131
|
- spec/spec_helper.rb
|
134
132
|
- spec/loader_spec.rb
|
133
|
+
- spec/has_role_spec.rb
|
134
|
+
- spec/permissions_spec.rb
|
135
135
|
- spec/sieve_spec.rb
|