forked from MattHall/bort
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added role requirement. Also created a default admin user and admin role
- Loading branch information
Jim Neath
committed
Sep 12, 2008
1 parent
0f692d1
commit bf86685
Showing
34 changed files
with
1,542 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
class Role < ActiveRecord::Base | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
development: &non_production_settings | ||
site_url: http://localhost:3000 | ||
site_name: Bort | ||
admin_email: bort@bort.com | ||
|
||
test: | ||
<<: *non_production_settings | ||
|
||
production: | ||
site_url: http://www.example.com | ||
site_name: Bort | ||
admin_email: bort@bort.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
class CreateRoles < ActiveRecord::Migration | ||
def self.up | ||
create_table :roles do |t| | ||
t.string :name | ||
end | ||
|
||
create_table :roles_users, :id => false do |t| | ||
t.belongs_to :role | ||
t.belongs_to :user | ||
end | ||
end | ||
|
||
def self.down | ||
drop_table :roles | ||
drop_table :roles_users | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
class AddDefaultAdminUser < ActiveRecord::Migration | ||
def self.up | ||
# Create admin role | ||
admin_role = Role.create(:name => 'admin') | ||
|
||
# Create default admin user | ||
user = User.create do |u| | ||
u.login = 'admin' | ||
u.password = u.password_confirmation = 'chester' | ||
u.email = APP_CONFIG[:admin_email] | ||
end | ||
|
||
# Activate user | ||
user.register! | ||
user.activate! | ||
|
||
# Add admin role to admin user | ||
user.roles << admin_role | ||
end | ||
|
||
def self.down | ||
Role.delete_all | ||
User.delete_all | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Hijacker class | ||
# | ||
# This class is used by RoleRequirementTestHelper to temporarily hijack a controller action for testing | ||
# | ||
# Example usage: | ||
# hijacker = Hijacker.new(ListingsController) | ||
# hijacker.hijack_instance_method("index", "render :text => 'hello world!'" ) | ||
# get :index # will return "hello world" | ||
# hijacker.restore # put things back the way you found it | ||
|
||
class Hijacker | ||
def initialize(klass) | ||
@target_klass = klass | ||
@method_stores = {} | ||
end | ||
|
||
def hijack_class_method(method_name, eval_string = nil, arg_names = [], &block) | ||
hijack_method(class_self_instance, method_name, eval_string, arg_names, &block ) | ||
end | ||
|
||
def hijack_instance_method(method_name, eval_string = nil, arg_names = [], &block) | ||
hijack_method(@target_klass, method_name, eval_string, arg_names, &block ) | ||
end | ||
|
||
# restore all | ||
def restore | ||
@method_stores.each_pair{|klass, method_stores| | ||
method_stores.reverse_each{ |method_name, method| | ||
klass.send :undef_method, method_name | ||
klass.send :define_method, method_name, method if method | ||
} | ||
} | ||
@method_stores.clear | ||
true | ||
rescue | ||
false | ||
end | ||
|
||
protected | ||
|
||
def class_self_instance | ||
@target_klass.send :eval, "class << self; self; end;" | ||
end | ||
|
||
def hijack_method(klass, method_name, eval_string = nil, arg_names = [], &block) | ||
method_name = method_name.to_s | ||
# You have got love ruby! What other language allows you to pillage and plunder a class like this? | ||
|
||
(@method_stores[klass]||=[]) << [ | ||
method_name, | ||
klass.instance_methods.include?(method_name) && klass.instance_method(method_name) | ||
] | ||
|
||
klass.send :undef_method, method_name | ||
if Symbol === eval_string | ||
klass.send :define_method, method_name, klass.instance_methods(eval_string) | ||
elsif String === eval_string | ||
klass.class_eval <<-EOF | ||
def #{method_name}(#{arg_names * ','}) | ||
#{eval_string} | ||
end | ||
EOF | ||
elsif block_given? | ||
klass.send :define_method, method_name, block | ||
end | ||
|
||
true | ||
rescue | ||
false | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
# Main module for authentication. | ||
# Include this in ApplicationController to activate RoleRequirement | ||
# | ||
# See RoleSecurityClassMethods for some methods it provides. | ||
module RoleRequirementSystem | ||
def self.included(klass) | ||
klass.send :class_inheritable_array, :role_requirements | ||
klass.send :include, RoleSecurityInstanceMethods | ||
klass.send :extend, RoleSecurityClassMethods | ||
klass.send :helper_method, :url_options_authenticate? | ||
|
||
klass.send :role_requirements=, [] | ||
|
||
end | ||
|
||
module RoleSecurityClassMethods | ||
|
||
def reset_role_requirements! | ||
self.role_requirements.clear | ||
end | ||
|
||
# Add this to the top of your controller to require a role in order to access it. | ||
# Example Usage: | ||
# | ||
# require_role "contractor" | ||
# require_role "admin", :only => :destroy # don't allow contractors to destroy | ||
# require_role "admin", :only => :update, :unless => "current_user.authorized_for_listing?(params[:id]) " | ||
# | ||
# Valid options | ||
# | ||
# * :only - Only require the role for the given actions | ||
# * :except - Require the role for everything but | ||
# * :if - a Proc or a string to evaluate. If it evaluates to true, the role is required. | ||
# * :unless - The inverse of :if | ||
# | ||
def require_role(roles, options = {}) | ||
options.assert_valid_keys(:if, :unless, | ||
:for, :only, | ||
:for_all_except, :except | ||
) | ||
|
||
# only declare that before filter once | ||
unless (@before_filter_declared||=false) | ||
@before_filter_declared=true | ||
before_filter :check_roles | ||
end | ||
|
||
# convert to an array if it isn't already | ||
roles = [roles] unless Array===roles | ||
|
||
options[:only] ||= options[:for] if options[:for] | ||
options[:except] ||= options[:for_all_except] if options[:for_all_except] | ||
|
||
# convert any actions into symbols | ||
for key in [:only, :except] | ||
if options.has_key?(key) | ||
options[key] = [options[key]] unless Array === options[key] | ||
options[key] = options[key].compact.collect{|v| v.to_sym} | ||
end | ||
end | ||
|
||
self.role_requirements||=[] | ||
self.role_requirements << {:roles => roles, :options => options } | ||
end | ||
|
||
# This is the core of RoleRequirement. Here is where it discerns if a user can access a controller or not./ | ||
def user_authorized_for?(user, params = {}, binding = self.binding) | ||
return true unless Array===self.role_requirements | ||
self.role_requirements.each{| role_requirement| | ||
roles = role_requirement[:roles] | ||
options = role_requirement[:options] | ||
# do the options match the params? | ||
|
||
# check the action | ||
if options.has_key?(:only) | ||
next unless options[:only].include?( (params[:action]||"index").to_sym ) | ||
end | ||
|
||
if options.has_key?(:except) | ||
next if options[:except].include?( (params[:action]||"index").to_sym) | ||
end | ||
|
||
if options.has_key?(:if) | ||
# execute the proc. if the procedure returns false, we don't need to authenticate these roles | ||
next unless ( String===options[:if] ? eval(options[:if], binding) : options[:if].call(params) ) | ||
end | ||
|
||
if options.has_key?(:unless) | ||
# execute the proc. if the procedure returns true, we don't need to authenticate these roles | ||
next if ( String===options[:unless] ? eval(options[:unless], binding) : options[:unless].call(params) ) | ||
end | ||
|
||
# check to see if they have one of the required roles | ||
passed = false | ||
roles.each { |role| | ||
passed = true if user.has_role?(role) | ||
} unless (! user || user==:false) | ||
|
||
return false unless passed | ||
} | ||
|
||
return true | ||
end | ||
end | ||
|
||
module RoleSecurityInstanceMethods | ||
def self.included(klass) | ||
raise "Because role_requirement extends acts_as_authenticated, You must include AuthenticatedSystem first before including RoleRequirementSystem!" unless klass.included_modules.include?(AuthenticatedSystem) | ||
end | ||
|
||
def access_denied | ||
if logged_in? | ||
render :nothing => true, :status => 401 | ||
return false | ||
else | ||
super | ||
end | ||
end | ||
|
||
def check_roles | ||
return access_denied unless self.class.user_authorized_for?(current_user, params, binding) | ||
|
||
true | ||
end | ||
|
||
protected | ||
# receives a :controller, :action, and :params. Finds the given controller and runs user_authorized_for? on it. | ||
# This can be called in your views, and is for advanced users only. If you are using :if / :unless eval expressions, | ||
# then this may or may not work (eval strings use the current binding to execute, not the binding of the target | ||
# controller) | ||
def url_options_authenticate?(params = {}) | ||
params = params.symbolize_keys | ||
if params[:controller] | ||
# find the controller class | ||
klass = eval("#{params[:controller]}_controller".classify) | ||
else | ||
klass = self.class | ||
end | ||
klass.user_authorized_for?(current_user, params, binding) | ||
end | ||
end | ||
end |
Oops, something went wrong.