diff --git a/CHANGELOG.md b/CHANGELOG.md index 995f9f088c..910db470b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ### unreleased * enhancements + * Devise `FailureApp` now returns a `422` status when running the `recall` flow. This, combined with https://github.com/heartcombo/responders/pull/223, enables Devise to work correctly with the [new Rails defaults](https://github.com/rails/rails/pull/41026) for form errors, as well as with new libraries like Turbo. By default, the `recall` flow only runs on the [`SessionsController`](https://github.com/heartcombo/devise/blob/v4.7.3/app/controllers/devise/sessions_controller.rb#L48). But you should check if it is required in other flows too - this may be a **breaking change**. * Devise now enables the upgrade of OmniAuth 2+. Previously Devise would raise an error if you'd try to upgrade. Please note that OmniAuth 2 is considered a security upgrade and recommended to everyone. You can read more about the details (and possible necessary changes to your app as part of the upgrade) in [their release notes](https://github.com/omniauth/omniauth/releases/tag/v2.0.0). [Devise's OmniAuth Overview wiki](https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview) was also updated to cover OmniAuth 2.0 requirements. - Note that the upgrade required Devise shared links that initiate the OmniAuth flow to be changed to `method: :post`, which is now a requirement for OmniAuth, part of the security improvement. If you have copied and customized the Devise shared links partial to your app, or if you have other links in your app that initiate the OmniAuth flow, they will have to be updated to use `method: :post`, or changed to use buttons (e.g. `button_to`) to work with OmniAuth 2. (if you're using links with `method: :post`, make sure your app has `rails-ujs` or `jquery-ujs` included in order for these links to work properly.) - As part of the OmniAuth 2.0 upgrade you might also need to add the [`omniauth-rails_csrf_protection`](https://github.com/cookpad/omniauth-rails_csrf_protection) gem to your app if you don't have it already. (and you don't want to roll your own code to verify requests.) Check the OmniAuth v2 release notes for more info. diff --git a/lib/devise/failure_app.rb b/lib/devise/failure_app.rb index ee8219fff1..f05c2a6c21 100644 --- a/lib/devise/failure_app.rb +++ b/lib/devise/failure_app.rb @@ -71,7 +71,9 @@ def recall end flash.now[:alert] = i18n_message(:invalid) if is_flashing_format? - self.response = recall_app(warden_options[:recall]).call(request.env) + response_from_app = recall_app(warden_options[:recall]).call(request.env) + response_from_app[0] = 422 + self.response = response_from_app end def redirect diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb index e88cf7e908..a3e3a3f219 100644 --- a/test/controllers/sessions_controller_test.rb +++ b/test/controllers/sessions_controller_test.rb @@ -19,7 +19,7 @@ class SessionsControllerTest < Devise::ControllerTestCase password: "wrongpassword" } } - assert_equal 200, @response.status + assert_equal 422, @response.status ensure ActiveSupport::Notifications.unsubscribe(subscriber) end @@ -29,7 +29,7 @@ class SessionsControllerTest < Devise::ControllerTestCase swap Devise, scoped_views: true do request.env["devise.mapping"] = Devise.mappings[:user] post :create - assert_equal 200, @response.status + assert_equal 422, @response.status assert_template "users/sessions/new" end end @@ -70,7 +70,7 @@ class SessionsControllerTest < Devise::ControllerTestCase password: "wevdude" } } - assert_equal 200, @response.status + assert_equal 422, @response.status assert_template "devise/sessions/new" end diff --git a/test/failure_app_test.rb b/test/failure_app_test.rb index 1b0aeb04aa..0fa12ed93c 100644 --- a/test/failure_app_test.rb +++ b/test/failure_app_test.rb @@ -326,6 +326,7 @@ def call_failure(env_params = {}) "warden" => stub_everything } call_failure(env) + assert_equal 422, @response.first assert_includes @response.third.body, '

Log in

' assert_includes @response.third.body, 'Invalid Email or password.' end @@ -337,6 +338,7 @@ def call_failure(env_params = {}) "warden" => stub_everything } call_failure(env) + assert_equal 422, @response.first assert_includes @response.third.body, '

Log in

' assert_includes @response.third.body, 'You have to confirm your email address before continuing.' end @@ -348,6 +350,7 @@ def call_failure(env_params = {}) "warden" => stub_everything } call_failure(env) + assert_equal 422, @response.first assert_includes @response.third.body, '

Log in

' assert_includes @response.third.body, 'Your account is not activated yet.' end @@ -361,6 +364,7 @@ def call_failure(env_params = {}) "warden" => stub_everything } call_failure(env) + assert_equal 422, @response.first assert_includes @response.third.body, '

Log in

' assert_includes @response.third.body, 'Invalid Email or password.' assert_equal '/sample', @request.env["SCRIPT_NAME"] @@ -375,6 +379,7 @@ def call_failure(env_params = {}) assert_equal "yes it does", Devise::FailureApp.new.lazy_loading_works? end end + context "Without Flash Support" do test "returns to the default redirect location without a flash message" do call_failure request_klass: RequestWithoutFlashSupport