zuul 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|