aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/mass_assignment_security.rb
diff options
context:
space:
mode:
authorJosh Kalderimis <josh.kalderimis@gmail.com>2010-07-07 17:05:42 +0200
committerJosé Valim <jose.valim@gmail.com>2010-07-08 18:28:38 +0200
commit7c86e8e21ba6a1f88226ddd0cf012a563f234d06 (patch)
treeba1ebdeaed80dc86211c1bce56919c0d39a0bea2 /activerecord/lib/active_record/mass_assignment_security.rb
parent606088df3f10dd8daec8ccc97d8279c119a503b5 (diff)
downloadrails-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.rb198
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