role_authorization 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gemtest ADDED
@@ -0,0 +1 @@
1
+
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.gem
2
+
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2@gems
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 John "asceth" Long
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,8 @@
1
+ Features
2
+ --------
3
+
4
+ Requirements
5
+ ------------
6
+
7
+ Usage
8
+ -----
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require "bundler"
2
+ Bundler.setup
3
+
4
+ require "rspec"
5
+ require "rspec/core/rake_task"
6
+
7
+ Rspec::Core::RakeTask.new(:spec)
8
+
9
+ gemspec = eval(File.read(File.join(Dir.pwd, "role_authorization.gemspec")))
10
+
11
+ task :build => "#{gemspec.full_name}.gem"
12
+
13
+ task :test => :spec
14
+
15
+ file "#{gemspec.full_name}.gem" => gemspec.files + ["role_authorization.gemspec"] do
16
+ system "gem build role_authorization.gemspec"
17
+ system "gem install role_authorization-#{RoleAuthorization::VERSION}.gem"
18
+ end
19
+
@@ -0,0 +1,8 @@
1
+ module RoleAuthorization
2
+ class Railtie < Rails::Railtie
3
+ initializer "role_authorization.initialize" do |app|
4
+ RoleAuthorization.enable
5
+ RoleAuthorization.load_controller_classes
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ module RoleAuthorization
2
+ module AllowGroup
3
+ include RoleAuthorization::Ruleset
4
+ cattr_ruleset :ruleset
5
+
6
+ class << self
7
+ def define(name, &block)
8
+ add_to_ruleset(name, &block)
9
+ end
10
+
11
+ def get(*names)
12
+ ruleset.values_at(names).compact
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,116 @@
1
+ module RoleAuthorization
2
+ class << self
3
+ # shortcut for <tt>enable_actionpack; enable_activerecord</tt>
4
+ def enable
5
+ # load rule mapper
6
+ load 'role_authorization/mapper.rb'
7
+ load 'role_authorization/ruleset.rb'
8
+ load 'role_authorization/allow_group.rb'
9
+ load 'role_authorization/rules/basic.rb'
10
+
11
+ # load default rules
12
+ Dir.chdir(File.dirname(__FILE__)) do
13
+ Dir["rules/*.rb"].each do |rule_definition|
14
+ require "#{File.dirname(__FILE__)}/#{rule_definition}"
15
+ end
16
+ end
17
+
18
+ # load application rules
19
+ Dir.chdir(Rails.root) do
20
+ Dir["lib/rules/*.rb"].each do |rule_definition|
21
+ require "#{Rails.root}/#{rule_definition}"
22
+ end
23
+ end
24
+
25
+ # load allow groups
26
+ Dir.chdir(Rails.root) do
27
+ Dir["lib/allow_groups/*.rb"].each do |allow_group|
28
+ require "#{Rails.root}/#{allow_group}"
29
+ end
30
+ end
31
+
32
+ enable_actionpack
33
+ enable_activerecord
34
+ end
35
+
36
+ def enable_actionpack
37
+ load 'role_authorization/exts/view.rb'
38
+ unless ActionView::Base.instance_methods.include? :link_to_or_show
39
+ ActionView::Base.class_eval { include Exts::View }
40
+ end
41
+
42
+ load 'role_authorization/exts/session.rb'
43
+ load 'role_authorization/exts/controller.rb'
44
+ unless ActionController::Base.instance_methods.include? :authorized?
45
+ ActionController::Base.class_eval { include Exts::Session }
46
+ ActionController::Base.class_eval { include Exts::Controller }
47
+ end
48
+ end
49
+
50
+ def enable_activerecord
51
+ load 'role_authorization/exts/model.rb'
52
+ unless ActiveRecord::Base.instance_methods.include? :roleable
53
+ ActiveRecord::Base.class_eval { include Exts::Model }
54
+ end
55
+
56
+ load 'role_authorization/exts/user.rb'
57
+ end
58
+
59
+ def load_controller_classes
60
+ @controller_classes = {}
61
+
62
+ maybe_load_framework_controller_parent
63
+
64
+ Dir.chdir("#{Rails.root}/app/controllers") do
65
+ Dir["**/*.rb"].sort.each do |c|
66
+ next if c.include?("application")
67
+ rola_load(c)
68
+ end
69
+ end
70
+
71
+ # if ENV['RAILS_ENV'] != 'production'
72
+ # if ActiveSupport.const_defined?("Dependencies")
73
+ # ActiveSupport::Dependencies.clear
74
+ # else
75
+ # Dependencies.clear
76
+ # end
77
+ # end
78
+ end
79
+
80
+ def maybe_load_framework_controller_parent
81
+ if ::Rails::VERSION::MAJOR >= 3 || (::Rails::VERSION::MAJOR >= 2 && ::Rails::VERSION::MINOR >= 3)
82
+ filename = "application_controller.rb"
83
+ else
84
+ filename = "application.rb"
85
+ end
86
+ require_or_load(filename)
87
+ end
88
+
89
+ def rola_load(filename)
90
+ klass = class_name_from_file(filename)
91
+ require_or_load(filename)
92
+ @controller_classes[klass] = qualified_const_get(klass)
93
+ end
94
+
95
+ def require_or_load(filename)
96
+ if ActiveSupport.const_defined?("Dependencies")
97
+ ActiveSupport::Dependencies.require_or_load(filename)
98
+ else
99
+ Dependencies.require_or_load(filename)
100
+ end
101
+ end
102
+
103
+ def class_name_from_file(str)
104
+ str.split(".")[0].split("/").collect{|s| s.camelize }.join("::")
105
+ end
106
+
107
+ def qualified_const_get(klass)
108
+ if klass =~ /::/
109
+ namespace, klass = klass.split("::")
110
+ eval(namespace).const_get(klass)
111
+ else
112
+ const_get(klass)
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,127 @@
1
+ module RoleAuthorization
2
+ module Exts
3
+ module Controller
4
+ def self.included(base)
5
+ base.class_eval do
6
+ rescue_from SecurityError, :with => proc {|e| access_denied(e)}
7
+ helper_method :authorized?
8
+ helper_method :accessible?
9
+ end
10
+ base.send :extend, RoleAuthorization::Ruleset::ClassMethods
11
+ base.send :cattr_ruleset, :ruleset, :allowable_groups
12
+ base.send :extend, ClassMethods
13
+
14
+ base.send :include, InstanceMethods
15
+ end
16
+
17
+ module ClassMethods
18
+ def allow_group(*args)
19
+ add_to_allowable_groups(self.controller_rule_name, args)
20
+ add_role_authorization_filter
21
+ end
22
+
23
+ def allow(&block)
24
+ add_to_ruleset(self.controller_rule_name, &block)
25
+ add_role_authorization_filter
26
+ end
27
+
28
+ def add_role_authorization_filter
29
+ callbacks = _process_action_callbacks
30
+ chain = callbacks.select {|cl| cl.klass.to_s.include?(name)}.collect(&:filter).select {|c| c.is_a?(Symbol)}
31
+ before_filter :check_request_authorization unless chain.include?(:check_request_authorization)
32
+ end
33
+
34
+ def controller_rule_name
35
+ @controller_rule_name ||= name.gsub('Controller', '').underscore.downcase
36
+ end
37
+
38
+ def controller_model
39
+ @controller_model ||= name.gsub('Controller', '').singularize
40
+ end
41
+ end # ClassMethods
42
+
43
+ module InstanceMethods
44
+ def check_request_authorization
45
+ unless authorized_action?(self, self.class.controller_rule_name, action_name.to_sym, params[:id])
46
+ raise SecurityError, "You do not have the required clearance to access this resource."
47
+ end
48
+ end
49
+
50
+ def authorized_action?(controller_klass, controller, action, id = nil)
51
+ # by default admins see everything
52
+ return true if current_user_is_admin?
53
+
54
+ ruleset = self.class.ruleset[controller]
55
+ groups = RoleAuthorization::AllowGroup.get(self.class.allowable_groups[controller])
56
+
57
+ if defined?(DEBUG_AUTHORIZATION_RULES) == 'constant'
58
+ Rails.logger.info "#" * 60
59
+ Rails.logger.info ruleset.to_s
60
+ Rails.logger.info "#" * 60
61
+ end
62
+
63
+ # we have no ruleset for this controller or any allow groups so deny
64
+ return false if ruleset.nil? && groups.empty?
65
+
66
+ # first check controller ruleset
67
+ unless ruleset.nil?
68
+ return true if ruleset.authorized?(controller_klass, controller, :all, id)
69
+ return true if ruleset.authorized?(controller_klass, controller, action, id)
70
+ end
71
+
72
+ # next check any allow groups
73
+ unless groups.empty?
74
+ groups.each do |group|
75
+ return true if group.authorized?(controller_klass, controller, :all, id)
76
+ return true if group.authorized?(controller_klass, controller, action, id)
77
+ end
78
+ end
79
+
80
+ # finally deny if they haven't passed any rules
81
+ return false
82
+ end
83
+
84
+ def accessible?(access_role)
85
+ return true if current_user_is_admin?
86
+ return false if access_role.nil?
87
+ return true if access_role.name.to_sym == :public
88
+ return false if session[:access_rights].nil?
89
+ session[:access_rights].include?(access_role.name.to_sym)
90
+ end
91
+
92
+ def authorized?(url, method = nil)
93
+ return false unless url
94
+ return true if current_user_is_admin?
95
+
96
+ method ||= (params[:method] || request.method)
97
+ url_parts = URI::split(url.strip)
98
+ path = url_parts[5]
99
+
100
+ begin
101
+ hash = Rails.application.routes.recognize_path(path, :method => method)
102
+ return authorized_action?(self, hash[:controller], hash[:action].to_sym, hash[:id]) if hash
103
+ rescue Exception => e
104
+ Rails.logger.error e.inspect
105
+ Rails.logger.error e.backtrace
106
+ # continue on
107
+ end
108
+
109
+ # Mailto link
110
+ return true if url =~ /^mailto:/
111
+
112
+ # Public file
113
+ file = File.join(RAILS_ROOT, 'public', url)
114
+ return true if File.exists?(file)
115
+
116
+ # Passing in different domain
117
+ return remote_url?(url_parts[2])
118
+ end
119
+
120
+ def remote_url?(domain = nil)
121
+ return false if domain.nil? || domain.strip.length == 0
122
+ request.host.downcase != domain.downcase
123
+ end
124
+ end # InstanceMethods
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,126 @@
1
+ module RoleAuthorization
2
+ module Exts
3
+ module Model
4
+ def self.included(base)
5
+ base.send :extend, ClassMethods
6
+ base.send :include, InstanceMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def roleable_options
11
+ @roleable_options
12
+ end
13
+
14
+ def roleable_options=(options)
15
+ @roleable_options = options
16
+ end
17
+
18
+ def roleable options = {}
19
+ has_many :roles, :as => :roleable, :dependent => :delete_all
20
+ after_create :create_roles
21
+
22
+ send(:extend, SpecificClassMethods)
23
+
24
+ options[:name] ||= :class
25
+
26
+ options[:priority] ||= {}
27
+ options[:creation_priority] ||= {}
28
+ options[:roles] ||= [:default]
29
+ options[:roles].each do |role_name|
30
+ options[:priority][role_name] ||= 1
31
+ options[:creation_priority][role_name] ||= 1
32
+ end
33
+
34
+ options[:cache] = {}
35
+ @roleable_options = options
36
+ end # roleable
37
+
38
+ def enrolled(role_name)
39
+ roles = Role.all(:conditions => {:roleable_type => self.to_s, :name => role_name.to_s})
40
+ unless roles.empty?
41
+ roles.collect(&:users).flatten
42
+ else
43
+ []
44
+ end
45
+ end
46
+ end # ClassMethods
47
+
48
+ module SpecificClassMethods
49
+ def reset_roles
50
+ all.map(&:reset_roles)
51
+ end
52
+ end
53
+
54
+ module InstanceMethods
55
+
56
+ def reset_roles
57
+ options = self.class.roleable_options
58
+
59
+ mroles = roles.all
60
+ rejected_roles = mroles.reject {|r| options[:roles].include?(r.name.to_sym)}
61
+ rejected_roles.map {|rejected_role| rejected_role.destroy}
62
+
63
+ valid_roles = mroles - rejected_roles
64
+ valid_role_names = valid_roles.collect(&:name)
65
+ new_roles = options[:roles].select {|role| !valid_role_names.include?(role.to_sym)}
66
+ valid_roles.each do |role|
67
+ if roles.find_by_name(role.name.to_s).nil?
68
+ roles.create(:name => role.name.to_s,
69
+ :display_name => "#{self.send(options[:name])} #{role.name.to_s}",
70
+ :creation_priority => options[:creation_priority][role.name.to_s],
71
+ :priority => options[:priority][role.name.to_s])
72
+ end
73
+ end
74
+ new_roles.each do |role|
75
+ roles.create(:name => role.to_s,
76
+ :display_name => "#{self.send(options[:name])} #{role.to_s}",
77
+ :creation_priority => options[:creation_priority][role],
78
+ :priority => options[:priority][role])
79
+ end
80
+ roles(true).all
81
+ end
82
+
83
+ def enroll(user, role)
84
+ options = self.class.roleable_options
85
+ role = role.is_a?(Integer) ? roles.find_by_id(role) : roles.find_by_name(role.to_s)
86
+ user_id = ((user.is_a?(Integer) || user.is_a?(String)) ? user.to_i : user.id)
87
+ unless role.nil?
88
+ role.user_roles.create(:user_id => user_id)
89
+ end
90
+ end
91
+ alias_method :assign, :enroll
92
+
93
+ def enrolled(role)
94
+ role = roles.find_by_name(role.to_s)
95
+ unless role.nil?
96
+ role.users
97
+ else
98
+ []
99
+ end
100
+ end
101
+
102
+ def withdraw(user, role = nil)
103
+ options = self.class.roleable_options
104
+ role = role.is_a?(Integer) ? roles.find_by_id(role, :include => :user_roles) : roles.find_by_name(role.to_s, :include => :user_roles)
105
+ user_id = ((user.is_a?(Integer) || user.is_a?(String)) ? user.to_i : user.id)
106
+ unless role.nil?
107
+ role.user_roles.first(:conditions => {:user_id => user_id}).try(:destroy)
108
+ else
109
+ UserRole.all(:conditions => {:user_id => user_id, :role_id => role_ids}).map(&:destroy)
110
+ end
111
+ end
112
+
113
+ private
114
+ def create_roles
115
+ options = self.class.roleable_options
116
+ options[:roles].each do |role|
117
+ roles.create(:name => role.to_s,
118
+ :display_name => "#{self.send(options[:name])} #{role.to_s}",
119
+ :creation_priority => options[:creation_priority][role],
120
+ :priority => options[:priority][role])
121
+ end
122
+ end # create_user_roles
123
+ end # InstanceMethods
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,52 @@
1
+ module RoleAuthorization
2
+ module Exts
3
+ module Session
4
+ def self.included(base)
5
+ base.send :include, InstanceMethods
6
+ base.class_eval do
7
+ helper_method :current_user_is_admin?
8
+ helper_method :admin?
9
+ helper_method :access_in_role?
10
+ end
11
+ end
12
+
13
+ module InstanceMethods
14
+ protected
15
+
16
+ def add_role_authorization_session_values(user = nil)
17
+ user ||= current_user
18
+
19
+ if user
20
+ roles = user.roles.where({:roleable_id => nil}).all
21
+ session[:access_rights] = roles.collect {|role| role.name.to_sym}
22
+ end
23
+ end
24
+
25
+ def current_user_is_admin?
26
+ !session[:access_rights].nil? && session[:access_rights].include?(:all)
27
+ end
28
+
29
+ def admin?
30
+ current_user_is_admin?
31
+ end
32
+
33
+ def access_in_role?(role)
34
+ return true if current_user_is_admin?
35
+ return true if session_access_rights_include?(role)
36
+ false
37
+ end
38
+
39
+ def session_access_rights_include?(role)
40
+ return false unless session[:access_rights]
41
+ session[:access_rights].include?(role)
42
+ end
43
+
44
+ def reset_role_authorization_session
45
+ [:access_rights].each do |val|
46
+ session[val] = nil if session[val]
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,58 @@
1
+ module RoleAuthorization
2
+ module Exts
3
+ module User
4
+ def self.included(base)
5
+ base.send :extend, ClassMethods
6
+ base.send :include, InstanceMethods
7
+
8
+ base.class_eval do
9
+ has_many :user_roles, :dependent => :delete_all
10
+ has_many :roles, :through => :user_roles
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ def enroll(user_id, role_name)
16
+ user = find_by_id(user_id.to_i)
17
+ user.enroll(role_name) unless user.nil?
18
+ end # enroll
19
+
20
+ def withdraw(user_id, role_name)
21
+ user = find_by_id(user_id.to_i)
22
+ user.withdraw(role_name) unless user.nil?
23
+ end # withdraw
24
+ end # ClassMethods
25
+
26
+ module InstanceMethods
27
+ # has_object_role? simply needs to return true or false whether a user has a role or not.
28
+ # It may be a good idea to have "admin" roles return true always
29
+ # Return false always for anonymous users
30
+ def has_object_role?(role, object)
31
+ return false if self.anonymous?
32
+
33
+ @object_user_roles ||= roles.all(:conditions => ["roleable_type IS NOT NULL and roleable_id IS NOT NULL"])
34
+ result = @object_user_roles.detect do |r|
35
+ r.roleable_type == object.class.to_s && r.roleable_id == object.id && r.name == role.to_s
36
+ end
37
+ !result.nil?
38
+ end
39
+
40
+ # adds a role to the user
41
+ def enroll(role_name)
42
+ role_id = role_name.is_a?(Integer) ? role_name : Role.find_by_name(role_name.to_s).try(:id)
43
+ user_roles.create(:role_id => role_id) if !role_id.nil? && self.user_roles.find_by_role_id(role_id).nil?
44
+ end
45
+
46
+ def withdraw(role_name)
47
+ role_id = role_name.is_a?(Integer) ? role_name : Role.find_by_name(role_name.to_s).try(:id)
48
+ UserRole.delete_all(["user_id = ? AND role_id = ?", self.id, role_id]) unless role_id.nil?
49
+ end
50
+
51
+ def admin?
52
+ return true if roles.include?(Role.get(:all))
53
+ false
54
+ end
55
+ end # InstanceMethods
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,77 @@
1
+ module RoleAuthorization
2
+ module Exts
3
+ module View
4
+ def self.included(base)
5
+ base.class_eval do
6
+ alias_method :link_to_open, :link_to
7
+ alias_method :link_to, :link_to_secured
8
+
9
+ alias_method :button_to_open, :button_to
10
+ alias_method :button_to, :button_to_secured
11
+
12
+ alias_method :form_for_open, :form_for
13
+ alias_method :form_for, :form_for_secured
14
+ end
15
+ end
16
+
17
+ def form_for_secured(record_or_name_or_array, *args, &proc)
18
+ options = args.last.is_a?(Hash) ? args.last : {}
19
+
20
+ url = url_for(options[:url])
21
+
22
+ method = (options[:html] && options[:html].has_key?(:method)) ? options[:html][:method] : :post
23
+
24
+ if authorized?(url, method)
25
+ return form_for_open(record_or_name_or_array, *args, &proc)
26
+ else
27
+ return ""
28
+ end
29
+ end
30
+
31
+ def link_to_secured(name, options = {}, html_options = nil)
32
+ url = url_for(options)
33
+
34
+ method = (html_options && html_options.has_key?(:method)) ? html_options[:method] : :get
35
+
36
+ if authorized?(url, method)
37
+ return link_to_open(name, url, html_options)
38
+ else
39
+ return ""
40
+ end
41
+ end
42
+
43
+ def button_to_secured(name, options = {}, html_options = nil)
44
+ url = url_for(options)
45
+
46
+ method = (html_options && html_options.has_key?(:method)) ? html_options[:method] : :post
47
+
48
+ if authorized?(url, method)
49
+ return button_to_open(name, url, html_options)
50
+ else
51
+ return ""
52
+ end
53
+ end
54
+
55
+ def role(*user_roles, &block)
56
+ if block_given? && !session[:access_rights].blank? && !(user_roles & session[:access_rights]).empty?
57
+ capture_haml(&block)
58
+ end
59
+ end
60
+
61
+ def permitted_to?(url, method, &block)
62
+ capture_haml(&block) if block_given? && authorized?(url, method)
63
+ end
64
+
65
+ def link_to_or_show(name, options = {}, html_options = nil)
66
+ lnk = link_to(name, options, html_options)
67
+ lnk.length == 0 ? name : lnk
68
+ end
69
+
70
+ def links(*lis)
71
+ rvalue = []
72
+ lis.each{|link| rvalue << link if link.length > 0 }
73
+ rvalue.join(' | ')
74
+ end
75
+ end # View
76
+ end
77
+ end