From e3a00b27d19ba995891d7dd92394fe2900a789c2 Mon Sep 17 00:00:00 2001 From: kenji kobayashi Date: Fri, 28 Dec 2018 22:29:58 +0900 Subject: [PATCH] Add an option to not automatically sign in a user after changing a password (#4569) --- .../devise/registrations_controller.rb | 32 ++++++++++++++---- config/locales/en.yml | 1 + lib/devise.rb | 4 +++ lib/devise/models/registerable.rb | 2 ++ lib/generators/templates/devise.rb | 8 ++++- test/integration/registerable_test.rb | 33 +++++++++++++++++++ test/rails_app/config/initializers/devise.rb | 6 ++++ 7 files changed, 78 insertions(+), 8 deletions(-) diff --git a/app/controllers/devise/registrations_controller.rb b/app/controllers/devise/registrations_controller.rb index c79ce56e..1b8a969f 100644 --- a/app/controllers/devise/registrations_controller.rb +++ b/app/controllers/devise/registrations_controller.rb @@ -50,12 +50,9 @@ class Devise::RegistrationsController < DeviseController resource_updated = update_resource(resource, account_update_params) yield resource if block_given? if resource_updated - if is_flashing_format? - flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ? - :update_needs_confirmation : :updated - set_flash_message :notice, flash_key - end - bypass_sign_in resource, scope: resource_name + set_flash_message_for_update(resource, prev_unconfirmed_email) + bypass_sign_in resource, scope: resource_name if sign_in_after_change_password? + respond_with resource, location: after_update_path_for(resource) else clean_up_passwords resource @@ -127,7 +124,7 @@ class Devise::RegistrationsController < DeviseController # The default url to be used after updating a resource. You need to overwrite # this method in your own RegistrationsController. def after_update_path_for(resource) - signed_in_root_path(resource) + sign_in_after_change_password? ? signed_in_root_path(resource) : new_session_path(resource_name) end # Authenticates the current scope and gets the current resource from the session. @@ -147,4 +144,25 @@ class Devise::RegistrationsController < DeviseController def translation_scope 'devise.registrations' end + + private + + def set_flash_message_for_update(resource, prev_unconfirmed_email) + return unless is_flashing_format? + + flash_key = if update_needs_confirmation?(resource, prev_unconfirmed_email) + :update_needs_confirmation + elsif sign_in_after_change_password? + :updated + else + :updated_but_not_signed_in + end + set_flash_message :notice, flash_key + end + + def sign_in_after_change_password? + return true if account_update_params[:password].blank? + + Devise.sign_in_after_change_password + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 0b8f1302..55617bdf 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -44,6 +44,7 @@ en: signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address." updated: "Your account has been updated successfully." + updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again" sessions: signed_in: "Signed in successfully." signed_out: "Signed out successfully." diff --git a/lib/devise.rb b/lib/devise.rb index 360d5e13..dceee089 100755 --- a/lib/devise.rb +++ b/lib/devise.rb @@ -293,6 +293,10 @@ module Devise mattr_accessor :token_generator @@token_generator = nil + # When set to false, changing a password does not automatically sign in a user + mattr_accessor :sign_in_after_change_password + @@sign_in_after_change_password = true + def self.rails51? # :nodoc: Rails.gem_version >= Gem::Version.new("5.1.x") end diff --git a/lib/devise/models/registerable.rb b/lib/devise/models/registerable.rb index 3965ee5c..e55dac27 100644 --- a/lib/devise/models/registerable.rb +++ b/lib/devise/models/registerable.rb @@ -21,6 +21,8 @@ module Devise def new_with_session(params, session) new(params) end + + Devise::Models.config(self, :sign_in_after_change_password) end end end diff --git a/lib/generators/templates/devise.rb b/lib/generators/templates/devise.rb index 09616950..5bad7f9a 100755 --- a/lib/generators/templates/devise.rb +++ b/lib/generators/templates/devise.rb @@ -9,7 +9,7 @@ Devise.setup do |config| # Devise will use the `secret_key_base` as its `secret_key` # by default. You can change it below and use your own secret key. # config.secret_key = '<%= SecureRandom.hex(64) %>' - + # ==> Controller configuration # Configure the parent class to the devise controllers. # config.parent_controller = 'DeviseController' @@ -290,4 +290,10 @@ Devise.setup do |config| # ActiveSupport.on_load(:devise_failure_app) do # include Turbolinks::Controller # end + + # ==> Configuration for :registerable + + # When set to false, does not sign a user in automatically after their password is + # changed. Defaults to true, so a user is signed in automatically after changing a password. + # config.sign_in_after_change_password = true end diff --git a/test/integration/registerable_test.rb b/test/integration/registerable_test.rb index 2387cd29..46f09f37 100644 --- a/test/integration/registerable_test.rb +++ b/test/integration/registerable_test.rb @@ -179,6 +179,39 @@ class RegistrationTest < Devise::IntegrationTest assert warden.authenticated?(:user) end + test 'a signed in user should not be able to use the website after changing their password if config.sign_in_after_change_password is false' do + swap Devise, sign_in_after_change_password: false do + sign_in_as_user + get edit_user_registration_path + + fill_in 'password', with: '1234567890' + fill_in 'password confirmation', with: '1234567890' + fill_in 'current password', with: '12345678' + click_button 'Update' + + assert_contain 'Your account has been updated successfully, but since your password was changed, you need to sign in again' + assert_equal new_user_session_path, @request.path + refute warden.authenticated?(:user) + end + end + + test 'a signed in user should be able to use the website after changing its email with config.sign_in_after_change_password is false' do + swap Devise, sign_in_after_change_password: false do + sign_in_as_user + get edit_user_registration_path + + fill_in 'email', with: 'user.new@example.com' + fill_in 'current password', with: '12345678' + click_button 'Update' + + assert_current_url '/' + assert_contain 'Your account has been updated successfully.' + + assert warden.authenticated?(:user) + assert_equal "user.new@example.com", User.to_adapter.find_first.email + end + end + test 'a signed in user should not change their current user with invalid password' do sign_in_as_user get edit_user_registration_path diff --git a/test/rails_app/config/initializers/devise.rb b/test/rails_app/config/initializers/devise.rb index bf4f7212..0ce41964 100644 --- a/test/rails_app/config/initializers/devise.rb +++ b/test/rails_app/config/initializers/devise.rb @@ -180,6 +180,12 @@ Devise.setup do |config| # manager.default_strategies(scope: :user).unshift :some_external_strategy # end + # ==> Configuration for :registerable + + # When set to false, does not sign a user in automatically after their password is + # changed. Defaults to true, so a user is signed in automatically after changing a password. + # config.sign_in_after_change_password = true + ActiveSupport.on_load(:devise_failure_app) do require "lazy_load_test_module" include LazyLoadTestModule