1
0
Fork 0
mirror of https://github.com/heartcombo/devise.git synced 2022-11-09 12:18:31 -05:00

Add support for Rails 4 strong_parameters

This brings support for Rails 4 StrongParameters changes.

- Parameter sanitizing is setup for Devise controllers via
  resource_params except Omniauth Callbacks which doesn't use
  resource_params.

- Change #build_resource to not call resource_params for get requests.
  Parameter sanitizing is only needed when params are posted to the
  server so there's no need to try to construct resource params on get
  requests (new, edit).
This commit is contained in:
Drew Ulmer 2013-03-13 11:37:54 -05:00
parent af4a582300
commit 78f137368c
7 changed files with 153 additions and 14 deletions

View file

@ -39,5 +39,4 @@ class Devise::ConfirmationsController < DeviseController
def after_confirmation_path_for(resource_name, resource)
after_sign_in_path_for(resource)
end
end

View file

@ -83,7 +83,11 @@ class Devise::RegistrationsController < DeviseController
# Build a devise resource passing in the session. Useful to move
# temporary session data to the newly created user.
def build_resource(hash=nil)
hash ||= resource_params || {}
if request.get?
hash ||= {}
else
hash ||= resource_params || {}
end
self.resource = resource_class.new_with_session(hash, session)
end

View file

@ -40,5 +40,4 @@ class Devise::UnlocksController < DeviseController
def after_unlock_path_for(resource)
new_session_path(resource)
end
end

View file

@ -28,10 +28,6 @@ class DeviseController < Devise.parent_controller.constantize
devise_mapping.to
end
def resource_params
params[resource_name]
end
# Returns a signed in resource from session (if one exists)
def signed_in_resource
warden.authenticate(:scope => resource_name)
@ -96,7 +92,13 @@ MESSAGE
# Build a devise resource.
# Assignment bypasses attribute protection when :unsafe option is passed
def build_resource(hash = nil, options = {})
hash ||= resource_params || {}
# When building a resource, invoke strong_parameters require/permit
# steps if the params hash includes the resource name.
if params[resource_name]
hash ||= resource_params || {}
else
hash ||= {}
end
if options[:unsafe]
self.resource = resource_class.new.tap do |resource|
@ -181,4 +183,21 @@ MESSAGE
format.any(*navigational_formats, &block)
end
end
# Setup a param sanitizer to filter parameters using strong_parameters. See
# lib/devise/controllers/parameter_sanitizer.rb for more info. Override this
# method in your application controller to use your own parameter sanitizer.
def parameters_sanitizer
@parameters_sanitizer ||= Devise::ParameterSanitizer.new
end
# Return the params to be used for mass assignment passed through the
# strong_parameters require/permit step. To customize the parameters
# permitted for a specific controller, simply prepend a before_filter and
# call #permit_devise_param or #remove_permitted_devise_param on
# parameters_sanitizer to update the default allowed lists of permitted
# parameters.
def resource_params
params.require(resource_name).permit(parameters_sanitizer.permitted_params_for(controller_name))
end
end

View file

@ -6,12 +6,13 @@ require 'set'
require 'securerandom'
module Devise
autoload :Delegator, 'devise/delegator'
autoload :FailureApp, 'devise/failure_app'
autoload :OmniAuth, 'devise/omniauth'
autoload :ParamFilter, 'devise/param_filter'
autoload :TestHelpers, 'devise/test_helpers'
autoload :TimeInflector, 'devise/time_inflector'
autoload :Delegator, 'devise/delegator'
autoload :FailureApp, 'devise/failure_app'
autoload :OmniAuth, 'devise/omniauth'
autoload :ParamFilter, 'devise/param_filter'
autoload :ParameterSanitizer, 'devise/parameter_sanitizer'
autoload :TestHelpers, 'devise/test_helpers'
autoload :TimeInflector, 'devise/time_inflector'
module Controllers
autoload :Helpers, 'devise/controllers/helpers'

View file

@ -0,0 +1,65 @@
module Devise
class ParameterSanitizer
attr_reader :allowed_params
# Return a list of parameter names permitted to be mass-assigned for the
# passed controller.
def permitted_params_for(controller_name)
allowed_params.fetch(key_for_controller_name(controller_name), [])
end
# Set up a new parameter sanitizer with a set of allowed parameters. This
# gets initialized on each request so that parameters may be augmented or
# changed as needed via before_filter.
def initialize
@allowed_params = {
:confirmations_controller => [:email],
:passwords_controller => authentication_keys + [:password, :password_confirmation, :reset_password_token],
:registrations_controller => authentication_keys + [:password, :password_confirmation, :current_password],
:sessions_controller => authentication_keys + [:password],
:unlocks_controller => [:email]
}
end
# Allow additional parameters for a Devise controller. If the
# controller_name doesn't exist in allowed_params, it will be added to it
# as an empty array and param_name will be appended to that array. Note
# that when adding a new controller, use the full controller name
# (:confirmations_controller) and not the short names
# (:confirmation/:confirmations).
def permit_devise_param(controller_name, param_name)
@allowed_params[key_for_controller_name(controller_name)] << param_name
true
end
# Remove specific allowed parameter for a Devise controller. If the
# controller_name doesn't exist in allowed_params, it will be added to it
# as an empty array.
def remove_permitted_devise_param(controller_name, param_name)
@allowed_params[key_for_controller_name(controller_name)].delete(param_name)
true
end
protected
def authentication_keys
Array(::Devise.authentication_keys)
end
# Flexibly allow access to permitting/denying/checking parameters by
# controller name in the following key formats: :confirmations_controller,
# :confirmations, :confirmation
def key_for_controller_name(name)
if allowed_params.has_key?(name.to_sym)
name.to_sym
elsif allowed_params.has_key?(:"#{name}s_controller")
:"#{name}s_controller"
elsif allowed_params.has_key?(:"#{name}_controller")
:"#{name}_controller"
else
@allowed_params[name.to_sym] = []
name.to_sym
end
end
end
end

View file

@ -0,0 +1,52 @@
require 'test_helper'
class ParameterSanitizerTest < ActiveSupport::TestCase
def sanitizer
Devise::ParameterSanitizer.new
end
test '#permitted_params_for allows querying of allowed parameters by controller' do
assert_equal [:email], sanitizer.permitted_params_for(:confirmations_controller)
assert_equal [:email, :password, :password_confirmation, :reset_password_token], sanitizer.permitted_params_for(:password)
assert_equal [:email], sanitizer.permitted_params_for(:unlocks)
end
test '#permitted_params_for returns an empty array for a bad key' do
assert_equal [], sanitizer.permitted_params_for(:bad_key)
end
test '#permit_devise_param allows adding an allowed param for a specific controller' do
subject = sanitizer
subject.permit_devise_param(:confirmations_controller, :other)
assert_equal [:email, :other], subject.permitted_params_for(:confirmations_controller)
end
test '#remove_permitted_devise_param allows disallowing a param for a specific controller' do
subject = sanitizer
subject.remove_permitted_devise_param(:confirmations_controller, :email)
assert_equal [], subject.permitted_params_for(:confirmations_controller)
end
test '#permit_devise_param allows adding additional devise controllers' do
subject = sanitizer
subject.permit_devise_param(:invitations_controller, :email)
assert_equal [:email], subject.permitted_params_for(:invitations)
end
test '#remove_permitted_devise_param fails gracefully when removing a missing param' do
subject = sanitizer
# perform twice, just to be sure it handles it gracefully
subject.remove_permitted_devise_param(:invitations_controller, :email)
subject.remove_permitted_devise_param(:invitations_controller, :email)
assert_equal [], subject.permitted_params_for(:invitations)
end
end