diff --git a/app/controllers/devise/sessions_controller.rb b/app/controllers/devise/sessions_controller.rb index 933de540..f19b65d6 100644 --- a/app/controllers/devise/sessions_controller.rb +++ b/app/controllers/devise/sessions_controller.rb @@ -4,7 +4,7 @@ class Devise::SessionsController < DeviseController # GET /resource/sign_in def new - resource = build_resource + resource = build_resource(nil, :unsafe => true) clean_up_passwords(resource) respond_with(resource, serialize_options(resource)) end diff --git a/app/controllers/devise_controller.rb b/app/controllers/devise_controller.rb index 0f37d046..d92295df 100644 --- a/app/controllers/devise_controller.rb +++ b/app/controllers/devise_controller.rb @@ -67,10 +67,21 @@ MESSAGE instance_variable_set(:"@#{resource_name}", new_resource) end - # Build a devise resource. - def build_resource(hash=nil) + # Build a devise resource. + # Assignment bypasses attribute protection when :unsafe option is passed + def build_resource(hash = nil, options = {}) hash ||= params[resource_name] || {} - self.resource = resource_class.new(hash) + + if options[:unsafe] + self.resource = resource_class.new.tap do |resource| + hash.each do |key, value| + setter = :"#{key}=" + resource.send(setter, value) if resource.respond_to?(setter) + end + end + else + self.resource = resource_class.new(hash) + end end # Helper for use in before_filters where no authentication is required. diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb index 912cf5e3..7451a203 100644 --- a/test/controllers/sessions_controller_test.rb +++ b/test/controllers/sessions_controller_test.rb @@ -13,4 +13,20 @@ class SessionsControllerTest < ActionController::TestCase assert_equal 200, @response.status assert_template "devise/sessions/new" end + + test "#new doesn't raise mass-assignment exception even if sign-in key is attr_protected" do + request.env["devise.mapping"] = Devise.mappings[:user] + + ActiveRecord::Base.mass_assignment_sanitizer = :strict + User.class_eval { attr_protected :email } + + begin + assert_nothing_raised ActiveModel::MassAssignmentSecurity::Error do + get :new, :user => { :email => "allez viens!" } + end + ensure + ActiveRecord::Base.mass_assignment_sanitizer = :logger + User.class_eval { attr_accessible :email } + end + end end