zuul 0.1.1 → 0.2.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/lib/generators/zuul/orm_helpers.rb +21 -0
- data/lib/generators/zuul/permission_generator.rb +57 -0
- data/lib/generators/zuul/permission_role_generator.rb +40 -0
- data/lib/generators/zuul/permission_subject_generator.rb +40 -0
- data/lib/generators/zuul/role_generator.rb +58 -0
- data/lib/generators/zuul/role_subject_generator.rb +40 -0
- data/lib/generators/zuul/subject_generator.rb +39 -0
- data/lib/generators/zuul/templates/permission.rb +18 -0
- data/lib/generators/zuul/templates/permission_existing.rb +25 -0
- data/lib/generators/zuul/templates/permission_role.rb +17 -0
- data/lib/generators/zuul/templates/permission_role_existing.rb +24 -0
- data/lib/generators/zuul/templates/permission_subject.rb +17 -0
- data/lib/generators/zuul/templates/permission_subject_existing.rb +24 -0
- data/lib/generators/zuul/templates/role.rb +20 -0
- data/lib/generators/zuul/templates/role_existing.rb +27 -0
- data/lib/generators/zuul/templates/role_subject.rb +17 -0
- data/lib/generators/zuul/templates/role_subject_existing.rb +24 -0
- data/lib/tasks/zuul.rake +56 -0
- data/lib/zuul.rb +14 -5
- data/lib/zuul/action_controller.rb +108 -0
- data/lib/zuul/action_controller/dsl.rb +384 -0
- data/lib/zuul/action_controller/evaluators.rb +60 -0
- data/lib/zuul/active_record.rb +338 -0
- data/lib/zuul/active_record/context.rb +38 -0
- data/lib/zuul/active_record/permission.rb +31 -0
- data/lib/zuul/active_record/permission_role.rb +29 -0
- data/lib/zuul/active_record/permission_subject.rb +29 -0
- data/lib/zuul/active_record/role.rb +117 -0
- data/lib/zuul/active_record/role_subject.rb +29 -0
- data/lib/zuul/active_record/scope.rb +71 -0
- data/lib/zuul/active_record/subject.rb +239 -0
- data/lib/zuul/configuration.rb +149 -0
- data/lib/zuul/context.rb +53 -0
- data/lib/zuul/exceptions.rb +3 -0
- data/lib/zuul/exceptions/access_denied.rb +9 -0
- data/lib/zuul/exceptions/invalid_context.rb +9 -0
- data/lib/zuul/exceptions/undefined_scope.rb +9 -0
- data/lib/zuul/railtie.rb +5 -0
- data/lib/zuul/version.rb +3 -0
- data/lib/zuul_viz.rb +195 -0
- data/spec/db/schema.rb +172 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/capture_stdout.rb +12 -0
- data/spec/support/models.rb +167 -0
- data/spec/zuul/active_record/context_spec.rb +55 -0
- data/spec/zuul/active_record/permission_role_spec.rb +84 -0
- data/spec/zuul/active_record/permission_spec.rb +174 -0
- data/spec/zuul/active_record/permission_subject_spec.rb +84 -0
- data/spec/zuul/active_record/role_spec.rb +694 -0
- data/spec/zuul/active_record/role_subject_spec.rb +84 -0
- data/spec/zuul/active_record/scope_spec.rb +75 -0
- data/spec/zuul/active_record/subject_spec.rb +1186 -0
- data/spec/zuul/active_record_spec.rb +624 -0
- data/spec/zuul/configuration_spec.rb +254 -0
- data/spec/zuul/context_spec.rb +128 -0
- data/spec/zuul_spec.rb +15 -0
- metadata +181 -70
- data/.document +0 -5
- data/.gitignore +0 -23
- data/LICENSE +0 -20
- data/README.rdoc +0 -65
- data/Rakefile +0 -54
- data/VERSION +0 -1
- data/lib/zuul/restrict_access.rb +0 -104
- data/lib/zuul/valid_roles.rb +0 -37
- data/spec/rails_root/app/controllers/application_controller.rb +0 -2
- data/spec/rails_root/app/models/user.rb +0 -8
- data/spec/rails_root/config/boot.rb +0 -110
- data/spec/rails_root/config/database.yml +0 -5
- data/spec/rails_root/config/environment.rb +0 -7
- data/spec/rails_root/config/environments/test.rb +0 -7
- data/spec/rails_root/config/initializers/session_store.rb +0 -15
- data/spec/rails_root/config/routes.rb +0 -4
- data/spec/rails_root/db/test.sqlite3 +0 -0
- data/spec/rails_root/log/test.log +0 -5388
- data/spec/rails_root/spec/controllers/require_user_spec.rb +0 -138
- data/spec/rails_root/spec/controllers/restrict_access_spec.rb +0 -64
- data/spec/rails_root/spec/models/user_spec.rb +0 -37
- data/spec/rails_root/spec/spec_helper.rb +0 -34
- data/zuul.gemspec +0 -78
@@ -0,0 +1,29 @@
|
|
1
|
+
module Zuul
|
2
|
+
module ActiveRecord
|
3
|
+
module PermissionRole
|
4
|
+
def self.included(base)
|
5
|
+
base.send :extend, ClassMethods
|
6
|
+
base.send :include, ContextMethods # defined in lib/zuul/active_record.rb
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def self.extended(base)
|
11
|
+
base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.role_foreign_key.to_sym
|
12
|
+
add_validations base
|
13
|
+
add_associations base
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.add_validations(base)
|
17
|
+
base.send :validates_presence_of, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.role_foreign_key.to_sym
|
18
|
+
base.send :validates_uniqueness_of, base.auth_scope.permission_foreign_key.to_sym, :scope => [base.auth_scope.role_foreign_key.to_sym, :context_id, :context_type], :case_sensitive => false
|
19
|
+
base.send :validates_numericality_of, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.role_foreign_key.to_sym, :only_integer => true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.add_associations(base)
|
23
|
+
base.send :belongs_to, base.auth_scope.permission_class_name.underscore.to_sym
|
24
|
+
base.send :belongs_to, base.auth_scope.role_class_name.underscore.to_sym
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Zuul
|
2
|
+
module ActiveRecord
|
3
|
+
module PermissionSubject
|
4
|
+
def self.included(base)
|
5
|
+
base.send :extend, ClassMethods
|
6
|
+
base.send :include, ContextMethods # defined in lib/zuul/active_record.rb
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def self.extended(base)
|
11
|
+
base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym
|
12
|
+
add_validations base
|
13
|
+
add_associations base
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.add_validations(base)
|
17
|
+
base.send :validates_presence_of, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym
|
18
|
+
base.send :validates_uniqueness_of, base.auth_scope.permission_foreign_key.to_sym, :scope => [base.auth_scope.subject_foreign_key.to_sym, :context_id, :context_type], :case_sensitive => false
|
19
|
+
base.send :validates_numericality_of, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym, :only_integer => true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.add_associations(base)
|
23
|
+
base.send :belongs_to, base.auth_scope.permission_class_name.underscore.to_sym
|
24
|
+
base.send :belongs_to, base.auth_scope.subject_class_name.underscore.to_sym
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Zuul
|
2
|
+
module ActiveRecord
|
3
|
+
module Role
|
4
|
+
def self.included(base)
|
5
|
+
base.send :extend, ClassMethods
|
6
|
+
base.send :include, ContextMethods # defined in lib/zuul/active_record.rb
|
7
|
+
base.send :include, PermissionMethods if base.auth_scope.config.with_permissions
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def self.extended(base)
|
12
|
+
base.send :attr_accessible, :context_id, :context_type, :level, :slug
|
13
|
+
add_validations base
|
14
|
+
add_associations base
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.add_validations(base)
|
18
|
+
base.send :validates_presence_of, :level, :slug
|
19
|
+
base.send :validates_uniqueness_of, :slug, :scope => [:context_id, :context_type], :case_sensitive => false
|
20
|
+
base.send :validates_format_of, :slug, :with => /\A[a-z0-9_]+\Z/
|
21
|
+
base.send :validates_uniqueness_of, :level, :scope => [:context_id, :context_type]
|
22
|
+
base.send :validates_numericality_of, :level, :only_integer => true
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.add_associations(base)
|
26
|
+
base.send :has_many, base.auth_scope.role_subjects_table_name.to_sym
|
27
|
+
base.send :has_many, base.auth_scope.subjects_table_name.to_sym, :through => base.auth_scope.role_subjects_table_name.to_sym
|
28
|
+
if base.auth_scope.config.with_permissions
|
29
|
+
base.send :has_many, base.auth_scope.permission_roles_table_name.to_sym
|
30
|
+
base.send :has_many, base.auth_scope.permissions_table_name.to_sym, :through => base.auth_scope.permission_roles_table_name.to_sym
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module PermissionMethods
|
36
|
+
# Assigns a permission to a role within the provided context.
|
37
|
+
#
|
38
|
+
# If a Permission object is provided it's used directly, otherwise if a
|
39
|
+
# permission slug is provided, the permission is looked up in the context
|
40
|
+
# chain by target_permission.
|
41
|
+
def assign_permission(permission, context=nil, force_context=nil)
|
42
|
+
auth_scope do
|
43
|
+
context = Zuul::Context.parse(context)
|
44
|
+
target = target_permission(permission, context, force_context)
|
45
|
+
return false unless verify_target_context(target, context, force_context) && verify_target_context(self, context, false) && permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first.nil?
|
46
|
+
|
47
|
+
return permission_role_class.create(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Removes a permission from a role within the provided context.
|
52
|
+
#
|
53
|
+
# If a Permission object is provided it's used directly, otherwise if a
|
54
|
+
# permission slug is provided, the permission is looked up in the context
|
55
|
+
# chain by target_permission.
|
56
|
+
def unassign_permission(permission, context=nil, force_context=nil)
|
57
|
+
auth_scope do
|
58
|
+
context = Zuul::Context.parse(context)
|
59
|
+
target = target_permission(permission, context, force_context)
|
60
|
+
return false if target.nil?
|
61
|
+
|
62
|
+
assigned_permission = permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first
|
63
|
+
return false if assigned_permission.nil?
|
64
|
+
return assigned_permission.destroy
|
65
|
+
end
|
66
|
+
end
|
67
|
+
alias_method :remove_permission, :unassign_permission
|
68
|
+
|
69
|
+
# Checks whether a role has a permission within the provided context.
|
70
|
+
#
|
71
|
+
# If a Permission object is provided it's used directly, otherwise if a
|
72
|
+
# permission slug is provided, the permission is looked up in the context
|
73
|
+
# chain by target_permission.
|
74
|
+
#
|
75
|
+
# The assigned context behaves the same way, in that if the permission is not found
|
76
|
+
# to belong to the role with the specified context, we look up the context chain.
|
77
|
+
#
|
78
|
+
# TODO add options to force context, not go up the chain
|
79
|
+
def has_permission?(permission, context=nil, force_context=nil)
|
80
|
+
auth_scope do
|
81
|
+
force_context ||= config.force_context
|
82
|
+
context = Zuul::Context.parse(context)
|
83
|
+
target = target_permission(permission, context, force_context)
|
84
|
+
return false if target.nil?
|
85
|
+
|
86
|
+
return true unless (context.id.nil? && !force_context) || permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
|
87
|
+
unless force_context
|
88
|
+
return true unless context.class_name.nil? || permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
|
89
|
+
return !permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
alias_method :permission?, :has_permission?
|
94
|
+
alias_method :can?, :has_permission?
|
95
|
+
alias_method :allowed_to?, :has_permission?
|
96
|
+
|
97
|
+
# Returns all permissions possessed by the role within the provided context.
|
98
|
+
def permissions_for(context=nil, force_context=nil)
|
99
|
+
auth_scope do
|
100
|
+
force_context ||= config.force_context
|
101
|
+
context = Zuul::Context.parse(context)
|
102
|
+
if force_context
|
103
|
+
return permission_class.joins(permission_roles_table_name.to_sym).where(permission_roles_table_name.to_sym => {role_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => context.id})
|
104
|
+
else
|
105
|
+
return permission_class.joins("LEFT JOIN #{permission_roles_table_name} ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id").where("#{permission_roles_table_name}.#{role_foreign_key} = ? AND (#{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{permission_roles_table_name}.context_type IS NULL) AND (#{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{permission_roles_table_name}.context_id IS NULL)", id, context.class_name, context.id)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Check whether the role possesses any permissions within the specified context.
|
111
|
+
def permissions_for?(context=nil, force_context=nil)
|
112
|
+
permissions_for(context, force_context).count > 0
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Zuul
|
2
|
+
module ActiveRecord
|
3
|
+
module RoleSubject
|
4
|
+
def self.included(base)
|
5
|
+
base.send :extend, ClassMethods
|
6
|
+
base.send :include, ContextMethods # defined in lib/zuul/active_record.rb
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def self.extended(base)
|
11
|
+
base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.role_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym
|
12
|
+
add_validations base
|
13
|
+
add_associations base
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.add_validations(base)
|
17
|
+
base.send :validates_presence_of, base.auth_scope.role_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym
|
18
|
+
base.send :validates_uniqueness_of, base.auth_scope.role_foreign_key.to_sym, :scope => [base.auth_scope.subject_foreign_key.to_sym, :context_id, :context_type], :case_sensitive => false
|
19
|
+
base.send :validates_numericality_of, base.auth_scope.role_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym, :only_integer => true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.add_associations(base)
|
23
|
+
base.send :belongs_to, base.auth_scope.role_class_name.underscore.to_sym
|
24
|
+
base.send :belongs_to, base.auth_scope.subject_class_name.underscore.to_sym
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Zuul
|
2
|
+
module ActiveRecord
|
3
|
+
class Scope
|
4
|
+
attr_reader :config, :name
|
5
|
+
|
6
|
+
protected
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
@name = @config.scope
|
11
|
+
define_reflection_methods
|
12
|
+
super()
|
13
|
+
end
|
14
|
+
|
15
|
+
# Define dynamic reflection methods that reference the config to be used for subjects, roles, permissions and their associations.
|
16
|
+
def define_reflection_methods
|
17
|
+
# *_class_name, *_class, *_table_name methods for all classes
|
18
|
+
@config.classes.to_h.each do |class_type,class_name|
|
19
|
+
class_type_name = class_type.to_s.gsub(/_class$/,'').singularize
|
20
|
+
class_eval do
|
21
|
+
# def CLASS_TYPE_class_name
|
22
|
+
define_method "#{class_type_name}_class_name" do
|
23
|
+
if @config.send(class_type).is_a?(Class)
|
24
|
+
@config.send(class_type).name
|
25
|
+
else
|
26
|
+
@config.send(class_type).to_s.camelize
|
27
|
+
end
|
28
|
+
end
|
29
|
+
alias_method "#{class_type_name.pluralize}_class_name", "#{class_type_name}_class_name"
|
30
|
+
|
31
|
+
# def CLASS_TYPE_class
|
32
|
+
define_method "#{class_type_name}_class" do
|
33
|
+
"::#{send("#{class_type_name}_class_name")}".constantize
|
34
|
+
end
|
35
|
+
alias_method "#{class_type_name.pluralize}_class", "#{class_type_name}_class"
|
36
|
+
|
37
|
+
# def CLASS_TYPE_table_name
|
38
|
+
define_method "#{class_type_name}_table_name" do
|
39
|
+
send("#{class_type_name}_class").table_name
|
40
|
+
end
|
41
|
+
alias_method "#{class_type_name.pluralize}_table_name", "#{class_type_name}_table_name"
|
42
|
+
|
43
|
+
unless class_type.to_s.underscore == "#{class_name.to_s.underscore}_class"
|
44
|
+
["_class_name", "_class", "_table_name"].each do |suffix|
|
45
|
+
alias_method "#{class_name.to_s.underscore.singularize}#{suffix}", "#{class_type_name}#{suffix}"
|
46
|
+
alias_method "#{class_name.to_s.underscore.pluralize}#{suffix}", "#{class_name.to_s.underscore.singularize}#{suffix}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# *_foreign_key method for primary classes
|
53
|
+
@config.primary_classes.to_h.each do |class_type,class_name|
|
54
|
+
class_type_name = class_type.to_s.gsub(/_class$/,'').singularize
|
55
|
+
class_eval do
|
56
|
+
# def CLASS_TYPE_foreign_key
|
57
|
+
define_method "#{class_type_name}_foreign_key" do
|
58
|
+
"#{send("#{class_type_name}_table_name").singularize}_#{send("#{class_type_name}_class").primary_key}"
|
59
|
+
end
|
60
|
+
alias_method "#{class_type.to_s.gsub(/_class$/,"").pluralize}_foreign_key", "#{class_type.to_s.gsub(/_class$/,"").singularize}_foreign_key"
|
61
|
+
|
62
|
+
unless class_type.to_s.underscore == "#{class_name.to_s.underscore}_class"
|
63
|
+
alias_method "#{class_name.to_s.underscore.singularize}_foreign_key", "#{class_type.to_s.gsub(/_class$/,"").singularize}_foreign_key" # CLASS_NAME_foreign_key
|
64
|
+
alias_method "#{class_name.to_s.underscore.pluralize}_foreign_key", "#{class_name.to_s.underscore.singularize}_foreign_key"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
module Zuul
|
2
|
+
module ActiveRecord
|
3
|
+
module Subject
|
4
|
+
def self.included(base)
|
5
|
+
base.send :include, RoleMethods
|
6
|
+
base.send(:include, PermissionMethods) if base.auth_scope.config.with_permissions
|
7
|
+
end
|
8
|
+
|
9
|
+
module RoleMethods
|
10
|
+
def self.included(base)
|
11
|
+
base.send :extend, ClassMethods
|
12
|
+
base.send :include, InstanceMethods
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def self.extended(base)
|
17
|
+
base.send :has_many, base.auth_scope.role_subjects_table_name.to_sym
|
18
|
+
base.send :has_many, base.auth_scope.roles_table_name.to_sym, :through => base.auth_scope.role_subjects_table_name.to_sym
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module InstanceMethods
|
23
|
+
# Assigns a role to a subject within the provided context.
|
24
|
+
#
|
25
|
+
# If a Role object is provided it's used directly, otherwise if a role slug
|
26
|
+
# is provided, the role is looked up in the context chain by target_role.
|
27
|
+
def assign_role(role, context=nil, force_context=nil)
|
28
|
+
auth_scope do
|
29
|
+
context = Zuul::Context.parse(context)
|
30
|
+
target = target_role(role, context, force_context)
|
31
|
+
return false unless verify_target_context(target, context, force_context) && role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first.nil?
|
32
|
+
|
33
|
+
return role_subject_class.create(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Removes a role from a subject within the provided context.
|
38
|
+
#
|
39
|
+
# If a Role object is provided it's used directly, otherwise if a role slug
|
40
|
+
# is provided, the role is looked up in the context chain by target_role.
|
41
|
+
def unassign_role(role, context=nil, force_context=nil)
|
42
|
+
auth_scope do
|
43
|
+
context = Zuul::Context.parse(context)
|
44
|
+
target = target_role(role, context, force_context)
|
45
|
+
return false if target.nil?
|
46
|
+
|
47
|
+
assigned_role = role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first
|
48
|
+
return false if assigned_role.nil?
|
49
|
+
return assigned_role.destroy
|
50
|
+
end
|
51
|
+
end
|
52
|
+
alias_method :remove_role, :unassign_role
|
53
|
+
|
54
|
+
# Checks whether a subject has a role within the provided context.
|
55
|
+
#
|
56
|
+
# If a Role object is provided it's used directly, otherwise if a role slug
|
57
|
+
# is provided, the role is looked up in the context chain by target_role.
|
58
|
+
#
|
59
|
+
# The assigned context behaves the same way, in that if the role is not found
|
60
|
+
# to belong to the subject with the specified context, we look up the context chain.
|
61
|
+
def has_role?(role, context=nil, force_context=nil)
|
62
|
+
auth_scope do
|
63
|
+
force_context ||= config.force_context
|
64
|
+
context = Zuul::Context.parse(context)
|
65
|
+
target = target_role(role, context, force_context)
|
66
|
+
return false if target.nil?
|
67
|
+
|
68
|
+
return true unless (context.id.nil? && !force_context) || role_subject_class.joins(role_class_name.underscore.to_sym).where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
|
69
|
+
return false if force_context
|
70
|
+
return true unless context.class_name.nil? || role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
|
71
|
+
return !role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
alias_method :role?, :has_role?
|
75
|
+
|
76
|
+
# Checks whether a subject has the specified role or a role with a level greather than
|
77
|
+
# that of the specified role, within the provided context.
|
78
|
+
#
|
79
|
+
# If a Role object is provided it's used directly, otherwise if a role slug
|
80
|
+
# is provided, the role is looked up in the context chain by target_role.
|
81
|
+
#
|
82
|
+
# The assigned context behaves the same way, in that if a matching role is not found
|
83
|
+
# to belong to the subject with the specified context, we look up the context chain.
|
84
|
+
def has_role_or_higher?(role, context=nil, force_context=nil)
|
85
|
+
auth_scope do
|
86
|
+
context = Zuul::Context.parse(context)
|
87
|
+
target = target_role(role, context, force_context)
|
88
|
+
return false if target.nil?
|
89
|
+
|
90
|
+
return true if has_role?(target, context, force_context)
|
91
|
+
|
92
|
+
return true unless context.id.nil? || role_subject_class.joins(role_class_name.underscore.to_sym).where(subject_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => context.id).where("#{roles_table_name}.level >= ? AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ? AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?", target.level, target.context_type, target.context_id).first.nil?
|
93
|
+
return true unless context.class_name.nil? || role_subject_class.joins(role_class_name.underscore.to_sym).where(subject_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => nil).where("#{roles_table_name}.level >= ? AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ? AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?", target.level, target.context_type, target.context_id).first.nil?
|
94
|
+
return !role_subject_class.joins(role_class_name.underscore.to_sym).where(subject_foreign_key.to_sym => id, :context_type => nil, :context_id => nil).where("#{roles_table_name}.level >= ? AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ? AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?", target.level, target.context_type, target.context_id).first.nil?
|
95
|
+
end
|
96
|
+
end
|
97
|
+
alias_method :role_or_higher?, :has_role_or_higher?
|
98
|
+
alias_method :at_least_role?, :has_role_or_higher?
|
99
|
+
|
100
|
+
# Returns the highest level role a subject possesses within the provided context.
|
101
|
+
#
|
102
|
+
# This includes any roles found by looking up the context chain.
|
103
|
+
def highest_role(context=nil, force_context=nil)
|
104
|
+
return nil unless roles_for?(context, force_context)
|
105
|
+
roles_for(context, force_context).order(:level).reverse_order.limit(1).first
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns all roles possessed by the subject within the provided context.
|
109
|
+
#
|
110
|
+
# This includes all roles found by looking up the context chain.
|
111
|
+
def roles_for(context=nil, force_context=nil)
|
112
|
+
auth_scope do
|
113
|
+
force_context ||= config.force_context
|
114
|
+
context = Zuul::Context.parse(context)
|
115
|
+
if force_context
|
116
|
+
return role_class.joins(role_subjects_table_name.to_sym).where("#{role_subjects_table_name}.#{subject_foreign_key} = ? AND #{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?", id, context.class_name, context.id)
|
117
|
+
else
|
118
|
+
return role_class.joins(role_subjects_table_name.to_sym).where("#{role_subjects_table_name}.#{subject_foreign_key} = ? AND ((#{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{role_subjects_table_name}.context_type IS NULL) AND (#{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{role_subjects_table_name}.context_id IS NULL))", id, context.class_name, context.id)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Check whether the subject possesses any roles within the specified context.
|
124
|
+
#
|
125
|
+
# This includes any roles found by looking up the context chain.
|
126
|
+
def roles_for?(context=nil, force_context=nil)
|
127
|
+
roles_for(context, force_context).count > 0
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
module PermissionMethods
|
133
|
+
def self.included(base)
|
134
|
+
base.send :extend, ClassMethods
|
135
|
+
base.send :include, InstanceMethods
|
136
|
+
end
|
137
|
+
|
138
|
+
module ClassMethods
|
139
|
+
def self.extended(base)
|
140
|
+
base.send :has_many, base.auth_scope.permission_subjects_table_name.to_sym
|
141
|
+
base.send :has_many, base.auth_scope.permissions_table_name.to_sym, :through => base.auth_scope.permission_subjects_table_name.to_sym
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
module InstanceMethods
|
146
|
+
# Assigns a permission to a subject within the provided context.
|
147
|
+
#
|
148
|
+
# If a Permission object is provided it's used directly, otherwise if a
|
149
|
+
# permission slug is provided, the permission is looked up in the context
|
150
|
+
# chain by target_permission.
|
151
|
+
def assign_permission(permission, context=nil, force_context=nil)
|
152
|
+
auth_scope do
|
153
|
+
context = Zuul::Context.parse(context)
|
154
|
+
target = target_permission(permission, context, force_context)
|
155
|
+
return false unless verify_target_context(target, context, force_context) && permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first.nil?
|
156
|
+
|
157
|
+
return permission_subject_class.create(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Removes a permission from a subject within the provided context.
|
162
|
+
#
|
163
|
+
# If a Permission object is provided it's used directly, otherwise if a
|
164
|
+
# permission slug is provided, the permission is looked up in the context
|
165
|
+
# chain by target_permission.
|
166
|
+
def unassign_permission(permission, context=nil, force_context=nil)
|
167
|
+
auth_scope do
|
168
|
+
context = Zuul::Context.parse(context)
|
169
|
+
target = target_permission(permission, context, force_context)
|
170
|
+
return false if target.nil?
|
171
|
+
|
172
|
+
assigned_permission = permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first
|
173
|
+
return false if assigned_permission.nil?
|
174
|
+
return assigned_permission.destroy
|
175
|
+
end
|
176
|
+
end
|
177
|
+
alias_method :remove_permission, :unassign_permission
|
178
|
+
|
179
|
+
# Checks whether a subject has a permission within the provided context.
|
180
|
+
#
|
181
|
+
# If a Permission object is provided it's used directly, otherwise if a
|
182
|
+
# permission slug is provided, the permission is looked up in the context
|
183
|
+
# chain by target_permission.
|
184
|
+
#
|
185
|
+
# The assigned context behaves the same way, in that if the permission is not found
|
186
|
+
# to belong to the subject with the specified context, we look up the context chain.
|
187
|
+
#
|
188
|
+
# Permissions belonging to roles possessed by the subject are also included.
|
189
|
+
def has_permission?(permission, context=nil, force_context=nil)
|
190
|
+
auth_scope do
|
191
|
+
force_context ||= config.force_context
|
192
|
+
context = Zuul::Context.parse(context)
|
193
|
+
target = target_permission(permission, context, force_context)
|
194
|
+
return false if target.nil?
|
195
|
+
|
196
|
+
return true unless (context.id.nil? && !force_context) || permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
|
197
|
+
unless force_context
|
198
|
+
return true unless context.class_name.nil? || permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
|
199
|
+
return true unless permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
|
200
|
+
end
|
201
|
+
|
202
|
+
return true unless (context.id.nil? && !force_context) || permission_role_class.where(role_foreign_key.to_sym => roles_for(context).map(&:id), permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
|
203
|
+
return false if force_context
|
204
|
+
return true unless context.class_name.nil? || permission_role_class.where(role_foreign_key.to_sym => roles_for(context).map(&:id), permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
|
205
|
+
return !permission_role_class.where(role_foreign_key.to_sym => roles_for(context).map(&:id), permission_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
|
206
|
+
end
|
207
|
+
end
|
208
|
+
alias_method :permission?, :has_permission?
|
209
|
+
alias_method :can?, :has_permission?
|
210
|
+
alias_method :allowed_to?, :has_permission?
|
211
|
+
|
212
|
+
# Returns all permissions possessed by the subject within the provided context.
|
213
|
+
#
|
214
|
+
# This includes permissions assigned directly to the subject or any roles possessed by
|
215
|
+
# the subject, as well as all permissions found by looking up the context chain.
|
216
|
+
def permissions_for(context=nil, force_context=nil)
|
217
|
+
auth_scope do
|
218
|
+
force_context ||= config.force_context
|
219
|
+
context = Zuul::Context.parse(context)
|
220
|
+
if force_context
|
221
|
+
return permission_class.joins("LEFT JOIN #{permission_roles_table_name} ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id LEFT JOIN #{permission_subjects_table_name} ON #{permission_subjects_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id").where("(#{permission_subjects_table_name}.#{subject_foreign_key} = ? AND #{permission_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{permission_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?) OR (#{permission_roles_table_name}.#{role_foreign_key} IN (?) AND #{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ?)", id, context.class_name, context.id, roles_for(context).map(&:id), context.class_name, context.id)
|
222
|
+
else
|
223
|
+
return permission_class.joins("LEFT JOIN #{permission_roles_table_name} ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id LEFT JOIN #{permission_subjects_table_name} ON #{permission_subjects_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id").where("(#{permission_subjects_table_name}.#{subject_foreign_key} = ? AND (#{permission_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{permission_subjects_table_name}.context_type IS NULL) AND (#{permission_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{permission_subjects_table_name}.context_id IS NULL)) OR (#{permission_roles_table_name}.#{role_foreign_key} IN (?) AND (#{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{permission_roles_table_name}.context_type IS NULL) AND (#{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{permission_roles_table_name}.context_id IS NULL))", id, context.class_name, context.id, roles_for(context).map(&:id), context.class_name, context.id)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Check whether the subject possesses any permissions within the specified context.
|
229
|
+
#
|
230
|
+
# This includes permissions assigned directly to the subject or any roles possessed by
|
231
|
+
# the subject, as well as all permissions found by looking up the context chain.
|
232
|
+
def permissions_for?(context=nil, force_context=nil)
|
233
|
+
permissions_for(context, force_context).count > 0
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|