aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller
diff options
context:
space:
mode:
authorDavid Heinemeier Hansson <david@loudthinking.com>2005-01-09 15:20:00 +0000
committerDavid Heinemeier Hansson <david@loudthinking.com>2005-01-09 15:20:00 +0000
commit75fca04590a310bedc66a455d7508168ae932ba4 (patch)
treeebb61524bb141a5b045530cc170ca7c1914ab148 /actionpack/lib/action_controller
parent298cbbd3a0a3cd678b9134ad2f998abbb25e51b6 (diff)
downloadrails-75fca04590a310bedc66a455d7508168ae932ba4.tar.gz
rails-75fca04590a310bedc66a455d7508168ae932ba4.tar.bz2
rails-75fca04590a310bedc66a455d7508168ae932ba4.zip
Added authentication framework to protect actions behind a condition and redirect on failure. See ActionController::Authentication for more.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@351 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionpack/lib/action_controller')
-rw-r--r--actionpack/lib/action_controller/authentication.rb99
-rwxr-xr-xactionpack/lib/action_controller/base.rb2
-rw-r--r--actionpack/lib/action_controller/filters.rb2
3 files changed, 101 insertions, 2 deletions
diff --git a/actionpack/lib/action_controller/authentication.rb b/actionpack/lib/action_controller/authentication.rb
new file mode 100644
index 0000000000..3ba193c1b2
--- /dev/null
+++ b/actionpack/lib/action_controller/authentication.rb
@@ -0,0 +1,99 @@
+module ActionController #:nodoc:
+ module Authentication #:nodoc:
+ def self.append_features(base)
+ super
+ base.extend(ClassMethods)
+ end
+
+ # Authentication standardizes the need to protect certain actions unless a given condition is fulfilled. It doesn't address
+ # _how_ someone becomes authorized, but only that if the condition isn't fulfilled a redirect to a given place will happen.
+ #
+ # The authentication model is setup up in two stages. One to configure the authentication, which is often done in the super-most
+ # class (such as ApplicationController in Rails), and then the protection of actions in the individual controller subclasses:
+ #
+ # class ApplicationController < ActionController::Base
+ # authentication :by => '@session[:authenticated]', :failure => { :controller => "login" }
+ # end
+ #
+ # class WeblogController < ApplicationController
+ # authenticates :edit, :update
+ #
+ # def show() render_text "I showed something" end
+ # def index() render_text "I indexed something" end
+ # def edit() render_text "I edited something" end
+ # def update() render_text "I updated something" end
+ # def login() @session[:authenticated] = true; render_nothing end
+ # end
+ #
+ # In the example above, the edit and update methods are protected by an authentication condition that requires
+ # <tt>@session[:authenticated]</tt> to be true. If that is not the case, the request is redirected to LoginController#index.
+ # Note that the :by condition is enclosed in single quotes. This is because we want to defer evaluation of the condition until
+ # we're at run time. Also note, that the :failure option uses the same format as Base#url_for and friends do to perform the redirect.
+ module ClassMethods
+ # Enables authentication for this class and all its subclasses.
+ #
+ # Options are:
+ # * <tt>:by</tt> - the code fragment that will be evaluated on each request to determine whether the request is authenticated.
+ # * <tt>:failure</tt> - redirection options following the format of Base#url_for.
+ def authentication(options)
+ options.assert_valid_keys([:by, :failure])
+ class_eval <<-EOV
+ protected
+ def actions_excepted_from_authentication
+ self.class.read_inheritable_attribute("actions_excepted_from_authentication") || []
+ end
+
+ def actions_included_in_authentication
+ actions = self.class.read_inheritable_attribute("actions_included_in_authentication")
+
+ if actions == :all
+ action_methods.collect { |action| action.intern }
+ elsif actions.is_a?(Array)
+ actions
+ else
+ []
+ end
+ end
+
+ def action_needs_authentication?
+ if actions_excepted_from_authentication.include?(action_name.intern)
+ false
+ elsif actions_included_in_authentication.include?(action_name.intern)
+ true
+ elsif actions_excepted_from_authentication.length > 0
+ true
+ else
+ false
+ end
+ end
+
+ def authenticate
+ if !action_needs_authentication? || #{options[:by]}
+ return true
+ else
+ redirect_to(#{options[:failure].inspect})
+ return false
+ end
+ end
+ EOV
+
+ before_filter :authenticate
+ end
+
+ # Protects the actions specified behind the authentication condition.
+ def authenticates(*actions)
+ write_inheritable_array("actions_included_in_authentication", actions)
+ end
+
+ # Protects all the actions of this controller behind the authentication condition.
+ def authenticates_all
+ write_inheritable_attribute("actions_included_in_authentication", :all)
+ end
+
+ # Protects all the actions of this controller _except_ the listed behind the authentication condition.
+ def authenticates_all_except(*actions)
+ write_inheritable_array("actions_excepted_from_authentication", actions)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 851a382682..dbdce1bbfd 100755
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -602,7 +602,7 @@ module ActionController #:nodoc:
def action_methods
action_controller_classes = self.class.ancestors.reject{ |a| [Object, Kernel].include?(a) }
- action_controller_classes.inject([]) { |action_methods, klass| action_methods + klass.instance_methods(false) }
+ action_controller_classes.inject([]) { |action_methods, klass| action_methods + klass.public_instance_methods(false) }
end
def add_variables_to_assigns
diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/filters.rb
index 1691f031f8..1ae2ea2251 100644
--- a/actionpack/lib/action_controller/filters.rb
+++ b/actionpack/lib/action_controller/filters.rb
@@ -3,7 +3,7 @@ module ActionController #:nodoc:
def self.append_features(base)
super
base.extend(ClassMethods)
- base.class_eval { include ActionController::Filters::InstanceMethods }
+ base.send(:include, ActionController::Filters::InstanceMethods)
end
# Filters enable controllers to run shared pre and post processing code for its actions. These filters can be used to do