0
+module AuthorizedSystem
0
+ def self.included(base)
0
+ base.send :class_inheritable_array, :auth_requirements
0
+ base.send :include, AuthorizationSecurityInstanceMethods
0
+ base.send :extend, AuthorizationSecurityClassMethods
0
+ base.send :helper_method, :url_options_authenticate?
0
+ base.send :helper_method, :next_authorized_url?
0
+ base.send :auth_requirements=, []
0
+ module AuthorizationSecurityClassMethods
0
+ # This is the core of AuthorizedSystem.
0
+ # By calling require_authorization at the top of your
0
+ # controller via dynamically create methods, you can
0
+ # test for a variety of conditions.
0
+ # require_role "contractor"
0
+ # require_role "admin", :only => :destroy # don't allow contractors to destroy
0
+ # require_state "active", :only => [:new, :create] # only allow active <%= users_name %>s to create new items
0
+ # * :only - authorization is only required for these actions
0
+ # * :except - authorization is required for all other actions
0
+ # * :if - a Proc or a string to evaluate; the authorization is required if it returns true
0
+ # * :unless - the inverse of :if
0
+ # * :redirect_url - takes a named route as a symbol (:new_example_path), string "/example/new",
0
+ # or hash { :controller => "example", :action => "new" }
0
+ # The <%= users_name %> is redirected to :redirect_url if authorization fails. If nothing is specified, it defaults
0
+ # to restful_authentication's access_denied
0
+ # * :render_url - takes a hash of parameters to pass to render such as
0
+ # { :file => "#{RAILS_ROOT}/public/404.html" }
0
+ # * :status - takes a status code ("304", "404", "500") as a string
0
+ # Rather than redirecting the <%= users_name %>, the action specified in :render_url is rendered with the
0
+ # given status. If no :render_url is specified, it renders a blank page with the status code given.
0
+ def require_authorization(type, values, options = {})
0
+ options.assert_valid_keys(:if, :unless, :only, :except, :redirect_url, :render_url, :status)
0
+ # only declare the before filter once
0
+ unless @before_filter_declared ||= false
0
+ @before_filter_declared = true
0
+ before_filter :check_authorization
0
+ # convert values to an array if it isn't already one
0
+ values = [values] unless Array === values
0
+ # convert any keys into symbols
0
+ for key in [:only, :except]
0
+ if options.has_key?(key)
0
+ options[key] = [options[key]] unless Array === options[key]
0
+ options[key] = options[key].compact.collect{|v| v.to_sym}
0
+ self.auth_requirements||=[]
0
+ self.auth_requirements << {:type => type, :values => values, :options => options }
0
+ # The method_missing helper for AuthorizedSystem catches
0
+ # all class level methods beginning with authorize_foo
0
+ # that have a matching foo_is_authorized? method.
0
+ # It then executes request_authorization and passes
0
+ # foo as the authorization type.
0
+ def method_missing(method_id, *arguments)
0
+ super unless method_id.to_s.match(/^authorize_([_a-zA-Z]\w*)$/) and respond_to?("#{method_id.to_s.gsub(/^authorize_/,'')}_is_authorized?")
0
+ require_authorization(method_id.to_s.gsub(/^authorize_/,''), *arguments )
0
+ # This method takes a <%= users_name %>, params (which includes a :controller
0
+ # and :action) and a binding. It evalutes all authorization
0
+ # requirements for this particular route and returns the
0
+ # :redirect_url and :status for the first requirement it fails
0
+ def next_authorized_url_for?(<%= users_name %>, params = {}, binding = self.binding)
0
+ return nil unless Array===self.auth_requirements
0
+ self.auth_requirements.each do |requirement|
0
+ type = requirement[:type]
0
+ values = requirement[:values]
0
+ options = requirement[:options]
0
+ # handle the restriction keys associated with this requirement
0
+ if options.has_key?(:only)
0
+ next unless options[:only].include?( (params[:action]||"index").to_sym)
0
+ if options.has_key?(:except)
0
+ next if options[:except].include?( (params[:action]||"index").to_sym)
0
+ if options.has_key?(:if)
0
+ next unless ( String===options[:if] ? eval(options[:if], binding) : options[:if].call(params) )
0
+ if options.has_key?(:unless)
0
+ next if ( String===options[:unless] ? eval(options[:unless], binding) : options[:unless].call(params) )
0
+ if options.has_key?(:render_url) && options.has_key?(:status)
0
+ options[:redirect_url] = options[:render_url]
0
+ # run the authorization test method associated with the current requirement
0
+ return { :url => options[:redirect_url], :status => options[:status] } unless send("#{type}_is_authorized?", <%= users_name %>, value)
0
+ } unless (<%= users_name %>==:false || <%= users_name %>==false)
0
+ # This is a wrapper method for next_authorized_url_for? that makes
0
+ # up the core of AuthorizedSystem. If next_authorized_url_for?
0
+ # returns nil, the <%= users_name %> is authorized to view the current page.
0
+ def <%= users_name %>_authorized_for?(<%= users_name %>, params = {}, binding = self.binding)
0
+ unless next_authorized_url_for?(<%= users_name %>, params, binding)
0
+ def reset_auth_requirements!
0
+ self.auth_requirements.clear
0
+ # == Authorization Test Methods
0
+ # These methods correspond to types stored in auth_requirement.
0
+ # For a particular form of authorization to exist, it must have
0
+ # a method here in the format #{type}_is_authorized?(<%= users_name %>, value)
0
+ # that returns a boolean value
0
+ # next_authorized_url_for? will dynamically allow for new
0
+ # authorization requirements based on these methods. In other words,
0
+ # if the following method existed:
0
+ # def foo_is_authorized?(<%= users_name %>, value)
0
+ # the dynamic method authorize_foo would be available in your
0
+ # This method invokes the generated has_role? method to
0
+ # determine if a <%= users_name %> has a given role. By default,
0
+ # has_role? downcases both the stored roles and the
0
+ # requested match, so Admin == admin == ADMIN and so on.
0
+ def role_is_authorized?(<%= users_name %>, value)
0
+ <%= users_name %>.has_role?(value)
0
+ # This method is provided as an example of authorization beyond
0
+ # the internal role system. It verifies that the <%= users_name %> has
0
+ # a field "state" that matches the required value. This works
0
+ # out of the box with Scott Barron's acts_as_state_machine.
0
+ def state_is_authorized?(<%= users_name %>, value)
0
+ <%= users_name %>.state.downcase == value.downcase
0
+ module AuthorizationSecurityInstanceMethods
0
+ # Verifies that restful_authentication is properly required before restful-authorization gets going
0
+ def self.included(base)
0
+ raise "Because restful-authorization extends restful_authentication, AuthenticatedSystem must be included before first before AuthorizedSystem!" unless base.included_modules.include?(AuthenticatedSystem)
0
+ # When <%= users_name %>_authorized_for fails, access_denied stores the current location
0
+ # in the session and then handles :redirect_to and :status as described in
0
+ # the require_authorization documentation.
0
+ # It's important to use restful_authentication's redirect_back_or_default
0
+ # instead of redirect_to to make sure that the workflow can move forward
0
+ # as well as backward.
0
+ if status = self.next_authorized_url?(params)[:status]
0
+ if self.next_authorized_url?(params)[:url]
0
+ render self.next_authorized_url?(params)[:url], :status => status
0
+ render :nothing => true, :status => status
0
+ if self.next_authorized_url?(params)[:url]
0
+ redirect_to(Symbol===self.next_authorized_url?(params)[:url] ? eval(self.next_authorized_url?(params)[:url].to_s) : self.next_authorized_url?(params)[:url])
0
+ # This is the before filter called by require_authorization
0
+ def check_authorization
0
+ return access_denied unless self.url_options_authenticate?(params)
0
+ # This calls <%= users_name %>_authorized_for? on the given parameters. If no controller
0
+ # is specified, it defaults to the current one.
0
+ def url_options_authenticate?(params = {})
0
+ params = params.symbolize_keys
0
+ if params[:controller]
0
+ base = eval("#{params[:controller]}_controller".classify)
0
+ base.<%= users_name %>_authorized_for?(current_<%= users_name %>, params, binding)
0
+ # This calls next_authorized_url_for? on the given parameters. If no controller
0
+ # is specified, it defaults to the current one.
0
+ def next_authorized_url?(params = {})
0
+ params = params.symbolize_keys
0
+ if params[:controller]
0
+ base = eval("#{params[:controller]}_controller".classify)
0
+ base.next_authorized_url_for?(current_<%= users_name %>, params, binding)
0
\ No newline at end of file
Comments
No one has commented yet.