diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index 555627febb3..69cd4c6d80e 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -103,7 +103,12 @@ def redirect_to_signin analytics.invalid_authenticity_token(controller: controller_info) sign_out flash[:error] = t('errors.general') - redirect_back fallback_location: new_user_session_url, allow_other_host: false + begin + redirect_back fallback_location: new_user_session_url, allow_other_host: false + rescue ActionController::Redirecting::UnsafeRedirectError => err + # Exceptions raised inside exception handlers are not propagated up, so we manually rescue + unsafe_redirect_error(err) + end end def check_user_needs_redirect @@ -228,4 +233,16 @@ def override_csp_for_google_analytics request.content_security_policy = policy end end + + def unsafe_redirect_error(_exception) + controller_info = "#{controller_path}##{action_name}" + analytics.unsafe_redirect_error( + controller: controller_info, + user_signed_in: user_signed_in?, + referer: request.referer, + ) + + flash[:error] = t('errors.general') + redirect_to new_user_session_url + end end diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index bb8ed35918a..06a70371091 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -393,6 +393,26 @@ expect(flash[:error]).to eq t('errors.general') end + it 'redirects back to home page if CSRF error and referer is invalid' do + user = create(:user, :signed_up) + stub_analytics + analytics_hash = { controller: 'users/sessions#create', user_signed_in: nil } + allow(controller).to receive(:create).and_raise(ActionController::InvalidAuthenticityToken) + + expect(@analytics).to receive(:track_event). + with('Invalid Authenticity Token', analytics_hash) + + expect(@analytics).to receive(:track_event). + with('Unsafe Redirect', { controller: 'users/sessions#create', referer: '@@@', + user_signed_in: false }) + + request.env['HTTP_REFERER'] = '@@@' + post :create, params: { user: { email: user.email, password: user.password } } + + expect(response).to redirect_to new_user_session_url + expect(flash[:error]).to eq t('errors.general') + end + it 'returns to sign in page if email is a Hash' do post :create, params: { user: { email: { foo: 'bar' }, password: 'password' } }