id_please 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +5 -2
- data/VERSION +1 -1
- data/id_please.gemspec +17 -7
- data/lib/id_please/config.rb +6 -2
- data/lib/id_please/model_extensions/for_group.rb +26 -0
- data/lib/id_please/model_extensions/for_object.rb +123 -0
- data/lib/id_please/model_extensions/for_subject.rb +181 -0
- data/lib/id_please/model_extensions.rb +202 -104
- data/lib/id_please.rb +5 -0
- data/test/id_please_test.rb +0 -0
- data/test/roles_test.rb +317 -0
- data/test/support/models.rb +33 -0
- data/test/support/schema.rb +36 -0
- data/test/test_helper.rb +44 -0
- metadata +37 -6
- data/test/helper.rb +0 -12
- data/test/test_id_please.rb +0 -7
data/Rakefile
CHANGED
@@ -11,6 +11,9 @@ begin
|
|
11
11
|
gem.homepage = "http://github.com/tastyhat/id_please"
|
12
12
|
gem.authors = ["James Stuart"]
|
13
13
|
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
gem.add_development_dependency "thoughtbot-factory_girl", ">= 0"
|
15
|
+
gem.add_development_dependency "ruby-debug", ">= 0"
|
16
|
+
gem.add_dependency "searchlogic"
|
14
17
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
18
|
end
|
16
19
|
Jeweler::GemcutterTasks.new
|
@@ -21,7 +24,7 @@ end
|
|
21
24
|
require 'rake/testtask'
|
22
25
|
Rake::TestTask.new(:test) do |test|
|
23
26
|
test.libs << 'lib' << 'test'
|
24
|
-
test.pattern = 'test
|
27
|
+
test.pattern = 'test/**/*_test.rb'
|
25
28
|
test.verbose = true
|
26
29
|
end
|
27
30
|
|
@@ -29,7 +32,7 @@ begin
|
|
29
32
|
require 'rcov/rcovtask'
|
30
33
|
Rcov::RcovTask.new do |test|
|
31
34
|
test.libs << 'test'
|
32
|
-
test.pattern = 'test
|
35
|
+
test.pattern = 'test/**/*_test.rb'
|
33
36
|
test.verbose = true
|
34
37
|
end
|
35
38
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/id_please.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{id_please}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["James Stuart"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-28}
|
13
13
|
s.description = %q{Access control gem}
|
14
14
|
s.email = %q{tastyhat@jamesstuart.org}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -31,9 +31,7 @@ Gem::Specification.new do |s|
|
|
31
31
|
"lib/id_please/model_extensions/for_group.rb",
|
32
32
|
"lib/id_please/model_extensions/for_object.rb",
|
33
33
|
"lib/id_please/model_extensions/for_subject.rb",
|
34
|
-
"lib/id_please/model_extensions/for_user.rb"
|
35
|
-
"test/helper.rb",
|
36
|
-
"test/test_id_please.rb"
|
34
|
+
"lib/id_please/model_extensions/for_user.rb"
|
37
35
|
]
|
38
36
|
s.homepage = %q{http://github.com/tastyhat/id_please}
|
39
37
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -41,8 +39,11 @@ Gem::Specification.new do |s|
|
|
41
39
|
s.rubygems_version = %q{1.3.5}
|
42
40
|
s.summary = %q{Access control gem for rails}
|
43
41
|
s.test_files = [
|
44
|
-
"test/
|
45
|
-
"test/
|
42
|
+
"test/id_please_test.rb",
|
43
|
+
"test/roles_test.rb",
|
44
|
+
"test/support/models.rb",
|
45
|
+
"test/support/schema.rb",
|
46
|
+
"test/test_helper.rb"
|
46
47
|
]
|
47
48
|
|
48
49
|
if s.respond_to? :specification_version then
|
@@ -51,11 +52,20 @@ Gem::Specification.new do |s|
|
|
51
52
|
|
52
53
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
53
54
|
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<thoughtbot-factory_girl>, [">= 0"])
|
56
|
+
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
57
|
+
s.add_runtime_dependency(%q<searchlogic>, [">= 0"])
|
54
58
|
else
|
55
59
|
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
60
|
+
s.add_dependency(%q<thoughtbot-factory_girl>, [">= 0"])
|
61
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
62
|
+
s.add_dependency(%q<searchlogic>, [">= 0"])
|
56
63
|
end
|
57
64
|
else
|
58
65
|
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
66
|
+
s.add_dependency(%q<thoughtbot-factory_girl>, [">= 0"])
|
67
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
68
|
+
s.add_dependency(%q<searchlogic>, [">= 0"])
|
59
69
|
end
|
60
70
|
end
|
61
71
|
|
data/lib/id_please/config.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
module IdPlease
|
2
2
|
@@config = {
|
3
3
|
:default_role_class_name => 'Role',
|
4
|
-
:
|
4
|
+
:default_subject_class_name => 'User',
|
5
5
|
:default_group_class_name => 'Group',
|
6
6
|
:default_assignment_class_name => 'Assignment',
|
7
|
-
:
|
7
|
+
:default_group_role => 'member',
|
8
|
+
:default_subject_method => :current_user,
|
9
|
+
:default_association_name => :assigned_roles,
|
10
|
+
:groups_enabled => true,
|
11
|
+
:nested_groups => true
|
8
12
|
}
|
9
13
|
|
10
14
|
mattr_reader :config
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module IdPlease
|
2
|
+
module ModelExtensions
|
3
|
+
module ForGroup
|
4
|
+
def children(*args)
|
5
|
+
options = args.extract_options!
|
6
|
+
all_children = _auth_assign_class.role_name_eq(_auth_group_role).role_authorizable_eq(self).all(:include => :subject).collect(&:subject)
|
7
|
+
|
8
|
+
if _auth_nested_groups == true && options[:nested] != false
|
9
|
+
all_children.select { |child| child._auth_is_group == true }.each do |child|
|
10
|
+
all_children << child.children
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
all_children.flatten.uniq
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_role!(role_name, object = nil)
|
18
|
+
if object && object.kind_of?(self.class) && role_name.to_s == _auth_group_role && self.children.include?(object)
|
19
|
+
raise "Attempt to make circular membership loop"
|
20
|
+
else
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module IdPlease
|
2
|
+
module ModelExtensions
|
3
|
+
module ForObject
|
4
|
+
##
|
5
|
+
# Role check.
|
6
|
+
#
|
7
|
+
# @return [Boolean] Returns true if +subject+ has a role +role_name+ on this object.
|
8
|
+
#
|
9
|
+
# @param [Symbol,String] role_name Role name
|
10
|
+
# @param [Subject] subject Subject to add role for
|
11
|
+
# @see Acl9::ModelExtensions::Subject#has_role?
|
12
|
+
def accepts_role?(role_name, subject, options = {})
|
13
|
+
subject.has_role?(role_name, self, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
##
|
19
|
+
# Add role on the object to specified subject.
|
20
|
+
#
|
21
|
+
# @param [Symbol,String] role_name Role name
|
22
|
+
# @param [Subject] subject Subject to add role for
|
23
|
+
# @see Acl9::ModelExtensions::Subject#has_role!
|
24
|
+
def accepts_role!(role_name, subject)
|
25
|
+
subject.has_role!(role_name, self)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def list_subjects_all_roles(*args)
|
30
|
+
options = args.extract_options!
|
31
|
+
|
32
|
+
find_subjects(nil, options)
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def list_subjects_for(role_name, *args)
|
37
|
+
options = args.extract_options!
|
38
|
+
|
39
|
+
find_subjects(role_name, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
def method_missing(method_sym, *arguments, &block)
|
45
|
+
# the first argument is a Symbol, so you need to_s it if you want to pattern match
|
46
|
+
if method_sym.to_s =~ /^list_(.+)$/
|
47
|
+
list_subjects_for($1.singularize, *arguments)
|
48
|
+
else
|
49
|
+
super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
##
|
55
|
+
# Free specified subject of a role on this object.
|
56
|
+
#
|
57
|
+
# @param [Symbol,String] role_name Role name
|
58
|
+
# @param [Subject] subject Subject to remove role from
|
59
|
+
# @see Acl9::ModelExtensions::Subject#has_no_role!
|
60
|
+
def accepts_no_role!(role_name, subject)
|
61
|
+
subject.has_no_role!(role_name, self)
|
62
|
+
end
|
63
|
+
|
64
|
+
# ##
|
65
|
+
# # Are there any roles for the specified +subject+ on this object?
|
66
|
+
# #
|
67
|
+
# # @param [Subject] subject Subject to query roles
|
68
|
+
# # @return [Boolean] Returns true if +subject+ has any roles on this object.
|
69
|
+
# # @see Acl9::ModelExtensions::Subject#has_roles_for?
|
70
|
+
# def accepts_roles_by?(subject)
|
71
|
+
# subject.has_roles_for? self
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# alias :accepts_role_by? :accepts_roles_by?
|
75
|
+
#
|
76
|
+
# ##
|
77
|
+
# # Which roles does +subject+ have on this object?
|
78
|
+
# #
|
79
|
+
# # @return [Array<Role>] Role instances, associated both with +subject+ and +object+
|
80
|
+
# # @param [Subject] subject Subject to query roles
|
81
|
+
# # @see Acl9::ModelExtensions::Subject#roles_for
|
82
|
+
# def accepted_roles_by(subject)
|
83
|
+
# subject.roles_for self
|
84
|
+
# end
|
85
|
+
|
86
|
+
private
|
87
|
+
def get_role(role_name, object)
|
88
|
+
_auth_role_class.authorizable_eq(object).name_eq(role_name.to_s).first
|
89
|
+
end
|
90
|
+
|
91
|
+
def find_subjects(role_name = nil, options = {})
|
92
|
+
base_subjects = if role_name
|
93
|
+
self._auth_assign_class.role_name_eq(role_name.to_s).role_authorizable_eq(self).all(:include => :subject).collect(&:subject).uniq
|
94
|
+
else
|
95
|
+
self._auth_assign_class.role_authorizable_eq(self).all(:include => :subject).collect(&:subject).uniq
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
if options[:check_groups] == false
|
100
|
+
base_subjects
|
101
|
+
else
|
102
|
+
to_find = base_subjects.dup
|
103
|
+
to_find.select { |subj| subj._auth_is_group }.each do |subj|
|
104
|
+
base_subjects << subj.children
|
105
|
+
end
|
106
|
+
|
107
|
+
base_subjects.flatten.uniq
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
protected
|
112
|
+
|
113
|
+
def _auth_role_class
|
114
|
+
self.class._auth_role_class_name.constantize
|
115
|
+
end
|
116
|
+
|
117
|
+
def _auth_assign_class
|
118
|
+
self.class._auth_assign_class_name.constantize
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
module IdPlease
|
2
|
+
module ModelExtensions
|
3
|
+
module ForSubject
|
4
|
+
def in_group!(group)
|
5
|
+
raise "Groups must be enabled for this model" unless _auth_groups_enabled
|
6
|
+
raise "Object passed in not a group" unless group.kind_of?(_auth_group_class)
|
7
|
+
|
8
|
+
self.has_role!(_auth_group_role, group)
|
9
|
+
end
|
10
|
+
|
11
|
+
def in_group?(group)
|
12
|
+
raise "Groups must be enabled for this model" unless _auth_groups_enabled
|
13
|
+
raise "Object passed in not a group" unless group.kind_of?(_auth_group_class)
|
14
|
+
|
15
|
+
self.has_role?(_auth_group_role, group)
|
16
|
+
end
|
17
|
+
|
18
|
+
def not_in_group!(group)
|
19
|
+
raise "Groups must be enabled for this model" unless _auth_groups_enabled
|
20
|
+
raise "Object passed in not a group" unless group.kind_of?(_auth_group_class)
|
21
|
+
|
22
|
+
self.has_no_role!(_auth_group_role, group)
|
23
|
+
end
|
24
|
+
|
25
|
+
def not_in_any_group!
|
26
|
+
raise "Groups must be enabled for this model" unless _auth_groups_enabled
|
27
|
+
|
28
|
+
all_groups.each { |group| self.not_in_group!(group) }
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def groups(*args)
|
33
|
+
raise "Groups must be enabled for this model" unless _auth_groups_enabled
|
34
|
+
|
35
|
+
options = args.extract_options!
|
36
|
+
all_groups = direct_parent_groups(self)
|
37
|
+
|
38
|
+
if _auth_nested_groups && options[:nested] != false
|
39
|
+
infinite_loop_counter = 25
|
40
|
+
to_find = all_groups.dup
|
41
|
+
|
42
|
+
until to_find.empty? || (infinite_loop_counter -=1) <= 0
|
43
|
+
to_find = direct_parent_groups(*to_find)
|
44
|
+
all_groups += to_find
|
45
|
+
end
|
46
|
+
|
47
|
+
all_groups.uniq
|
48
|
+
else
|
49
|
+
all_groups
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
def has_role?(role_name, object = nil, option_hash = {})
|
57
|
+
subjects_to_check = option_hash[:check_groups] == false ? [self] : self_and_groups
|
58
|
+
|
59
|
+
!Role.authorizable_eq(object).name_eq(role_name.to_s).assignments_subject_eq(*subjects_to_check).empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def has_role!(role_name, object = nil)
|
63
|
+
role = get_role(role_name, object)
|
64
|
+
|
65
|
+
if role.nil?
|
66
|
+
role_attrs = case object
|
67
|
+
when Class
|
68
|
+
{ :authorizable_type => object.to_s }
|
69
|
+
when nil
|
70
|
+
{}
|
71
|
+
else
|
72
|
+
{ :authorizable => object }
|
73
|
+
end.merge(:name => role_name.to_s)
|
74
|
+
|
75
|
+
role = self._auth_assigned_roles.create!(role_attrs)
|
76
|
+
else
|
77
|
+
unless assigned_to_role?(role)
|
78
|
+
self._auth_assigned_roles << role
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
role
|
83
|
+
end
|
84
|
+
|
85
|
+
def has_roles_for?(object)
|
86
|
+
!get_assigned_roles_for(object).empty?
|
87
|
+
end
|
88
|
+
|
89
|
+
alias :has_role_for? :has_roles_for?
|
90
|
+
|
91
|
+
def roles_for(object)
|
92
|
+
get_assigned_roles_for(object)
|
93
|
+
end
|
94
|
+
|
95
|
+
def has_no_role!(role_name, object = nil)
|
96
|
+
role = get_role(role_name, object)
|
97
|
+
|
98
|
+
remove_from_role(role)
|
99
|
+
end
|
100
|
+
|
101
|
+
def has_no_roles_for!(object = nil)
|
102
|
+
roles_for(object).each { |role| remove_from_role(role) }
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
##
|
108
|
+
# Unassign all roles from +self+.
|
109
|
+
def has_no_roles!
|
110
|
+
roles = self._auth_assigned_roles.clone
|
111
|
+
roles.each do |role|
|
112
|
+
remove_from_role(role)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def direct_parent_groups(*subjects)
|
119
|
+
_auth_role_class.assignments_subject_eq(*subjects).name_eq(_auth_group_role).authorizable_type_eq(_auth_group_class_name).all(:include => :authorizable).collect(&:authorizable)
|
120
|
+
end
|
121
|
+
|
122
|
+
def self_and_groups
|
123
|
+
if _auth_groups_enabled
|
124
|
+
groups << self
|
125
|
+
else
|
126
|
+
[self]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def remove_from_role(role)
|
131
|
+
if role
|
132
|
+
self._auth_assigned_roles.delete(role)
|
133
|
+
|
134
|
+
role.destroy if self._auth_assign_class.role_id_eq(role).empty?
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def get_role(role_name, object)
|
139
|
+
_auth_role_class.authorizable_eq(object).name_eq(role_name.to_s).first
|
140
|
+
end
|
141
|
+
|
142
|
+
def assigned_to_role?(role)
|
143
|
+
!!_auth_assign_class.subject_eq(self).role_id_eq(role).first
|
144
|
+
end
|
145
|
+
|
146
|
+
def get_assigned_roles_for(object)
|
147
|
+
_auth_role_class.authorizable_eq(object).assignments_subject_eq(self)
|
148
|
+
end
|
149
|
+
|
150
|
+
protected
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
def _auth_role_class
|
155
|
+
self.class._auth_role_class_name.constantize
|
156
|
+
end
|
157
|
+
|
158
|
+
def _auth_subject_class
|
159
|
+
self.class._auth_subject_class_name.constantize
|
160
|
+
end
|
161
|
+
|
162
|
+
def _auth_group_class
|
163
|
+
self.class._auth_group_class_name.constantize
|
164
|
+
end
|
165
|
+
|
166
|
+
def _auth_assign_class
|
167
|
+
self.class._auth_assign_class_name.constantize
|
168
|
+
end
|
169
|
+
|
170
|
+
def _auth_role_assoc
|
171
|
+
self.class._auth_role_assoc_name
|
172
|
+
end
|
173
|
+
|
174
|
+
def _auth_assigned_roles
|
175
|
+
send(self._auth_role_assoc)
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'model_extensions', 'for_subject')
|
2
|
-
require File.join(File.dirname(__FILE__), 'model_extensions', 'for_object')
|
3
1
|
|
4
2
|
module IdPlease
|
5
3
|
module ModelExtensions #:nodoc:
|
@@ -8,132 +6,232 @@ module IdPlease
|
|
8
6
|
end
|
9
7
|
|
10
8
|
module ClassMethods
|
11
|
-
# Add #has_role? and other role methods to the class.
|
12
|
-
# Makes a class a auth. subject class.
|
13
|
-
#
|
14
|
-
# @param [Hash] options the options for tuning
|
15
|
-
# @option options [String] :role_class_name (Acl9::config[:default_role_class_name])
|
16
|
-
# Class name of the role class (e.g. 'AccountRole')
|
17
|
-
# @option options [String] :join_table_name (Acl9::config[:default_join_table_name])
|
18
|
-
# Join table name (e.g. 'accounts_account_roles')
|
19
|
-
# @option options [String] :association_name (Acl9::config[:default_association_name])
|
20
|
-
# Association name (e.g. ':roles')
|
21
|
-
# @example
|
22
|
-
# class User < ActiveRecord::Base
|
23
|
-
# acts_as_authorization_subject
|
24
|
-
# end
|
25
|
-
#
|
26
|
-
# user = User.new
|
27
|
-
# user.roles #=> returns Role objects, associated with the user
|
28
|
-
# user.has_role!(...)
|
29
|
-
# user.has_no_role!(...)
|
30
|
-
#
|
31
|
-
# # other functions from Acl9::ModelExtensions::Subject are made available
|
32
|
-
#
|
33
|
-
# @see Acl9::ModelExtensions::Subject
|
34
|
-
#
|
35
9
|
def acts_as_authorization_subject(options = {})
|
36
|
-
assoc = options[:association_name] ||
|
37
|
-
role = options[:role_class_name] ||
|
38
|
-
|
39
|
-
|
10
|
+
assoc = options[:association_name] || IdPlease.config[:default_association_name]
|
11
|
+
role = options[:role_class_name] || IdPlease.config[:default_role_class_name]
|
12
|
+
role_assoc = role.downcase.underscore.to_sym
|
13
|
+
|
14
|
+
group = options[:group_class_name] || IdPlease.config[:default_group_class_name]
|
15
|
+
|
16
|
+
assign = options[:assignment_class_name] || IdPlease.config[:default_assignment_class_name]
|
17
|
+
assign_table = assign.constantize.table_name
|
18
|
+
|
19
|
+
#TODO
|
20
|
+
groups_enabled = options.has_key?(:groups_enabled) ? options[:groups_enabled] : IdPlease.config[:groups_enabled]
|
21
|
+
nested_groups = options.has_key?(:nested_groups) ? options[:nested_groups] : IdPlease.config[:nested_groups]
|
22
|
+
group_role = options[:group_role] || IdPlease.config[:default_group_role]
|
23
|
+
|
24
|
+
has_many assign_table.to_sym, :class_name => assign, :as => :subject, :dependent => :destroy
|
25
|
+
has_many assoc, :through => assign_table.to_sym, :source => role_assoc
|
40
26
|
|
41
|
-
has_and_belongs_to_many assoc, :class_name => role, :join_table => join_table
|
42
27
|
|
43
28
|
cattr_accessor :_auth_role_class_name, :_auth_subject_class_name,
|
44
|
-
:
|
29
|
+
:_auth_groups_enabled, :_auth_nested_groups,
|
30
|
+
:_auth_group_class_name, :_auth_assign_class_name,
|
31
|
+
:_auth_role_assoc_name, :_auth_group_role,
|
32
|
+
:_auth_is_group
|
45
33
|
|
46
34
|
self._auth_role_class_name = role
|
47
35
|
self._auth_subject_class_name = self.to_s
|
36
|
+
self._auth_assign_class_name = assign
|
37
|
+
self._auth_group_class_name = group
|
48
38
|
self._auth_role_assoc_name = assoc
|
39
|
+
self._auth_group_role = group_role
|
40
|
+
self._auth_groups_enabled = groups_enabled
|
41
|
+
self._auth_nested_groups = nested_groups
|
42
|
+
self._auth_is_group = false
|
43
|
+
|
49
44
|
|
50
|
-
include
|
45
|
+
include IdPlease::ModelExtensions::ForSubject
|
51
46
|
end
|
47
|
+
|
48
|
+
def acts_as_authorization_group(options = {})
|
49
|
+
assoc = options[:association_name] || IdPlease.config[:default_association_name]
|
50
|
+
role = options[:role_class_name] || IdPlease.config[:default_role_class_name]
|
51
|
+
role_assoc = role.downcase.underscore.to_sym
|
52
|
+
|
53
|
+
subject = options[:subject_class_name] || IdPlease.config[:default_subject_class_name]
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
# class Product < ActiveRecord::Base
|
62
|
-
# acts_as_authorization_object
|
63
|
-
# end
|
64
|
-
#
|
65
|
-
# product = Product.new
|
66
|
-
# product.accepted_roles #=> returns Role objects, associated with the product
|
67
|
-
# product.users #=> returns User objects, associated with the product
|
68
|
-
# product.accepts_role!(...)
|
69
|
-
# product.accepts_no_role!(...)
|
70
|
-
# # other functions from Acl9::ModelExtensions::Object are made available
|
71
|
-
#
|
72
|
-
# @see Acl9::ModelExtensions::Object
|
73
|
-
#
|
74
|
-
def acts_as_authorization_object(options = {})
|
75
|
-
subject = options[:subject_class_name] || Acl9::config[:default_subject_class_name]
|
76
|
-
subj_table = subject.constantize.table_name
|
77
|
-
subj_col = subject.underscore
|
55
|
+
assign = options[:assignment_class_name] || IdPlease.config[:default_assignment_class_name]
|
56
|
+
assign_table = assign.constantize.table_name
|
57
|
+
|
58
|
+
#TODO
|
59
|
+
|
60
|
+
groups_enabled = options.has_key?(:groups_enabled) ? options[:groups_enabled] : IdPlease.config[:groups_enabled]
|
61
|
+
nested_groups = options.has_key?(:nested_groups) ? options[:nested_groups] : IdPlease.config[:nested_groups]
|
62
|
+
raise "Do not use acts_as_authorization_group if groups are disabled." unless groups_enabled
|
78
63
|
|
79
|
-
role = options[:role_class_name] || Acl9::config[:default_role_class_name]
|
80
|
-
role_table = role.constantize.table_name
|
81
64
|
|
82
|
-
|
83
|
-
FROM #{subj_table}
|
84
|
-
INNER JOIN #{role_table}_#{subj_table} ON #{subj_col}_id = #{subj_table}.id
|
85
|
-
INNER JOIN #{role_table} ON #{role_table}.id = #{role.underscore}_id
|
86
|
-
EOS
|
65
|
+
group_role = options[:group_role] || IdPlease.config[:default_group_role]
|
87
66
|
|
88
|
-
|
89
|
-
|
90
|
-
AND authorizable_id = #{column_for_attribute(self.class.primary_key).text? ? "'#{id}'": id}
|
91
|
-
EOS
|
67
|
+
has_many assign_table.to_sym, :class_name => assign, :as => :subject, :dependent => :destroy
|
68
|
+
has_many assoc, :through => :assignments, :class_name => role, :source => role_assoc
|
92
69
|
|
93
|
-
has_many :accepted_roles, :as => :authorizable, :class_name => role, :dependent => :destroy
|
94
70
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
71
|
+
cattr_accessor :_auth_role_class_name, :_auth_subject_class_name,
|
72
|
+
:_auth_groups_enabled, :_auth_nested_groups,
|
73
|
+
:_auth_group_class_name, :_auth_assign_class_name,
|
74
|
+
:_auth_role_assoc_name, :_auth_group_role,
|
75
|
+
:_auth_is_group
|
76
|
+
|
77
|
+
self._auth_role_class_name = role
|
78
|
+
self._auth_subject_class_name = subject
|
79
|
+
self._auth_assign_class_name = assign
|
80
|
+
self._auth_group_class_name = self.to_s
|
81
|
+
self._auth_role_assoc_name = assoc
|
82
|
+
self._auth_groups_enabled = groups_enabled
|
83
|
+
self._auth_nested_groups = nested_groups
|
84
|
+
self._auth_group_role = group_role
|
85
|
+
self._auth_is_group = true
|
86
|
+
|
87
|
+
include IdPlease::ModelExtensions::ForSubject
|
88
|
+
include IdPlease::ModelExtensions::ForGroup
|
89
|
+
include IdPlease::ModelExtensions::ForObject
|
90
|
+
end
|
91
|
+
|
92
|
+
|
99
93
|
|
100
|
-
|
94
|
+
def acts_as_authorization_object(options = {})
|
95
|
+
subject = options[:subject_class_name] || IdPlease.config[:default_subject_class_name]
|
96
|
+
subj_table = subject.constantize.table_name
|
97
|
+
|
98
|
+
role = options[:role_class_name] || IdPlease.config[:default_role_class_name]
|
99
|
+
role_table = role.constantize.table_name
|
100
|
+
|
101
|
+
assign = options[:assignment_class_name] || IdPlease.config[:default_assignment_class_name]
|
102
|
+
|
103
|
+
groups_enabled = options[:groups_enabled] || IdPlease.config[:groups_enabled]
|
104
|
+
nested_groups = options[:nested_groups] || IdPlease.config[:nested_groups]
|
105
|
+
group_role = options[:group_role] || IdPlease.config[:group_role]
|
106
|
+
|
107
|
+
|
108
|
+
has_many role_table.to_sym, :dependent => :destroy, :as => :authorizable
|
109
|
+
|
110
|
+
|
111
|
+
cattr_accessor :_auth_role_class_name, :_auth_groups_enabled,
|
112
|
+
:_auth_nested_groups, :_auth_assign_class_name,
|
113
|
+
:_auth_group_role
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
self._auth_role_class_name = role
|
118
|
+
self._auth_assign_class_name = assign
|
119
|
+
self._auth_group_role = group_role
|
120
|
+
self._auth_groups_enabled = groups_enabled
|
121
|
+
self._auth_nested_groups = nested_groups
|
122
|
+
|
123
|
+
|
124
|
+
include IdPlease::ModelExtensions::ForObject
|
101
125
|
end
|
102
126
|
|
103
|
-
# Make a class an auth role class.
|
104
|
-
#
|
105
|
-
# You'll probably never create or use objects of this class directly.
|
106
|
-
# Various auth. subject and object methods will do that for you
|
107
|
-
# internally.
|
108
|
-
#
|
109
|
-
# @param [Hash] options the options for tuning
|
110
|
-
# @option options [String] :subject_class_name (Acl9::config[:default_subject_class_name])
|
111
|
-
# Subject class name (e.g. 'User', or 'Account)
|
112
|
-
# @option options [String] :join_table_name (Acl9::config[:default_join_table_name])
|
113
|
-
# Join table name (e.g. 'accounts_account_roles')
|
114
|
-
#
|
115
|
-
# @example
|
116
|
-
# class Role < ActiveRecord::Base
|
117
|
-
# acts_as_authorization_role
|
118
|
-
# end
|
119
|
-
#
|
120
|
-
# @see Acl9::ModelExtensions::Subject#has_role!
|
121
|
-
# @see Acl9::ModelExtensions::Subject#has_role?
|
122
|
-
# @see Acl9::ModelExtensions::Subject#has_no_role!
|
123
|
-
# @see Acl9::ModelExtensions::Object#accepts_role!
|
124
|
-
# @see Acl9::ModelExtensions::Object#accepts_role?
|
125
|
-
# @see Acl9::ModelExtensions::Object#accepts_no_role!
|
126
127
|
def acts_as_authorization_role(options = {})
|
127
|
-
|
128
|
-
|
129
|
-
|
128
|
+
validates_presence_of :name
|
129
|
+
validates_uniqueness_of :name, :scope => [:authorizable_type, :authorizable_id]
|
130
|
+
|
131
|
+
subject = options[:subject_class_name] || IdPlease.config[:default_subject_class_name]
|
132
|
+
|
133
|
+
assign = options[:assignment_class_name] || IdPlease.config[:default_assignment_class_name]
|
134
|
+
assign_table = assign.constantize.table_name
|
135
|
+
|
136
|
+
groups_enabled = options[:groups_enabled] || IdPlease.config[:groups_enabled]
|
130
137
|
|
131
|
-
|
132
|
-
|
133
|
-
:join_table => join_table
|
138
|
+
nested_groups = options[:nested_groups] || IdPlease.config[:nested_groups]
|
139
|
+
group_role = options[:group_role] || IdPlease.config[:group_role]
|
134
140
|
|
141
|
+
role_table = self.table_name
|
142
|
+
|
143
|
+
has_many assign_table.to_sym, :dependent => :destroy
|
135
144
|
belongs_to :authorizable, :polymorphic => true
|
145
|
+
|
146
|
+
|
147
|
+
self.named_scope :authorizable_eq, lambda { |*objs|
|
148
|
+
obj_hash = {}
|
149
|
+
cond_sql = []
|
150
|
+
cond_parameters = []
|
151
|
+
|
152
|
+
if objs.include?(nil) || objs.empty?
|
153
|
+
cond_sql << "#{role_table}.authorizable_type IS NULL AND #{role_table}.authorizable_id IS NULL"
|
154
|
+
end
|
155
|
+
|
156
|
+
objs.compact!
|
157
|
+
|
158
|
+
unless objs.nil? || objs.length == 0
|
159
|
+
obj_hash = {}
|
160
|
+
|
161
|
+
objs.each { |obj|
|
162
|
+
obj_hash.has_key?(obj.class) ? obj_hash[obj.class] << obj.id : obj_hash[obj.class] = [obj.id]
|
163
|
+
}
|
164
|
+
|
165
|
+
|
166
|
+
obj_hash.each_pair { |class_name, ids|
|
167
|
+
cond_sql << "#{role_table}.authorizable_type = '#{class_name}' AND #{role_table}.authorizable_id IN(?)"
|
168
|
+
cond_parameters << ids
|
169
|
+
}
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
{:conditions => [cond_sql.join(" OR "), *cond_parameters].compact}
|
174
|
+
}
|
175
|
+
|
176
|
+
|
177
|
+
include IdPlease::ModelExtensions::ForRole
|
178
|
+
|
179
|
+
|
180
|
+
cattr_accessor :_auth_role_class_name, :_auth_groups_enabled,
|
181
|
+
:_auth_nested_groups, :_auth_assign_class_name
|
182
|
+
|
183
|
+
self._auth_role_class_name = self.to_s
|
184
|
+
self._auth_assign_class_name = assign
|
185
|
+
|
186
|
+
self._auth_groups_enabled = groups_enabled
|
187
|
+
self._auth_nested_groups = nested_groups
|
188
|
+
|
189
|
+
|
190
|
+
|
136
191
|
end
|
192
|
+
|
193
|
+
|
194
|
+
def acts_as_authorization_assignment(options = {})
|
195
|
+
role = options[:role_class_name] || IdPlease.config[:default_role_class_name]
|
196
|
+
role_assoc = role.downcase.underscore.to_sym
|
197
|
+
|
198
|
+
assignment_table = self.table_name
|
199
|
+
|
200
|
+
belongs_to :subject, :polymorphic => true
|
201
|
+
#TODO :fix:
|
202
|
+
belongs_to role_assoc
|
203
|
+
|
204
|
+
|
205
|
+
self.named_scope :subject_eq, lambda { |*objs|
|
206
|
+
obj_hash = {}
|
207
|
+
cond_sql = []
|
208
|
+
cond_parameters = []
|
209
|
+
|
210
|
+
if objs.include?(nil) || objs.empty?
|
211
|
+
cond_sql << "#{assignment_table}.subject_type IS NULL AND #{assignment_table}.subject_id IS NULL"
|
212
|
+
end
|
213
|
+
|
214
|
+
objs.compact!
|
215
|
+
|
216
|
+
unless objs.nil? || objs.length == 0
|
217
|
+
obj_hash = {}
|
218
|
+
|
219
|
+
objs.each { |obj|
|
220
|
+
obj_hash.has_key?(obj.class) ? obj_hash[obj.class] << obj.id : obj_hash[obj.class] = [obj.id]
|
221
|
+
}
|
222
|
+
|
223
|
+
|
224
|
+
obj_hash.each_pair { |class_name, ids|
|
225
|
+
cond_sql << "#{assignment_table}.subject_type = '#{class_name}' AND #{assignment_table}.subject_id IN(?)"
|
226
|
+
cond_parameters << ids
|
227
|
+
}
|
228
|
+
|
229
|
+
end
|
230
|
+
{:conditions => [cond_sql.join(" OR "), *cond_parameters].compact}
|
231
|
+
|
232
|
+
}
|
233
|
+
end
|
234
|
+
|
137
235
|
end
|
138
236
|
end
|
139
237
|
end
|
data/lib/id_please.rb
CHANGED
@@ -2,6 +2,11 @@ require 'id_please/config'
|
|
2
2
|
|
3
3
|
if defined? ActiveRecord::Base
|
4
4
|
require 'id_please/model_extensions'
|
5
|
+
require 'id_please/model_extensions/for_subject'
|
6
|
+
require 'id_please/model_extensions/for_subject_with_group'
|
7
|
+
require 'id_please/model_extensions/for_object'
|
8
|
+
require 'id_please/model_extensions/for_group'
|
9
|
+
require 'id_please/model_extensions/for_role'
|
5
10
|
ActiveRecord::Base.send(:include, IdPlease::ModelExtensions)
|
6
11
|
end
|
7
12
|
|
File without changes
|
data/test/roles_test.rb
ADDED
@@ -0,0 +1,317 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'support/models'
|
3
|
+
load 'support/schema.rb'
|
4
|
+
|
5
|
+
class ActiveSupport::TestCase
|
6
|
+
def self.should_handle_basic_role_manipulation(subject_class)
|
7
|
+
context "for #{subject_class.to_s}: " do
|
8
|
+
setup do
|
9
|
+
Role.delete_all
|
10
|
+
[subject_class, Foo, Bar, Uuid].each { |c| c.delete_all }
|
11
|
+
@subject1 = subject_class.create!
|
12
|
+
@subject2 = subject_class.create!
|
13
|
+
@foo = Foo.create!
|
14
|
+
@bar = Bar.create!
|
15
|
+
@uuid = Uuid.create!(:uuid => "C41642EE-2780-0001-189F-17F3101B26E0")
|
16
|
+
end
|
17
|
+
|
18
|
+
should "not have any roles by default" do
|
19
|
+
%w(user manager admin owner).each do |role|
|
20
|
+
assert_false @subject1.has_role?(role)
|
21
|
+
assert_false @subject1.has_role?(role, @foo)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "Given a global role" do
|
26
|
+
setup do
|
27
|
+
@subject1.has_role!(:admin)
|
28
|
+
end
|
29
|
+
|
30
|
+
should_change "create a role successfully", :by => 1 do
|
31
|
+
Role.count
|
32
|
+
end
|
33
|
+
|
34
|
+
should "not distinguish between symbols and strings" do
|
35
|
+
assert @subject1.has_role?("admin")
|
36
|
+
end
|
37
|
+
|
38
|
+
should "assign roles to a specific user" do
|
39
|
+
assert @subject1.has_role?(:admin)
|
40
|
+
assert_false @subject2.has_role?(:admin)
|
41
|
+
end
|
42
|
+
|
43
|
+
should "distinguish between names of roles" do
|
44
|
+
assert_false @subject1.has_role?(:manager)
|
45
|
+
end
|
46
|
+
|
47
|
+
should "not count a global role as an object role" do
|
48
|
+
assert_false @subject1.has_role?(:admin, @foo)
|
49
|
+
assert_false @subject1.has_roles_for?(@foo)
|
50
|
+
end
|
51
|
+
|
52
|
+
should "not let objects accept it" do
|
53
|
+
[@foo,@bar].each do |obj|
|
54
|
+
assert_false obj.accepts_role?(:admin, @subject1)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
should "reading roles should not add another role" do
|
59
|
+
assert_no_difference "Role.count" do
|
60
|
+
@subject1.has_role!(:admin)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "with two users" do
|
65
|
+
setup do
|
66
|
+
@subject2.has_role!(:admin)
|
67
|
+
end
|
68
|
+
|
69
|
+
should "remove assignments to roles through has_no_role!" do
|
70
|
+
@subject1.has_no_role!(:admin)
|
71
|
+
assert_false @subject1.has_role?(:admin)
|
72
|
+
end
|
73
|
+
|
74
|
+
should "only delete roles when they have no assignments" do
|
75
|
+
assert_no_difference 'Role.count' do
|
76
|
+
@subject1.has_no_role!(:admin)
|
77
|
+
end
|
78
|
+
|
79
|
+
assert_difference 'Role.count', -1 do
|
80
|
+
@subject2.has_no_role!(:admin)
|
81
|
+
end
|
82
|
+
|
83
|
+
assert_false @subject1.has_role?(:admin)
|
84
|
+
assert_false @subject2.has_role?(:admin)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "Given an object role" do
|
91
|
+
setup do
|
92
|
+
@subject1.has_role!(:admin, @foo)
|
93
|
+
end
|
94
|
+
|
95
|
+
should_change "create a role successfully", :by => 1 do
|
96
|
+
Role.count
|
97
|
+
end
|
98
|
+
|
99
|
+
should "assign roles to a specific user" do
|
100
|
+
assert @subject1.has_role?(:admin, @foo)
|
101
|
+
assert @subject1.has_roles_for?(@foo)
|
102
|
+
assert @subject1.has_role_for?(@foo)
|
103
|
+
|
104
|
+
roles = @subject1.roles_for(@foo)
|
105
|
+
assert_equal 1, roles.length
|
106
|
+
assert_equal "admin", roles.first.name
|
107
|
+
|
108
|
+
assert_false @subject1.has_role?(:manager, @foo)
|
109
|
+
assert_false @subject2.has_role?(:admin, @foo)
|
110
|
+
assert_false @subject2.has_roles_for?(@foo)
|
111
|
+
end
|
112
|
+
|
113
|
+
should "let the object accept it" do
|
114
|
+
assert @foo.accepts_role?(:admin, @subject1)
|
115
|
+
assert_false @bar.accepts_role?(:admin, @subject1)
|
116
|
+
|
117
|
+
@bar.accepts_role!(:admin, @subject1)
|
118
|
+
assert @bar.accepts_role?(:admin, @subject1)
|
119
|
+
|
120
|
+
@bar.accepts_no_role!(:admin, @subject1)
|
121
|
+
assert_false @bar.accepts_role?(:admin, @subject1)
|
122
|
+
end
|
123
|
+
|
124
|
+
should "allow the object to list its roles" do
|
125
|
+
assert_equal 1, @foo.roles.size
|
126
|
+
end
|
127
|
+
|
128
|
+
should "not count an object role as an global role" do
|
129
|
+
assert_false @subject1.has_role?(:admin)
|
130
|
+
end
|
131
|
+
|
132
|
+
should "reuse roles" do
|
133
|
+
assert_no_difference 'Role.count' do
|
134
|
+
@subject2.has_role!(:admin, @foo)
|
135
|
+
end
|
136
|
+
|
137
|
+
assert_difference 'Role.count', 1 do
|
138
|
+
@subject2.has_role!(:manager, @foo)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "with two users" do
|
143
|
+
setup do
|
144
|
+
@subject1.has_role!(:admin)
|
145
|
+
@subject2.has_role!(:admin, @foo)
|
146
|
+
@subject1.has_role!(:admin, @bar)
|
147
|
+
end
|
148
|
+
|
149
|
+
should "let objects be able to query their subjects" do
|
150
|
+
assert_same_elements @foo.list_subjects_for(:admin), [@subject1, @subject2]
|
151
|
+
assert_same_elements @foo.list_subjects_all_roles, [@subject1, @subject2]
|
152
|
+
end
|
153
|
+
|
154
|
+
should "dynamically build methods to query" do
|
155
|
+
assert_same_elements @foo.list_subjects_for(:admin), @foo.list_admins
|
156
|
+
end
|
157
|
+
|
158
|
+
should "remove assignments to object roles through has_no_role!" do
|
159
|
+
@subject1.has_no_role!(:admin, @foo)
|
160
|
+
|
161
|
+
assert @subject1.has_role?(:admin)
|
162
|
+
assert @subject1.has_role?(:admin, @bar)
|
163
|
+
assert_false @subject1.has_role?(:admin, @foo)
|
164
|
+
end
|
165
|
+
|
166
|
+
should "only delete roles when they have no assignments" do
|
167
|
+
assert_difference 'Role.count', 0 do
|
168
|
+
@subject2.has_no_role!(:admin, @foo)
|
169
|
+
end
|
170
|
+
|
171
|
+
assert_false @subject2.has_role?(:admin)
|
172
|
+
|
173
|
+
assert_difference 'Role.count', -1 do
|
174
|
+
@subject1.has_no_role!(:admin, @foo)
|
175
|
+
end
|
176
|
+
|
177
|
+
assert_false @subject1.has_role?(:admin, @foo)
|
178
|
+
end
|
179
|
+
|
180
|
+
should "delete all roles for a given object with has_no_roles_for!" do
|
181
|
+
assert_difference 'Role.count', 1 do
|
182
|
+
@subject1.has_role!(:manager, @bar)
|
183
|
+
end
|
184
|
+
|
185
|
+
assert_difference '@subject1.assigned_roles.size', -2 do
|
186
|
+
@subject1.has_no_roles_for!(@bar)
|
187
|
+
end
|
188
|
+
|
189
|
+
assert_false @subject1.has_roles_for?(@bar)
|
190
|
+
assert @subject1.has_role?(:admin)
|
191
|
+
assert @subject1.has_role?(:admin, @foo)
|
192
|
+
end
|
193
|
+
|
194
|
+
should "delete all roles with has_no_roles!" do
|
195
|
+
@subject1.has_no_roles!
|
196
|
+
assert_equal @subject1.assigned_roles.length, 0
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
class RolesTest < ActiveSupport::TestCase
|
207
|
+
context "role testing" do
|
208
|
+
should_handle_basic_role_manipulation(User)
|
209
|
+
should_handle_basic_role_manipulation(Group)
|
210
|
+
should_handle_basic_role_manipulation(UserNoGroup)
|
211
|
+
|
212
|
+
should "models without groups enabled raise errors when group commands are queried" do
|
213
|
+
@usernogroup = UserNoGroup.create!
|
214
|
+
assert_raises RuntimeError do
|
215
|
+
@usernogroup.groups
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
context "group testing: " do
|
220
|
+
setup do
|
221
|
+
@user1 = User.create!
|
222
|
+
@user2 = User.create!
|
223
|
+
@user3 = User.create!
|
224
|
+
@group1 = Group.create!
|
225
|
+
@group2 = Group.create!
|
226
|
+
@group3 = Group.create!
|
227
|
+
@group4 = Group.create!
|
228
|
+
@group5 = Group.create!
|
229
|
+
|
230
|
+
|
231
|
+
@foo = Foo.create!
|
232
|
+
@bar = Bar.create!
|
233
|
+
end
|
234
|
+
|
235
|
+
should "be able to assign users to a group" do
|
236
|
+
@user1.in_group!(@group1)
|
237
|
+
@user2.in_group!(@group1)
|
238
|
+
@user1.in_group!(@group2)
|
239
|
+
|
240
|
+
assert_same_elements @user1.groups, [@group1, @group2]
|
241
|
+
assert_same_elements @group1.children, [@user1, @user2]
|
242
|
+
assert_equal @group2.children, [@user1]
|
243
|
+
|
244
|
+
@user1.not_in_group!(@group1)
|
245
|
+
|
246
|
+
assert_same_elements @user1.groups, [@group2]
|
247
|
+
end
|
248
|
+
|
249
|
+
context "given test users and groups" do
|
250
|
+
setup do
|
251
|
+
@user1.in_group!(@group1)
|
252
|
+
@group1.in_group!(@group2)
|
253
|
+
@group2.in_group!(@group4)
|
254
|
+
|
255
|
+
@user1.in_group!(@group3)
|
256
|
+
@user2.in_group!(@group2)
|
257
|
+
end
|
258
|
+
|
259
|
+
should "avoid circularity" do
|
260
|
+
@group4.in_group!(@group5)
|
261
|
+
|
262
|
+
assert_raises RuntimeError do
|
263
|
+
@group5.in_group!(@group4)
|
264
|
+
end
|
265
|
+
|
266
|
+
assert_raises RuntimeError do
|
267
|
+
@group5.in_group!(@group1)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
should "not follow meaningless member assignments" do
|
272
|
+
@group5.has_role!(:member, @user1)
|
273
|
+
assert_equal @group5.children, []
|
274
|
+
end
|
275
|
+
|
276
|
+
should "handle nested groups" do
|
277
|
+
assert_same_elements @user1.groups(:nested => false), [@group1, @group3]
|
278
|
+
assert_same_elements @user1.groups, [@group1, @group2, @group3, @group4]
|
279
|
+
assert_same_elements @user2.groups, [@group2, @group4]
|
280
|
+
|
281
|
+
assert_same_elements @group4.children, [@group2, @group1, @user1, @user2]
|
282
|
+
assert_same_elements @group2.children, [@group1, @user1, @user2]
|
283
|
+
|
284
|
+
assert @group4.accepts_role?(:member, @user1)
|
285
|
+
assert @group2.accepts_role?(:member, @user1)
|
286
|
+
|
287
|
+
assert_false @group4.accepts_role?(:member, @user1, :check_groups => false)
|
288
|
+
end
|
289
|
+
|
290
|
+
should "check roles based on groups" do
|
291
|
+
|
292
|
+
assert @user2.has_role?(:member, @group2)
|
293
|
+
|
294
|
+
@group2.has_role!(:owner, @foo)
|
295
|
+
|
296
|
+
assert @user2.has_role?(:owner, @foo)
|
297
|
+
assert_false @user2.has_role?(:owner, @foo, :check_groups => false)
|
298
|
+
|
299
|
+
assert @user1.has_role?(:owner, @foo)
|
300
|
+
assert_false @user1.has_role?(:owner, @foo, :check_groups => false)
|
301
|
+
|
302
|
+
|
303
|
+
assert_same_elements @foo.list_owners, [@group2, @group1, @user1, @user2]
|
304
|
+
assert_same_elements @foo.list_owners(:check_groups => false), [@group2]
|
305
|
+
|
306
|
+
assert @foo.accepts_role?(:owner, @user1)
|
307
|
+
assert_false @foo.accepts_role?(:owner, @user1, :check_groups => false)
|
308
|
+
end
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
316
|
+
|
317
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
class Assignment < ActiveRecord::Base
|
3
|
+
acts_as_authorization_assignment
|
4
|
+
end
|
5
|
+
|
6
|
+
class Role < ActiveRecord::Base
|
7
|
+
acts_as_authorization_role
|
8
|
+
end
|
9
|
+
|
10
|
+
class User < ActiveRecord::Base
|
11
|
+
acts_as_authorization_subject
|
12
|
+
end
|
13
|
+
|
14
|
+
class UserNoGroup < ActiveRecord::Base
|
15
|
+
acts_as_authorization_subject :groups_enabled => false, :nested_groups => false
|
16
|
+
end
|
17
|
+
|
18
|
+
class Group < ActiveRecord::Base
|
19
|
+
acts_as_authorization_group
|
20
|
+
end
|
21
|
+
|
22
|
+
class Foo < ActiveRecord::Base
|
23
|
+
acts_as_authorization_object
|
24
|
+
end
|
25
|
+
|
26
|
+
class Bar < ActiveRecord::Base
|
27
|
+
acts_as_authorization_object
|
28
|
+
end
|
29
|
+
|
30
|
+
class Uuid < ActiveRecord::Base
|
31
|
+
set_primary_key "uuid"
|
32
|
+
acts_as_authorization_object
|
33
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
create_table "assignments", :force => true do |t|
|
3
|
+
t.integer "subject_id", :null => false
|
4
|
+
t.string "subject_type", :limit => 20, :null => false
|
5
|
+
t.integer "role_id", :null => false
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table "users", :force => true do |t| end
|
10
|
+
|
11
|
+
create_table "user_no_groups", :force => true do |t| end
|
12
|
+
|
13
|
+
create_table "roles", :force => true do |t|
|
14
|
+
t.string "name", :limit => 50, :null => false
|
15
|
+
t.integer "authorizable_id"
|
16
|
+
t.string "authorizable_type", :limit => 30
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table "groups", :force => true do |t| end
|
21
|
+
|
22
|
+
create_table "foos", :force => true do |t|
|
23
|
+
t.timestamps
|
24
|
+
end
|
25
|
+
|
26
|
+
create_table "bars", :force => true do |t|
|
27
|
+
t.timestamps
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
create_table "uuids", :id => false, :force => true do |t|
|
32
|
+
t.string "uuid"
|
33
|
+
t.timestamps
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'ruby-debug'
|
5
|
+
rescue LoadError
|
6
|
+
puts "ruby-debug not loaded"
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
require 'active_record'
|
11
|
+
require 'active_support'
|
12
|
+
require 'active_support/test_case'
|
13
|
+
|
14
|
+
|
15
|
+
gem 'sqlite3-ruby'
|
16
|
+
gem 'searchlogic'
|
17
|
+
require 'searchlogic'
|
18
|
+
require "shoulda"
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
ROOT = File.join(File.dirname(__FILE__), '..')
|
23
|
+
RAILS_ROOT = ROOT
|
24
|
+
RAILS_ENV = "test"
|
25
|
+
|
26
|
+
|
27
|
+
$LOAD_PATH << File.join(ROOT, 'lib')
|
28
|
+
$LOAD_PATH << File.join(ROOT, 'lib', 'id_please')
|
29
|
+
|
30
|
+
require File.join(ROOT, 'lib', 'id_please.rb')
|
31
|
+
|
32
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
33
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
34
|
+
ActiveRecord::Base.establish_connection(config['test'])
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
module Test::Unit::Assertions
|
40
|
+
def assert_false(object, message="")
|
41
|
+
assert_equal(false, object, message)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: id_please
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Stuart
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-28 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,6 +22,36 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: thoughtbot-factory_girl
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: ruby-debug
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: searchlogic
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
25
55
|
description: Access control gem
|
26
56
|
email: tastyhat@jamesstuart.org
|
27
57
|
executables: []
|
@@ -47,8 +77,6 @@ files:
|
|
47
77
|
- lib/id_please/model_extensions/for_object.rb
|
48
78
|
- lib/id_please/model_extensions/for_subject.rb
|
49
79
|
- lib/id_please/model_extensions/for_user.rb
|
50
|
-
- test/helper.rb
|
51
|
-
- test/test_id_please.rb
|
52
80
|
has_rdoc: true
|
53
81
|
homepage: http://github.com/tastyhat/id_please
|
54
82
|
licenses: []
|
@@ -78,5 +106,8 @@ signing_key:
|
|
78
106
|
specification_version: 3
|
79
107
|
summary: Access control gem for rails
|
80
108
|
test_files:
|
81
|
-
- test/
|
82
|
-
- test/
|
109
|
+
- test/id_please_test.rb
|
110
|
+
- test/roles_test.rb
|
111
|
+
- test/support/models.rb
|
112
|
+
- test/support/schema.rb
|
113
|
+
- test/test_helper.rb
|
data/test/helper.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'test/unit'
|
3
|
-
require 'shoulda'
|
4
|
-
require 'active_record'
|
5
|
-
require 'active_support'
|
6
|
-
|
7
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
8
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
9
|
-
require 'id_please'
|
10
|
-
|
11
|
-
class Test::Unit::TestCase
|
12
|
-
end
|