diff options
author | Josh Kalderimis <josh.kalderimis@gmail.com> | 2010-07-07 17:05:42 +0200 |
---|---|---|
committer | José Valim <jose.valim@gmail.com> | 2010-07-08 18:28:38 +0200 |
commit | 7c86e8e21ba6a1f88226ddd0cf012a563f234d06 (patch) | |
tree | ba1ebdeaed80dc86211c1bce56919c0d39a0bea2 /activerecord/lib/active_record/mass_assignment_security.rb | |
parent | 606088df3f10dd8daec8ccc97d8279c119a503b5 (diff) | |
download | rails-7c86e8e21ba6a1f88226ddd0cf012a563f234d06.tar.gz rails-7c86e8e21ba6a1f88226ddd0cf012a563f234d06.tar.bz2 rails-7c86e8e21ba6a1f88226ddd0cf012a563f234d06.zip |
minor changes to mass assignment security patch to bring it in line with rails standards
Signed-off-by: José Valim <jose.valim@gmail.com>
Diffstat (limited to 'activerecord/lib/active_record/mass_assignment_security.rb')
-rw-r--r-- | activerecord/lib/active_record/mass_assignment_security.rb | 198 |
1 files changed, 90 insertions, 108 deletions
diff --git a/activerecord/lib/active_record/mass_assignment_security.rb b/activerecord/lib/active_record/mass_assignment_security.rb index 07beb6405e..8f4d6e1c74 100644 --- a/activerecord/lib/active_record/mass_assignment_security.rb +++ b/activerecord/lib/active_record/mass_assignment_security.rb @@ -1,7 +1,16 @@ require 'active_record/mass_assignment_security/permission_set' module ActiveRecord + # = Active Record Mass-Assignment Security module MassAssignmentSecurity + extend ActiveSupport::Concern + + included do + class_attribute :_accessible_attributes + class_attribute :_protected_attributes + class_attribute :_active_authorizer + end + # Mass assignment security provides an interface for protecting attributes # from end-user assignment. For more complex permissions, mass assignment security # may be handled outside the model by extending a non-ActiveRecord class, @@ -11,7 +20,7 @@ module ActiveRecord # on their role: # # class AccountsController < ApplicationController - # extend ActiveRecord::MassAssignmentSecurity + # include ActiveRecord::MassAssignmentSecurity # # attr_accessible :first_name, :last_name # @@ -28,7 +37,7 @@ module ActiveRecord # protected # # def account_params - # remove_attributes_protected_from_mass_assignment(params[:account]) + # sanitize_for_mass_assignment(params[:account]) # end # # def mass_assignment_authorizer @@ -37,123 +46,96 @@ module ActiveRecord # # end # - def self.extended(base) - base.send(:include, InstanceMethods) - end - - module InstanceMethods - - protected - - def remove_attributes_protected_from_mass_assignment(attributes) - mass_assignment_authorizer.sanitize(attributes) - end - - def mass_assignment_authorizer - self.class.mass_assignment_authorizer - end + module ClassMethods + # Attributes named in this macro are protected from mass-assignment, + # such as <tt>new(attributes)</tt>, + # <tt>update_attributes(attributes)</tt>, or + # <tt>attributes=(attributes)</tt>. + # + # Mass-assignment to these attributes will simply be ignored, to assign + # to them you can use direct writer methods. This is meant to protect + # sensitive attributes from being overwritten by malicious users + # tampering with URLs or forms. + # + # class Customer < ActiveRecord::Base + # attr_protected :credit_rating + # end + # + # customer = Customer.new("name" => David, "credit_rating" => "Excellent") + # customer.credit_rating # => nil + # customer.attributes = { "description" => "Jolly fellow", "credit_rating" => "Superb" } + # customer.credit_rating # => nil + # + # customer.credit_rating = "Average" + # customer.credit_rating # => "Average" + # + # To start from an all-closed default and enable attributes as needed, + # have a look at +attr_accessible+. + # + # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +attr_protected+ + # to sanitize attributes won't provide sufficient protection. + def attr_protected(*names) + self._protected_attributes = self.protected_attributes + names + self._active_authorizer = self._protected_attributes + end - end + # Specifies a white list of model attributes that can be set via + # mass-assignment, such as <tt>new(attributes)</tt>, + # <tt>update_attributes(attributes)</tt>, or + # <tt>attributes=(attributes)</tt> + # + # This is the opposite of the +attr_protected+ macro: Mass-assignment + # will only set attributes in this list, to assign to the rest of + # attributes you can use direct writer methods. This is meant to protect + # sensitive attributes from being overwritten by malicious users + # tampering with URLs or forms. If you'd rather start from an all-open + # default and restrict attributes as needed, have a look at + # +attr_protected+. + # + # class Customer < ActiveRecord::Base + # attr_accessible :name, :nickname + # end + # + # customer = Customer.new(:name => "David", :nickname => "Dave", :credit_rating => "Excellent") + # customer.credit_rating # => nil + # customer.attributes = { :name => "Jolly fellow", :credit_rating => "Superb" } + # customer.credit_rating # => nil + # + # customer.credit_rating = "Average" + # customer.credit_rating # => "Average" + # + # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +attr_accessible+ + # to sanitize attributes won't provide sufficient protection. + def attr_accessible(*names) + self._accessible_attributes = self.accessible_attributes + names + self._active_authorizer = self._accessible_attributes + end - # Attributes named in this macro are protected from mass-assignment, - # such as <tt>new(attributes)</tt>, - # <tt>update_attributes(attributes)</tt>, or - # <tt>attributes=(attributes)</tt>. - # - # Mass-assignment to these attributes will simply be ignored, to assign - # to them you can use direct writer methods. This is meant to protect - # sensitive attributes from being overwritten by malicious users - # tampering with URLs or forms. - # - # class Customer < ActiveRecord::Base - # attr_protected :credit_rating - # end - # - # customer = Customer.new("name" => David, "credit_rating" => "Excellent") - # customer.credit_rating # => nil - # customer.attributes = { "description" => "Jolly fellow", "credit_rating" => "Superb" } - # customer.credit_rating # => nil - # - # customer.credit_rating = "Average" - # customer.credit_rating # => "Average" - # - # To start from an all-closed default and enable attributes as needed, - # have a look at +attr_accessible+. - # - # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +attr_protected+ - # to sanitize attributes won't provide sufficient protection. - def attr_protected(*keys) - use_authorizer(:protected_attributes) - protected_attributes.merge(keys) - end + def protected_attributes + self._protected_attributes ||= BlackList.new(attributes_protected_by_default).tap { |w| w.logger = logger } + end - # Specifies a white list of model attributes that can be set via - # mass-assignment, such as <tt>new(attributes)</tt>, - # <tt>update_attributes(attributes)</tt>, or - # <tt>attributes=(attributes)</tt> - # - # This is the opposite of the +attr_protected+ macro: Mass-assignment - # will only set attributes in this list, to assign to the rest of - # attributes you can use direct writer methods. This is meant to protect - # sensitive attributes from being overwritten by malicious users - # tampering with URLs or forms. If you'd rather start from an all-open - # default and restrict attributes as needed, have a look at - # +attr_protected+. - # - # class Customer < ActiveRecord::Base - # attr_accessible :name, :nickname - # end - # - # customer = Customer.new(:name => "David", :nickname => "Dave", :credit_rating => "Excellent") - # customer.credit_rating # => nil - # customer.attributes = { :name => "Jolly fellow", :credit_rating => "Superb" } - # customer.credit_rating # => nil - # - # customer.credit_rating = "Average" - # customer.credit_rating # => "Average" - # - # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +attr_accessible+ - # to sanitize attributes won't provide sufficient protection. - def attr_accessible(*keys) - use_authorizer(:accessible_attributes) - accessible_attributes.merge(keys) - end + def accessible_attributes + self._accessible_attributes ||= WhiteList.new.tap { |w| w.logger = logger } + end - # Returns an array of all the attributes that have been protected from mass-assignment. - def protected_attributes - read_inheritable_attribute(:protected_attributes) || begin - authorizer = BlackList.new - authorizer += attributes_protected_by_default - authorizer.logger = logger - write_inheritable_attribute(:protected_attributes, authorizer) + def active_authorizer + self._active_authorizer ||= protected_attributes end - end - # Returns an array of all the attributes that have been made accessible to mass-assignment. - def accessible_attributes - read_inheritable_attribute(:accessible_attributes) || begin - authorizer = WhiteList.new - authorizer.logger = logger - write_inheritable_attribute(:accessible_attributes, authorizer) + def attributes_protected_by_default + [] end end - def mass_assignment_authorizer - protected_attributes - end + protected - private + def sanitize_for_mass_assignment(attributes) + mass_assignment_authorizer.sanitize(attributes) + end - # Sets the active authorizer, (attr_protected or attr_accessible). Subsequent calls - # will raise an exception when using a different authorizer_id. - def use_authorizer(authorizer_id) # :nodoc: - if active_authorizer_id = read_inheritable_attribute(:active_authorizer_id) - unless authorizer_id == active_authorizer_id - raise("Already using #{active_authorizer_id}, cannot use #{authorizer_id}") - end - else - write_inheritable_attribute(:active_authorizer_id, authorizer_id) - end + def mass_assignment_authorizer + self.class.active_authorizer end end |